None of the current answers mentions test.step; if you've got a reusable piece of test code which can be organised into a function it should probably also be wrapped in test.step
. For example recently I extracted a function for entering credentials and logging in:
import test, { Page } from '@playwright/test';
export async function enterCredentialsAndLogIn(page: Page) {
await test.step('Enter credentials and log in', async () => {
await page.getByRole('textbox', { name: 'Identyfikator klienta' }).click();
await page.getByRole('textbox', { name: 'Identyfikator klienta' }).fill('1');
await page.getByRole('textbox', { name: 'Identyfikator klienta' }).press('Tab');
await page.getByRole('textbox', { name: 'Numer PESEL' }).click();
await page.getByRole('textbox', { name: 'Numer PESEL' }).fill('99123100000');
await page.getByRole('button', { name: 'Weryfikuj' }).click();
});
}
Thanks to this simple maneuver it looks very nice in the report:
You can of course click that step and view all sub-step it consists of. Naturally, you can also compose steps of other sub-steps, for example:
async enterCredentialsAndLogIn() {
await test.step('Enter credentials and log in', async () => {
await fillTextbox('Identyfikator klienta', '1');
await fillTextbox('Numer PESEL', '99123100000');
await pressButton('Weryfikuj');
});
}
async pressButton(name: string) {
await test.step('Click button: ' + name, async () => {
await page.getByRole('button', { name: name }).click();
});
}
async fillTextbox(name: string, value: string) {
await test.step(`Fill textbox ${name} with ${value}`, async () => {
await page.getByRole('textbox', { name: name }).click();
await page.getByRole('textbox', { name: name }).fill(value);
});
}
And the produces effect looks as follows: