SlideShare a Scribd company logo
Jonathan Frere
jonathan.frere@esveo.com
@johz@hachyderm.io
Das Beste aus dem
Dramatiker herausholen
1
2
https://playwright.dev/docs/writing-tests
import { test, expect } from "@playwright/test";
test("has title", async ({ page }) => {
await page.goto("https://playwright.dev/");
await expect(page).toHaveTitle(/Playwright/);
});
test("get started link", async ({ page }) => {
await page.goto("https://playwright.dev/");
await page.getByRole("link", { name: "Get started" }).click();
await expect(
page.getByRole("heading", { name: "Installation" }),
).toBeVisible();
});
3
Testing Goals
Accuracy
Speed
“How often will this test fail
without me changing anything? “If I change my code and the test fails,
is it likely that there’s a bug in my code?”
“How quickly can I run this test?”
“How quickly can I write this test?”
“If this code doesn’t work, will
the test still succeed?”
4
https://playwright.dev/docs/locators
Use Locators
page.getByLabel("Folder Name");
page.getByRole("button", { name: "New Folder" });
page.getByRole("listitem").filter({ hasText: "T-Shirt" });
page
.getByRole("listitem")
.filter({ hasText: "Trousers" })
.getByRole("button", { name: "Delete" });
5
https://testing-library.com/docs/queries/about
https://playwright.dev/docs/actionability
Use Locators
// define some locators
const newFolderButtonLocator = page.getByRole("button", { name: "New Folder" });
const folderNameInputLocator = page.getByLabel("Folder Name");
// load the page
await page.goto("/page");
// find the button and click it
await newFolderButtonLocator.click();
// check that the focus has been set correctly
await expect(folderNameInputLocator).toBeFocused();
// define some locators
const newFolderButtonLocator = page.getByRole("button", { name: "New Folder" });
const folderNameInputLocator = page.getByLabel("Folder Name");
// load the page
await page.goto("/page");
// find the button and click it
await newFolderButtonLocator.click();
// check that the focus has been set correctly
await expect(folderNameInputLocator).toBeFocused();
6
https://testing-library.com/docs/queries/about
https://playwright.dev/docs/actionability
Use Locators
Automatic Retries
User-Facing Selectors
7
Use Locators
Accuracy
Speed
8
Be Direct
test("creating a folder with the same name as a file is not allowed", async () => {
// set up our system ready to be tested
const fs = await createFileSystem();
await fs.createFolder("/hello/");
await fs.createFile("/hello/world", "Hello, World");
// perform an action
const result = await fs.createFolder("/hello/world/");
// check that we get the result we expect
expect(result).toBeInstanceOf(Error);
});
9
Be Direct
test("creating a folder with the same name as a file is not allowed", async ({page}) => {
// set up our system ready to be tested
await page.goto("/");
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("hello");
await page.getByRole("button", { name: /create/i }).click();
await page.getByRole("link", { name: /hello/i }).click();
await page.getByRole("button", { name: /new file/i }).click();
await page.getByLabel("File name”).type("world");
await page.getByLabel("File contents").type("Hello, World!");
await page.getByRole("button", { name: /create/i }).click();
// perform an action
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("world");
await page.getByRole("button", { name: /create/i }).click();
// check that we get the result we expect
await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible();
});
10
Be Direct
test("creating a folder with the same name as a file is not allowed", async ({page}) => {
// set up our system ready to be tested
await page.goto("/");
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("hello");
await page.getByRole("button", { name: /create/i }).click();
await page.getByRole("link", { name: /hello/i }).click();
await page.getByRole("button", { name: /new file/i }).click();
await page.getByLabel("File name”).type("world");
await page.getByLabel("File contents").type("Hello, World!");
await page.getByRole("button", { name: /create/i }).click();
// perform an action
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("world");
await page.getByRole("button", { name: /create/i }).click();
// check that we get the result we expect
await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible();
});
Slow - waiting for browser interaction
Opaque - multiple lines to do one thin
Brittle - multiple layers to go through
test("creating a folder with the same name as a file is not allowed", async ({page}) => {
// set up our system ready to be tested
await post("/api/hello", { type: "folder" });
await post(“/api/hello/world", "Hello, World!")
await page.goto("/hello");
// perform an action
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("world");
await page.getByRole("button", { name: /create/i }).click();
// check that we get the result we expect
await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible();
});
11
Be Direct
test("creating a folder with the same name as a file is not allowed", async ({page}) => {
// set up our system ready to be tested
await post("/api/hello", { type: "folder" });
await post(“/api/hello/world", "Hello, World!")
await page.goto("/hello");
// perform an action
await page.getByRole("button", { name: /new folder/i }).click();
await page.getByLabel("Folder name").type("world");
await page.getByRole("button", { name: /create/i }).click();
// check that we get the result we expect
await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible();
});
12
Be Direct
Quicker - directly interacts w/ API (or in-browser store, et
Clearer - declares what I want to achieve
Solid - fewer layers where something can go wrong
13
Be Direct
Accuracy
Speed
test("test something specific about my application", async ({ page, myFixture }) => {
await myFixture.createNewFile("test file");
await myFixture.getByFileName("test file").click();
expect(await myFixture.apiClient.files({ query: { open: true } }))
.toEqual(["test file"]);
});
14
https://playwright.dev/docs/test-fixtures
Add Fixtures
test("test something specific about my application", async ({ page, myFixture }) => {
await myFixture.createNewFile("test file");
await myFixture.getByFileName("test file").click();
expect(await myFixture.apiClient.files({ query: { open: true } }))
.toEqual(["test file"]);
});
import { test as _baseTest } from "@playwright/test";
export const test = _baseTest.extend({
myFixture: async ({ page }, use) => {
// run pre-test async setup code here
// e.g. page.goto(...)
const apiClient = new ApiClient(page.url());
await use({
apiClient,
getByFileName(name: string) { /* ... */ },
async createNewFile() { /* ... */ },
})
}
})
15
https://playwright.dev/docs/test-fixtures
Add Fixtures
App-specific locators
Direct (typed) access to API
Common/shared routines
16
Add Fixtures
Speed
Accuracy
17
Delete Tests
This slide intentionally left blank
18
Delete Tests
Speed
Accuracy
jof@esveo.com
esveo.com/jof
@johz@hachyderm.io
Jonathan Frere
19
1. Use locators
• Reduces flakiness, speeds up tests, improves accessibility
2. Be Direct
• Not everything in an end-to-end test needs to be end-to-end!
• Get the system into the ready-to-test state ASAP
3. Add Fixtures
• Project-specific methods, selectors, etc make it easier to share
code and write clear tests
4. Delete Your Tests
• Write tests where they can do the most impact

More Related Content

PDF
Playwright Test automation frameworktest
PPTX
PlayWright Training - PlayWright Automation Training.pptx
PDF
Leveraging Playwright for API Testing.pdf
PDF
How to Use Playwright Locators_ A Detailed Guide.pdf
PDF
Testing in FrontEnd World by Nikita Galkin
PDF
Intro To JavaScript Unit Testing - Ran Mizrahi
PDF
TDD CrashCourse Part3: TDD Techniques
PDF
"Playwright can do this? An intro into e2e testing and Playwright", Stefan Ju...
Playwright Test automation frameworktest
PlayWright Training - PlayWright Automation Training.pptx
Leveraging Playwright for API Testing.pdf
How to Use Playwright Locators_ A Detailed Guide.pdf
Testing in FrontEnd World by Nikita Galkin
Intro To JavaScript Unit Testing - Ran Mizrahi
TDD CrashCourse Part3: TDD Techniques
"Playwright can do this? An intro into e2e testing and Playwright", Stefan Ju...

Similar to Dev Day 2024: Jonathan Frere - Playwright: Das Beste aus dem Dramatiker herausholen (20)

PDF
ES3-2020-06 Test Driven Development (TDD)
PDF
Playwright Testing Guide for QA Engineers.pdf
PDF
FITC Web Unleashed 2017 - Introduction to the World of Testing for Front-End ...
PDF
An Introduction to the World of Testing for Front-End Developers
PDF
Никита Галкин "Testing in Frontend World"
PDF
Introducing Playwright's New Test Runner
PDF
Vuejs testing
PDF
Playwright: A New Test Automation Framework for the Modern Web
PPTX
Building Robust Web Applications with Test-Driven Development and Playwright:...
PPTX
Writing better tests for your java script app
PDF
Intro to JavaScript Testing
PDF
JavaScript development methodology
PDF
Collaborating with Developers: How-to Guide for Test Engineers - By Gil Tayar
PDF
Playwright vs. Jest_ A Comprehensive Guide to Choosing the Right Testing Fram...
PDF
We Are All Testers Now: The Testing Pyramid and Front-End Development
PDF
Reliable Javascript
PDF
How to push a react js application in production and sleep better
PDF
How do I write Testable Javascript
PDF
How do I write testable javascript?
PDF
How do I write Testable Javascript?
ES3-2020-06 Test Driven Development (TDD)
Playwright Testing Guide for QA Engineers.pdf
FITC Web Unleashed 2017 - Introduction to the World of Testing for Front-End ...
An Introduction to the World of Testing for Front-End Developers
Никита Галкин "Testing in Frontend World"
Introducing Playwright's New Test Runner
Vuejs testing
Playwright: A New Test Automation Framework for the Modern Web
Building Robust Web Applications with Test-Driven Development and Playwright:...
Writing better tests for your java script app
Intro to JavaScript Testing
JavaScript development methodology
Collaborating with Developers: How-to Guide for Test Engineers - By Gil Tayar
Playwright vs. Jest_ A Comprehensive Guide to Choosing the Right Testing Fram...
We Are All Testers Now: The Testing Pyramid and Front-End Development
Reliable Javascript
How to push a react js application in production and sleep better
How do I write Testable Javascript
How do I write testable javascript?
How do I write Testable Javascript?
Ad

Recently uploaded (20)

PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PPTX
Mastering-Cybersecurity-The-Crucial-Role-of-Antivirus-Support-Services.pptx
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
Materi_Pemrograman_Komputer-Looping.pptx
PDF
Become an Agentblazer Champion Challenge Kickoff
PDF
A REACT POMODORO TIMER WEB APPLICATION.pdf
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
L1 - Introduction to python Backend.pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
Digital Strategies for Manufacturing Companies
PPTX
Presentation of Computer CLASS 2 .pptx
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
Online Work Permit System for Fast Permit Processing
PDF
System and Network Administration Chapter 2
PPTX
Introduction to Artificial Intelligence
PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Mastering-Cybersecurity-The-Crucial-Role-of-Antivirus-Support-Services.pptx
Softaken Excel to vCard Converter Software.pdf
2025 Textile ERP Trends: SAP, Odoo & Oracle
Materi_Pemrograman_Komputer-Looping.pptx
Become an Agentblazer Champion Challenge Kickoff
A REACT POMODORO TIMER WEB APPLICATION.pdf
How to Migrate SBCGlobal Email to Yahoo Easily
L1 - Introduction to python Backend.pptx
How to Choose the Right IT Partner for Your Business in Malaysia
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Digital Strategies for Manufacturing Companies
Presentation of Computer CLASS 2 .pptx
PTS Company Brochure 2025 (1).pdf.......
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Online Work Permit System for Fast Permit Processing
System and Network Administration Chapter 2
Introduction to Artificial Intelligence
ManageIQ - Sprint 268 Review - Slide Deck
Upgrade and Innovation Strategies for SAP ERP Customers
Ad

Dev Day 2024: Jonathan Frere - Playwright: Das Beste aus dem Dramatiker herausholen

  • 2. 2 https://playwright.dev/docs/writing-tests import { test, expect } from "@playwright/test"; test("has title", async ({ page }) => { await page.goto("https://playwright.dev/"); await expect(page).toHaveTitle(/Playwright/); }); test("get started link", async ({ page }) => { await page.goto("https://playwright.dev/"); await page.getByRole("link", { name: "Get started" }).click(); await expect( page.getByRole("heading", { name: "Installation" }), ).toBeVisible(); });
  • 3. 3 Testing Goals Accuracy Speed “How often will this test fail without me changing anything? “If I change my code and the test fails, is it likely that there’s a bug in my code?” “How quickly can I run this test?” “How quickly can I write this test?” “If this code doesn’t work, will the test still succeed?”
  • 4. 4 https://playwright.dev/docs/locators Use Locators page.getByLabel("Folder Name"); page.getByRole("button", { name: "New Folder" }); page.getByRole("listitem").filter({ hasText: "T-Shirt" }); page .getByRole("listitem") .filter({ hasText: "Trousers" }) .getByRole("button", { name: "Delete" });
  • 5. 5 https://testing-library.com/docs/queries/about https://playwright.dev/docs/actionability Use Locators // define some locators const newFolderButtonLocator = page.getByRole("button", { name: "New Folder" }); const folderNameInputLocator = page.getByLabel("Folder Name"); // load the page await page.goto("/page"); // find the button and click it await newFolderButtonLocator.click(); // check that the focus has been set correctly await expect(folderNameInputLocator).toBeFocused();
  • 6. // define some locators const newFolderButtonLocator = page.getByRole("button", { name: "New Folder" }); const folderNameInputLocator = page.getByLabel("Folder Name"); // load the page await page.goto("/page"); // find the button and click it await newFolderButtonLocator.click(); // check that the focus has been set correctly await expect(folderNameInputLocator).toBeFocused(); 6 https://testing-library.com/docs/queries/about https://playwright.dev/docs/actionability Use Locators Automatic Retries User-Facing Selectors
  • 8. 8 Be Direct test("creating a folder with the same name as a file is not allowed", async () => { // set up our system ready to be tested const fs = await createFileSystem(); await fs.createFolder("/hello/"); await fs.createFile("/hello/world", "Hello, World"); // perform an action const result = await fs.createFolder("/hello/world/"); // check that we get the result we expect expect(result).toBeInstanceOf(Error); });
  • 9. 9 Be Direct test("creating a folder with the same name as a file is not allowed", async ({page}) => { // set up our system ready to be tested await page.goto("/"); await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("hello"); await page.getByRole("button", { name: /create/i }).click(); await page.getByRole("link", { name: /hello/i }).click(); await page.getByRole("button", { name: /new file/i }).click(); await page.getByLabel("File name”).type("world"); await page.getByLabel("File contents").type("Hello, World!"); await page.getByRole("button", { name: /create/i }).click(); // perform an action await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("world"); await page.getByRole("button", { name: /create/i }).click(); // check that we get the result we expect await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible(); });
  • 10. 10 Be Direct test("creating a folder with the same name as a file is not allowed", async ({page}) => { // set up our system ready to be tested await page.goto("/"); await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("hello"); await page.getByRole("button", { name: /create/i }).click(); await page.getByRole("link", { name: /hello/i }).click(); await page.getByRole("button", { name: /new file/i }).click(); await page.getByLabel("File name”).type("world"); await page.getByLabel("File contents").type("Hello, World!"); await page.getByRole("button", { name: /create/i }).click(); // perform an action await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("world"); await page.getByRole("button", { name: /create/i }).click(); // check that we get the result we expect await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible(); }); Slow - waiting for browser interaction Opaque - multiple lines to do one thin Brittle - multiple layers to go through
  • 11. test("creating a folder with the same name as a file is not allowed", async ({page}) => { // set up our system ready to be tested await post("/api/hello", { type: "folder" }); await post(“/api/hello/world", "Hello, World!") await page.goto("/hello"); // perform an action await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("world"); await page.getByRole("button", { name: /create/i }).click(); // check that we get the result we expect await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible(); }); 11 Be Direct
  • 12. test("creating a folder with the same name as a file is not allowed", async ({page}) => { // set up our system ready to be tested await post("/api/hello", { type: "folder" }); await post(“/api/hello/world", "Hello, World!") await page.goto("/hello"); // perform an action await page.getByRole("button", { name: /new folder/i }).click(); await page.getByLabel("Folder name").type("world"); await page.getByRole("button", { name: /create/i }).click(); // check that we get the result we expect await expect(page.getByText("A folder with the name 'world' already exists")).toBeVisible(); }); 12 Be Direct Quicker - directly interacts w/ API (or in-browser store, et Clearer - declares what I want to achieve Solid - fewer layers where something can go wrong
  • 14. test("test something specific about my application", async ({ page, myFixture }) => { await myFixture.createNewFile("test file"); await myFixture.getByFileName("test file").click(); expect(await myFixture.apiClient.files({ query: { open: true } })) .toEqual(["test file"]); }); 14 https://playwright.dev/docs/test-fixtures Add Fixtures
  • 15. test("test something specific about my application", async ({ page, myFixture }) => { await myFixture.createNewFile("test file"); await myFixture.getByFileName("test file").click(); expect(await myFixture.apiClient.files({ query: { open: true } })) .toEqual(["test file"]); }); import { test as _baseTest } from "@playwright/test"; export const test = _baseTest.extend({ myFixture: async ({ page }, use) => { // run pre-test async setup code here // e.g. page.goto(...) const apiClient = new ApiClient(page.url()); await use({ apiClient, getByFileName(name: string) { /* ... */ }, async createNewFile() { /* ... */ }, }) } }) 15 https://playwright.dev/docs/test-fixtures Add Fixtures App-specific locators Direct (typed) access to API Common/shared routines
  • 17. 17 Delete Tests This slide intentionally left blank
  • 19. [email protected] esveo.com/jof @[email protected] Jonathan Frere 19 1. Use locators • Reduces flakiness, speeds up tests, improves accessibility 2. Be Direct • Not everything in an end-to-end test needs to be end-to-end! • Get the system into the ready-to-test state ASAP 3. Add Fixtures • Project-specific methods, selectors, etc make it easier to share code and write clear tests 4. Delete Your Tests • Write tests where they can do the most impact