Exploring Frontend Element Locators with TypeScript and Playwright: Best Practices for Effective Test Automation

Frontend UI Testing

In the realm of test automation, one of the critical components is the ability to locate and interact with elements on a web page. The choice of locators plays a pivotal role in the success and reliability of your test automation framework. In this guide, we'll explore the importance of using meaningful locators and discuss the steps to enhance your test automation using TypeScript and Playwright. We'll also touch upon the concept of custom attributes and their significance in ensuring robust test automation.

Table of Contents

  1. Introduction
  2. Meaningful Locators
  3. Custom Attributes for Test Automation
  4. Best Practices for Locators
  5. Example with TypeScript and Playwright
  6. Conclusion

1. Introduction

The locators used to identify elements on a web page are like the foundation of a building. If your foundation is strong and well-thought-out, your structure (in this case, your test automation) is more likely to stand the test of time. Let's delve into the core concepts of frontend element locators for test automation.

2. Meaningful Locators

When you're dealing with locators, one of the cardinal rules is to use meaningful and semantic locators. This means that the locators you choose should be intuitive and convey the purpose of the element they are associated with. For example, consider the following button element:

<button data-test-id="directions">Itinéraire</button>
<button data-test-id="directions">Itinéraire</button>

In this case, the data-test-id attribute is used to provide a clear and meaningful identifier for the button. The name "directions" tells us exactly what this button is for. This approach makes your code more maintainable and helps other team members understand the purpose of the element.

3. Custom Attributes for Test Automation

In situations where user-facing attributes are subject to frequent changes, it's advisable to add custom attributes specifically for test automation. The data-* attributes are a common choice for this purpose and are well-supported by CSS and ID selectors.

Custom attributes can be added to your HTML elements like this:

<button data-test-id="directions">Itinéraire</button>
<button data-test-id="directions">Itinéraire</button>

You can then use these custom attributes to locate elements in your tests.

  • Using CSS selector:
await page.locator('css=[data-test-id=directions]').click();
await page.locator('[data-test-id=directions]').click(); // short-form
await page.locator('css=[data-test-id=directions]').click();
await page.locator('[data-test-id=directions]').click(); // short-form
  • Using ID selector:
await page.locator('data-test-id=directions').click();
await page.locator('data-test-id=directions').click();

The benefit of using custom attributes is that they significantly reduce test brittleness. When the UI changes, you only need to update the locators associated with these attributes, rather than making changes throughout your test suite.

4. Best Practices for Locators

Choosing the right locator is crucial for test automation success. The following order of preference is recommended:

  1. Id/data-test-id:

    If an element has a unique identifier, it is usually the best choice. Many modern web applications include data-test-ids for this purpose. Here's an example using Playwright and TypeScript:

    const uniqueElement = await page.locator('[data-test-id="unique-id"]');
    const uniqueElement = await page.locator('[data-test-id="unique-id"]');
  2. Name:

    The name attribute can be used if it uniquely identifies an element. Here's an example:

    const elementWithName = await page.locator('input[name="username"]');
    const elementWithName = await page.locator('input[name="username"]');
  3. Class Name:

    If no better option is available, you can use the class attribute. Be cautious as classes can be non-unique, and using them as locators may lead to flaky tests:

    const elementWithClass = await page.locator('.my-class');
    const elementWithClass = await page.locator('.my-class');
  4. CSS Selector:

    CSS selectors are powerful and versatile for locating elements. You should use them when they can uniquely identify an element. For example:

    const elementWithCSS = await page.locator('#uniqueId .nestedClass > div');
    const elementWithCSS = await page.locator('#uniqueId .nestedClass > div');
  5. XPath without text or indexing:

    While XPath can be powerful, it should be used sparingly and only when necessary. Avoid using text-based or indexed XPath expressions. Here's an example:

    const elementWithXPath = await page.locator('//input[@id="uniqueId"]');
    const elementWithXPath = await page.locator('//input[@id="uniqueId"]');
  6. Link Text / Partial Link Text:

    These locators are useful for finding anchor elements, particularly in navigation scenarios. Example:

    const linkByText = await page.locator('a=Click Me');
    const partialLinkText = await page.locator('a=Partial Link Text');
    const linkByText = await page.locator('a=Click Me');
    const partialLinkText = await page.locator('a=Partial Link Text');
  7. XPath with text and/or indexing:

    XPath with text or indexing should be your last resort as it can make your tests brittle and complex. Here's an example:

    const elementWithTextXPath = await page.locator('//div[contains(text(), "Some Text")]');
    const elementWithIndexedXPath = await page.locator('(//input)[2]');
    const elementWithTextXPath = await page.locator('//div[contains(text(), "Some Text")]');
    const elementWithIndexedXPath = await page.locator('(//input)[2]');

Remember that the choice of locator should be based on the specific context of your application and the element you want to interact with. Always prioritize unique and stable locators to create reliable and maintainable automation scripts. Playwright offers a wide range of locator strategies, and understanding when to use each one will lead to more robust test automation.

5. Example with TypeScript and Playwright

Let's put these concepts into action by providing an example using TypeScript and Playwright. We'll use the Playwright library to interact with a web page and demonstrate the use of meaningful locators.

import { chromium } from 'playwright';
 
(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
 
  await page.goto('https://example.com');
  
  // Click the "Directions" button using the data-test-id locator
  await page.locator('[data-test-id=directions]').click();
 
  await browser.close();
})();
import { chromium } from 'playwright';
 
(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
 
  await page.goto('https://example.com');
  
  // Click the "Directions" button using the data-test-id locator
  await page.locator('[data-test-id=directions]').click();
 
  await browser.close();
})();

In this example, we're opening a web page, locating the "Directions" button using the data-test-id attribute, and clicking it. This showcases the practical application of the concepts discussed.

6. Conclusion

Frontend element locators are a fundamental aspect of test automation. Using meaningful locators, custom attributes, and following best practices when choosing locators can greatly enhance the reliability and maintainability of your test automation framework. By adhering to these principles and utilizing the power of tools like TypeScript and Playwright, you can build robust and effective automated tests for your web applications.



Testingfly

Testingfly is my spot for sharing insights and experiences, with a primary focus on tools and technologies related to test automation and governance.

Comments

Want to give your thoughts or chat about more ideas? Feel free to leave a comment here.

Instead of authenticating the giscus application, you can also comment directly on GitHub.

Related Articles

Testing iFrames using Playwright

Automated testing has become an integral part of web application development. However, testing in Safari, Apple's web browser, presents unique challenges due to the browser's strict Same-Origin Policy (SOP), especially when dealing with iframes. In this article, we'll explore known issues related to Safari's SOP, discuss workarounds, and demonstrate how Playwright, a popular automation testing framework, supports automated testing in this context.

Overview of SiteCore for Beginners

Sitecore is a digital experience platform that combines content management, marketing automation, and eCommerce. It's an enterprise-level content management system (CMS) built on ASP.NET. Sitecore allows businesses to create, manage, and publish content across all channels using simple tools.