Part3. Writing your first test case.

Introduction:

In this tutorial, we are going to explore public website: https://practicesoftwaretesting.com

More examples of automation testing friendly websites you can find in the repo throughly curated by Butch Mayhew.

In Playwright, structuring a test suite involves organizing your test cases within descriptive blocks (test.describe) and utilizing setup and teardown functions (test.beforeEach and test.afterEach) to ensure consistent test environments. Here’s a brief description of each component and an example:

  1. test.describe block provides a high-level description of the test suite, allowing you to group related test cases together. It helps in organizing tests based on functionality or feature sets.
  2. Inside test.describe, individual test cases are defined using the test block. Each test block represents a specific scenario or behavior that you want to verify.
  3. test.beforeEach block is used to define setup actions that need to be executed before each test case within the test.describe block. It ensures that the test environment is in a consistent state before each test runs.
  4. test.afterEach block is utilized for defining teardown actions that need to be executed after each test case within the test.describe block. It helps in cleaning up the test environment and ensuring that resources are properly released.

Here’s an example demonstrating the structure of a test suite in Playwright:

import { chromium, Browser, Page } from 'playwright';

// Define the test suite
test.describe('Login functionality', () => {
  let browser: Browser;
  let page: Page;

  // Setup before each test case
  test.beforeEach(async () => {
    browser = await chromium.launch();
    page = await browser.newPage();
    await page.goto('https://example.com/login');
  });

  // Teardown after each test case
  test.afterEach(async () => {
    await browser.close();
  });

  // Test case 1: Verify successful login
  test('Successful login', async () => {
    // Test logic for successful login
  });

  // Test case 2: Verify error message on invalid credentials
  test('Error message on invalid credentials', async () => {
    // Test logic for error message on invalid credentials
  });
});

DOM Terminology

Before we start writing test cases, it will be useful to brush up our memory on DOM Terminology

  1. HTML tags are simple instructions that tell a web browser how to format text. You can use tags to format italics, line breaks, objects, bullet points, and more. Examples: <input>, <div>, <p>
  2. Elements in HTML have attributes; these are additional values that configure the elements or adjust their behavior in various ways to meet the criteria the users want. Sometimes these attributes can have a value and sometimes doesn’t. Refer to Developer Mozilla Website for more information.”Class” and “id” are the most used attributes in HTML. (image: show class attribute, class value)
  3. Value in between angle braces is a plain text
  4. HTML tags usually come in pairs of Opening and Closing Tags.

Locator Syntax Rules

Locate Element by tag name:

page.locator('img');

Locate by id:

page.locator('.img-fluid');

Locate by class value:

page.locator('.img-fluid');

Locate by attribute:

page.locator('[data-test="nav-home"]');

Combine several selectors:

page.locator('img.img-fluid');

Locate by full class value:

page.locator('[class=collapse d-md-block col-md-3 mb-3]');

Locate by partial text match:

page.locator(':text("Combination")');

Locate by exact text match:

page.locator(':text-is("Combination Pliers")');

XPATH:

As for XPath: it is not recommended approach to locate elements according to Playwright Best Practices:

Source: https://playwright.dev/docs/other-locators#xpath-locator

User-facing Locators.

There are other ways to locate elements by using built-in APIs Playwright provides.

There is one best practice we have to keep in mind: automated tests must focus on verifying that the application code functions as intended for end users, while avoiding reliance on implementation specifics that are not typically visible, accessible, or known to users. Users will only see or interact with the rendered output on the page; therefore, tests should primarily interact with this same rendered output. Playwright documentation: https://playwright.dev/docs/best-practices#test-user-visible-behavior.

There are recommended built-in locators:

  1. page.getByRole() to locate by explicit and implicit accessibility attributes.
  2. page.getByText() to locate by text content.
  3. page.getByLabel() to locate a form control by associated label’s text.
  4. page.getByPlaceholder() to locate an input by placeholder.
  5. page.getByAltText() to locate an element, usually image, by its text alternative.
  6. page.getByTitle() to locate an element by its title attribute.
  7. page.getByTestId() to locate an element based on its data-testid attribute (other attributes can be configured).

Let’s check out the example:

test('User facing locators', async({page}) => {
await page.getByPlaceholder('Search').click();
await page.getByPlaceholder('Search').fill("Hand Tools");
await page.getByRole('button', {name: "Search"}).click();
await expect (page.getByRole('heading', {name: "Searched for: Hand Tools"})).toBeVisible();
})

where we would like to explore search functional test:

Part of the page to be tested
  1. click on the Search Placeholder
Search placeholder HTML

await page.getByPlaceholder('Search').click();

2. enter “Hand Tools” text to search for available items.

await page.getByPlaceholder('Search').fill("Hand Tools");

3. locate Search button and click it to confirm.

Search button HTML

4. Then we have to verify if no items have been found by asserting text on this page:

Result after clicking on Search button
No Result Found HTML

await expect (page.getByRole('heading', {name: "Searched for: Hand Tools"})).toBeVisible();

5. Run this test case and make sure test is passing.

Assertions

Playwright incorporates test assertions utilizing the expect function. To perform an assertion, utilize expect(value) and select a matcher that best represents the expectation. Various generic matchers such as toEqual, toContain, and toBeTruthy are available to assert various conditions.

General Assertions

// Using toEqual matcher
test('Adding numbers', async () => {
const result = 10 + 5;
expect(result).toEqual(15);
});

Assert that the title of the product is “Combination Pliers”.

Element on the page
Element HTML
const element = page.locator('.col-md-9 .container').first().locator('.card-title');
const text = element.textContent();
expect(text).toEqual('Combination Pliers');

Locator Assertions

Playwright provides asynchronous matchers, ensuring they wait until the expected condition is fulfilled. For instance, in the following scenario:

const element = page.locator('.col-md-9 .container').first().locator('.card-title');
await expect(element).toHaveText('Combination Pliers');

!Note: do not forget to use await when asserting locators

Playwright continuously checks the element with the test id of “status” until it contains the text “Combination Pliers”. This process involves repeated fetching and verification of the element until either the condition is satisfied or the timeout limit is reached. You have the option to either specify a custom timeout or configure it globally using the testConfig.expect value in the test configuration.

By default, the timeout duration for assertions is set to 5 seconds.

There are two types assertion though: Auto-Retrying Assertions and Non-Retrying Assertions.

Auto-Retrying assertions provided below will automatically retry until they pass successfully or until the assertion timeout is exceeded. It’s important to note that these retrying assertions operate asynchronously, necessitating the use of the await keyword before them.

Non-Retrying assertions enable testing various conditions but do not automatically retry.

It’s advisable to prioritize auto-retrying assertions whenever feasible.

Soft Assertions

As a default behavior, when an assertion fails, it terminates the test execution. However, Playwright offers support for soft assertions. In soft assertions, failure doesn’t immediately stop the test execution; instead, it marks the test as failed while allowing further execution.

For example, if we take the previous example and put .soft it assertion, in case assertion fails, it will not lead to termination of test execution.

const element = page.locator('.col-md-9 .container').first().locator('.card-title');
await expect.soft(element).toHaveText('Combination Pliers');

Conclusion.

In conclusion, we’ve explored the aspects of writing test cases using Playwright. We delved into the standard structure of a test case, incorporating essential elements such as hooks and grouping for efficient test management. Additionally, we examined various strategies for locating elements within web pages. Lastly, we discussed the importance of assertions in verifying expected behaviors, covering different assertion techniques to ensure robust and reliable testing. Examples of code, you can see in repository.

Comments

Leave a comment