Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

Prezentacja

Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?

TIP: Cały kod testów z poszczególnych lekcji znajdziesz w specjalnie przygotowanym repozytorium:
👉jaktestowac/playwright-elements-locators

TIP: Ta lekcja jest częścią rozwijanego Programu Testy Automatyczne z Playwright 🎭

Czym jest data-testid?

Atrybuty data-testid są niestandardowymi atrybutami, które można dodać do elementów HTML. Dzięki temu łatwiej jest identyfikować i wyszukiwać te elementy podczas pisania testów automatycznych.

Choć data-testid nie są częścią specyfikacji HTML, są powszechnie używane w ramach testowych i narzędziach do lokalizowania i interakcji z elementami.

Jakie są zalety stosowania atrybutów data-testid?

  • Zwiększona niezawodność testów
    Atrybuty data-testid poprawiają niezawodność testów automatycznych. W testach korzystających z selektorów CSS lub wyrażeniach XPath łatwiej wyszukiwać i identyfikować elementy.
  • Łatwiejsza lokalizacja elementów

    Atrybuty data-testid oferują jasny i spójny sposób identyfikacji elementów na stronie. Ułatwia to deweloperom i testerom odnajdywanie elementów i interakcję z nimi.

  • Oddzielenie logiki od testów
    Korzystanie z data-testid do identyfikacji elementów dla celów testowych pozwala na oddzielenie logiki strony od testów. Dzięki temu zmiany w HTML mają mniejszy wpływ na testy, co ułatwia utrzymanie i aktualizację kodu.

Jakie są wady stosowania atrybutów data-testid?

  • Nadmiar atrybutów w kodzie HTML
    Dodanie dużej liczby atrybutów data-testid do kodu HTML może sprawić, że stanie się on mniej przejrzysty. Może to utrudniać czytanie i zrozumienie struktury dokumentu.
  • Ryzyko zduplikowanych wartości

    Nieumiejętne zarządzanie atrybutami data-testid może prowadzić do duplikacji wartości, co może spowodować problemy z identyfikacją elementów w testach. Konieczne jest wprowadzenie i utrzymanie spójnych konwencji nazewniczych, aby uniknąć takich konfliktów. Ważne: ten problem nie dotyczy tylko atrybutów data-testid, ale może dotyczyć każdego sposobu identyfikacji elementów na stronie.

Stosowanie atrybutów data-testid w procesie rozwoju może przynieść wiele korzyści, takich jak poprawa niezawodności testów, łatwiejsza lokalizacja elementów, oddzielenie logiki od testów oraz czytelniejsza dokumentacja. Dzięki spójnym i znaczącym konwencjom nazewniczym, deweloperzy mogą tworzyć bardziej niezawodny i łatwiejszy do utrzymania kod.

Można też wprowadzać inne własne atrybuty niestandardowe, takie jak dataid, aby identyfikować elementy HTML w testach. Wprowadzanie własnych atrybutów niestandardowych, zazwyczaj jest możliwe i może być korzystne w określonych przypadkach.

Kluczowe jest jednak, aby zachować spójność i przejrzystość kodu oraz być świadomym potencjalnych wad i ograniczeń. Własne atrybuty mogą być świetnym narzędziem do lepszego identyfikowania elementów w testach. Jednak powinny być używane z rozwagą i w zgodzie z dobrymi praktykami 😉

Kod i polecenia

Konfiguracja

Minimalna konfiguracja w pliku playwright.config.ts:

import { defineConfig, devices } from "@playwright/test";


export default defineConfig({
  testDir: "./tests",
  fullyParallel: true,
  workers: undefined,
  reporter: "html",
  use: {
    baseURL: "http://localhost:3000",
    trace: "on",
    testIdAttribute: 'pw-test' // define the testIdAttribute used in page.getByTestId()
  },


  projects: [
    {
      name: "chromium",
      use: { ...devices["Desktop Chrome"] },
    },
  ],
});


UWAGA: Jeśli w konfiguracji nie zdefiniujemy pola testIdAttribute to domyślna nazwa atrybutu, którego będzie szukał Playwright, to data-testid. W takim przypadku element powinien zawierać atrybut data-testid:

<button data-testid="simple-button" onclick="buttonOnClick()">Click me!</button>

Kod HTML szukanego elementu

Szukany element ma następujący kod HTML (możesz go podejrzeć w przeglądarce po wejściu na testowaną stronę za pomocą opcji inspect):

<button pw-test="simple-button" onclick="buttonOnClick()">Click me!</button>

Zauważ atrybut pw-test o wartości simple-button.

UWAGA: Playwright w metodzie getByTestId() będzie szukał atrybutu pw-test, bo w pliku playwright.config.ts zdefiniowaliśmy:

testIdAttribute: 'pw-test'

Jeśli w konfiguracji nie zdefiniujemy pola testIdAttribute to Playwright w metodzie getByTestId() będzie szukał atrybutu data-testid. W takim przypadku przycisk powinien mieć następujący kod HTML:

<button data-testid="simple-button" onclick="buttonOnClick()">Click me!</button>

Kod

Początkowa zawartość pliku custom-testid-attributes.spec.ts:

import { test, expect } from "@playwright/test";


