Powrót do: Playwright Elements – Kluczowe koncepcje automatyzacji testów
Rozwiązanie – operacje na listach lokatorów
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
Przykładowe rozwiązanie
Rozwiązanie podstawowe
import { test, expect } from "@playwright/test";
test.describe("Multiple checkboxes", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/practice/simple-multiple-elements-no-ids.html");
});
test("action on multiple checkboxes", async ({ page }) => {
// Arrange:
const elementRole = "checkbox";
const resultsTestId = "dti-results";
const expectedNumberOfElements = 5;
const checkboxLocator = page.getByRole(elementRole);
const resultsLocator = page.getByTestId(resultsTestId);
// Assert:
await expect(checkboxLocator).toHaveCount(expectedNumberOfElements);
const numberOfFoundCheckboxes = await checkboxLocator.count();
for (let i = 0; i < numberOfFoundCheckboxes; i++) {
// Act:
await checkboxLocator.nth(i).check();
// display the text content of the results element
console.log("results text content:", await resultsLocator.textContent());
}
});
});
import { test, expect } from "@playwright/test";
test.describe("Multiple checkboxes", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/practice/simple-multiple-elements-no-ids.html");
});
test("action on multiple checkboxes", async ({ page }) => {
// Arrange:
const elementRole = "checkbox";
const resultsTestId = "dti-results";
const expectedNumberOfElements = 5;
const checkboxLocator = page.getByRole(elementRole);
const resultsLocator = page.getByTestId(resultsTestId);
// Assert:
await expect(checkboxLocator).toHaveCount(expectedNumberOfElements);
const numberOfFoundCheckboxes = await checkboxLocator.count();
for (let i = 0; i < numberOfFoundCheckboxes; i++) {
// Act:
await checkboxLocator.nth(i).check();
// display the text content of the results element
console.log("results text content:", await resultsLocator.textContent());
}
});
});
import { test, expect } from "@playwright/test"; test.describe("Multiple checkboxes", () => { test.beforeEach(async ({ page }) => { await page.goto("/practice/simple-multiple-elements-no-ids.html"); }); test("action on multiple checkboxes", async ({ page }) => { // Arrange: const elementRole = "checkbox"; const resultsTestId = "dti-results"; const expectedNumberOfElements = 5; const checkboxLocator = page.getByRole(elementRole); const resultsLocator = page.getByTestId(resultsTestId); // Assert: await expect(checkboxLocator).toHaveCount(expectedNumberOfElements); const numberOfFoundCheckboxes = await checkboxLocator.count(); for (let i = 0; i < numberOfFoundCheckboxes; i++) { // Act: await checkboxLocator.nth(i).check(); // display the text content of the results element console.log("results text content:", await resultsLocator.textContent()); } }); });
Rozwiązanie trudniejsze, z asercją
import { test, expect } from "@playwright/test";
test.describe("Multiple locators", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/practice/simple-multiple-elements-no-ids.html");
});
test("action on multiple checkboxes (advanced, with assertion)", async ({
page,
}) => {
// Arrange:
const elementRole = "checkbox";
const resultsTestId = "dti-results";
const expectedMessages = {
0: "Checkbox is checked! (Opt 1!)",
1: "Checkbox is checked! (Opt 2!)",
2: "Checkbox is checked! (Opt 3!)",
3: "Checkbox is checked! (Opt 4!)",
4: "Checkbox is checked! (Opt 5!)",
};
const expectedNumberOfElements = 5;
const checkboxLocator = page.getByRole(elementRole);
const resultsLocator = page.getByTestId(resultsTestId);
// Assert:
await expect(checkboxLocator).toHaveCount(expectedNumberOfElements);
// Act & Assert:
const numberOfFoundCheckboxes = await checkboxLocator.count();
for (let i = 0; i < numberOfFoundCheckboxes; i++) {
// Act:
await checkboxLocator.nth(i).check();
console.log(await resultsLocator.innerText());
// Assert:
await expect.soft(resultsLocator).toHaveText(expectedMessages[i]);
}
});
});
import { test, expect } from "@playwright/test";
test.describe("Multiple locators", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/practice/simple-multiple-elements-no-ids.html");
});
test("action on multiple checkboxes (advanced, with assertion)", async ({
page,
}) => {
// Arrange:
const elementRole = "checkbox";
const resultsTestId = "dti-results";
const expectedMessages = {
0: "Checkbox is checked! (Opt 1!)",
1: "Checkbox is checked! (Opt 2!)",
2: "Checkbox is checked! (Opt 3!)",
3: "Checkbox is checked! (Opt 4!)",
4: "Checkbox is checked! (Opt 5!)",
};
const expectedNumberOfElements = 5;
const checkboxLocator = page.getByRole(elementRole);
const resultsLocator = page.getByTestId(resultsTestId);
// Assert:
await expect(checkboxLocator).toHaveCount(expectedNumberOfElements);
// Act & Assert:
const numberOfFoundCheckboxes = await checkboxLocator.count();
for (let i = 0; i < numberOfFoundCheckboxes; i++) {
// Act:
await checkboxLocator.nth(i).check();
console.log(await resultsLocator.innerText());
// Assert:
await expect.soft(resultsLocator).toHaveText(expectedMessages[i]);
}
});
});
import { test, expect } from "@playwright/test"; test.describe("Multiple locators", () => { test.beforeEach(async ({ page }) => { await page.goto("/practice/simple-multiple-elements-no-ids.html"); }); test("action on multiple checkboxes (advanced, with assertion)", async ({ page, }) => { // Arrange: const elementRole = "checkbox"; const resultsTestId = "dti-results"; const expectedMessages = { 0: "Checkbox is checked! (Opt 1!)", 1: "Checkbox is checked! (Opt 2!)", 2: "Checkbox is checked! (Opt 3!)", 3: "Checkbox is checked! (Opt 4!)", 4: "Checkbox is checked! (Opt 5!)", }; const expectedNumberOfElements = 5; const checkboxLocator = page.getByRole(elementRole); const resultsLocator = page.getByTestId(resultsTestId); // Assert: await expect(checkboxLocator).toHaveCount(expectedNumberOfElements); // Act & Assert: const numberOfFoundCheckboxes = await checkboxLocator.count(); for (let i = 0; i < numberOfFoundCheckboxes; i++) { // Act: await checkboxLocator.nth(i).check(); console.log(await resultsLocator.innerText()); // Assert: await expect.soft(resultsLocator).toHaveText(expectedMessages[i]); } }); });
Zasoby i dokumentacja
- Oficjalna dokumentacja - locators
Cześć
Miałam problem z użyciem obiektu expectedMessages:
Element implicitly has an ‘any’ type because expression of type ‘number’ can’t be used to index type ‘{ 0: string; 1: string; 2: string; 3: string; 4: string; }’.
No index signature with a parameter of type ‘number’ was found on type ‘{ 0: string; 1: string; 2: string; 3: string; 4: string; }’.
Musiałam z tego obiektu robić array.
Hej,
Jak wyglądał Twój kod dla którego pojawił się ten błąd?
Tak samo jak i u was w tej sekcji (Rozwiązanie trudniejsze, z asercją). Próbowałam nawet robić kopię waszego kodu żeby. I miałam ten problem z powrotem.
Hmm błąd o którym wspominasz prawdopodobnie wynikał z konfiguracji projektu i ze TypeScript traktował klucze w obiekcie jako “0”, “1” itd.
Gdy próbujesz użyć liczby do indeksowania (np. expectedMessages[2]), TypeScript nie znajduje dopasowania do indeksu typu number – oczekuje, że obiekt będzie miał sygnaturę indeksu zdefiniowaną np. jako
[key: number]: string
.Rozwiązania są 2 – jedno to zamiana na listę (czyli Twoje rozwiązanie).
Drugie to dodanie sygnatury indeksu do obiektu, czyli jawne określienie, że obiekt ten ma sygnaturę indeksu dla number np:
A dla mnie nie przemawia ani tablica ani lista
wystarczy spojrzeć, że ten wpis się powtarza "Checkbox is checked! (Opt)"
Gdyby to pojawiło się dwa razy to jeszcze ok, ale w przypadku 5 razy to już jest DRY
Można prościej
Zgadzam się, ze, ze to może być kolejny krok
W tym przypadku rozwiązanie z listą pokazuje nam duplikacje, a tym samym możemy zrefaktoryzować rozwiązanie i wydzielić część wspólną.
Rozwiązanie z listą ma na celu pokazanie jak można projektować struktury danych się przydać, gdy będziemy potrzebować odnosić się do oczekiwanych danych za pomocą klucza
To ja bym tutaj wgl poszedł inaczej, nie robił żadnej struktury w kodzie testowym tylko plik enums i tam wrzucił enuma z tym
W sumie ciekawy pomysł

Możesz podrzucić taki typ rozwiązania tutaj – może być inspirujący dla osób, które będą przechodziły przez tą lekcję
Dzięki!
hej ja w dodatkowym zadaniu użyłem takiego zapisu
choć pokazany zapis obiektu bardziej do mnie przemawia
świetna lekcja i zadania które faktycznie wnoszą praktyczne umiejętności 
Dzięki wielkie!
W tym przypadku tka lista też się sprawdzi, a lista obiektów daje więcej możliwości.
A to moze się przydać w bardziej skomplikowanych przypadkach lub gdy potrzebujemy bardziej skomplikowanych danych testowych