Powrót do: Playwright Elements – Kluczowe koncepcje automatyzacji testów
Czym jest test id i data-testid? Jak szukać elementów po tych atrybutach?
Prezentacja
👉jaktestowac/playwright-elements-locators
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
Atrybutydata-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 zdata-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ówdata-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ówdata-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"] }, }, ], });
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.
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
- Aplikacja do testów: lekcja o pobraniu, instalacji i uruchomieniu
- Strona do testów: [aplikacja GAD musi być uruchomiona lokalnie!] simple-elements-custom-attribute.html
- Oficjalna dokumentacja: Locate by test id
- Why Should You Use data-testid Attributes?
- Why Your Development Team Should Use data-testid Attributes