test.describe("Finding elements using getByTestId and locators", () => {
  test.beforeEach(async ({ page }) => {
    await page.goto("/practice/simple-elements-custom-attribute.html");
  });


  test("click the button (using getByTestId)", async ({ page }) => {
    // TODO:
  });


  test("click the button (using locator)", async ({ page }) => {
    // TODO:
  });
});


Finalna zawartość pliku custom-testid-attributes.spec.ts:

import { test, expect } from "@playwright/test";


test.describe("Finding elements using getByTestId and locators", () => {
  test.beforeEach(async ({ page }) => {
    await page.goto("/practice/simple-elements-custom-attribute.html");
  });


  test("click the button (using getByTestId)", async ({ page }) => {
    // Arrange:
    const buttonTestId = "simple-button";
    const resultsTestId = "results";
    const expectedMessage = "You clicked the button!";


    const buttonLocator = page.getByTestId(buttonTestId);
    const resultsLocator = page.getByTestId(resultsTestId);


    // Act:
    await buttonLocator.click();


    // Assert:
    await expect(resultsLocator).toHaveText(expectedMessage);
  });


  test("click the button (using locator)", async ({ page }) => {
    // Arrange:
    const buttonSelector = "[pw-test='simple-button']";
    const resultsSelector = "[pw-test='results']";
    const expectedMessage = "You clicked the button!";


    const buttonLocator = page.locator(buttonSelector);
    const resultsLocator = page.locator(resultsSelector);


    // Act:
    await buttonLocator.click();


    // Assert:
    await expect(resultsLocator).toHaveText(expectedMessage);
  });
});




Wiele atrybutów data-testid w jednym projekcie

Możemy lokalnie nadpisać wartość ustawienia testIdAttribute:

  test.use({ testIdAttribute : "pw-test"});

Czyli taki zapis w custom-testid-attributes.spec.ts:

import { test, expect } from "@playwright/test";


test.describe("Finding elements using getByTestId and locators", () => {
  test.use({ testIdAttribute : "pw-test"});


  test.beforeEach(async ({ page }) => {
    await page.goto("/practice/simple-elements-custom-attribute.html");
  });


  test("click the button (using getByTestId)", async ({ page }) => {
    // Arrange:
    const buttonTestId = "simple-button";
    const resultsTestId = "results";
    const expectedMessage = "You clicked the button!";


    const buttonLocator = page.getByTestId(buttonTestId);
    const resultsLocator = page.getByTestId(resultsTestId);


    // Act:
    await buttonLocator.click();


    // Assert:
    await expect(resultsLocator).toHaveText(expectedMessage);
  });


  test("click the button (using locator)", async ({ page }) => {
    // Arrange:
    const buttonSelector = "[pw-test='simple-button']";
    const resultsSelector = "[pw-test='results']";
    const expectedMessage = "You clicked the button!";


    const buttonLocator = page.locator(buttonSelector);
    const resultsLocator = page.locator(resultsSelector);


    // Act:
    await buttonLocator.click();


    // Assert:
    await expect(resultsLocator).toHaveText(expectedMessage);
  });
});




spowoduje, że w obrębie tego test.describe testy będą miały zmienioną konfigurację. Czyli metody page.getByTestId będą szukały atrybutów pw-test.

Dzięki temu możemy mieć w projekcie testy, które bazują na wielu niestandardowych atrybutach.

Jednak korzystanie z

  test.use({ testIdAttribute : "pw-test"});

może być niezalecane z kilku powodów:

  • Złożoność utrzymania

    Jeśli w projekcie jest wiele miejsc, gdzie nadpisujemy wartość testIdAttribute, może to prowadzić do trudności w śledzeniu, które testy korzystają z jakich atrybutów. W dłuższej perspektywie może to skomplikować utrzymanie testów, zwłaszcza gdy liczba testów rośnie lub gdy do projektu dołączają nowe osoby.

  • Spójność

    Nadpisywanie testIdAttribute lokalnie może prowadzić do niespójności w kodzie testów. Gdy różne testy używają różnych atrybutów, może to wprowadzać zamieszanie. Stosowanie jednego standardowego atrybutu testowego jest bardziej przejrzyste i zrozumiałe dla całego zespołu.

  • Trudności w debugowaniu

    W przypadku problemów z testami, konieczność uwzględniania różnych atrybutów podczas debugowania może być czasochłonna. Debugowanie staje się bardziej skomplikowane, gdy testy w różnych miejscach projektu używają różnych ustawień, co może prowadzić do nieoczekiwanych zachowań, trudnych do zdiagnozowania.

  • Problemy z reużywalnością kodu

    Jeżeli w projekcie używamy różnych testIdAttribute, reużywalność kodu testowego może być ograniczona. Testy, które są specyficzne dla danego atrybutu, mogą nie działać poprawnie, jeśli próbujemy je użyć w innym kontekście, gdzie używany jest inny atrybut testowy.

Z tych powodów, zaleca się unikanie nadmiernego używania lokalnych nadpisań testIdAttribute, a zamiast tego stosowanie jednolitego standardu w całym projekcie. Jeśli jednak konieczne jest użycie niestandardowego atrybutu w specyficznych przypadkach, warto to robić świadomie i z pełnym zrozumieniem potencjalnych konsekwencji.

Zewnętrzne linki i zasoby

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *