🎭 Playwright Test
Playful testing framework
Talk Prerequisites
https:/
/nodejs.org/ Web Platform
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
○ TypeScript support out-of-the-box
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
○ TypeScript support out-of-the-box
○ Parallel execution out-of-the-box
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
○ TypeScript support out-of-the-box
○ Parallel execution out-of-the-box
○ Cross-browser, Snapshots, Fixtures, ...
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
○ TypeScript support out-of-the-box
○ Parallel execution out-of-the-box
○ Cross-browser, Snapshots, Fixtures, …
○ Time-travel debugging 🔥
What is Playwright Test?
https:/
/github.com/microsoft/playwright
● New product from Playwright Team
● Batteries-included test framework for end-to-end testing
○ TypeScript support out-of-the-box
○ Parallel execution out-of-the-box
○ Cross-browser, Snapshots, Fixtures, …
○ Time-travel debugging 🔥
● Open Source, Free
What is Playwright Test?
https:/
/github.com/microsoft/playwright
Agenda
1. Getting Started 🚀
2. Fixtures 🦄
3. Configuration 🛠
4. Artifacts Management 💎
5. Playwright Tracing 󰨂
Act I
Getting Started
🚀 Getting Started
🦄 Fixtures
🛠 Configuration
💎 Artifacts
󰨂 Tracing
🍿 Demo: Getting Started 🍿
Installation
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
Running Test
# .github/workflows/tests.yml
on: [push]
jobs:
run_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npx playwright install-deps
- run: npx playwright install
- run: npx playwright test
G
i
t
h
u
b
A
c
t
i
o
n
s
💎 Artifacts
Act II
Fixtures
🚀 Getting Started
🦄 Fixtures
🛠 Configuration
󰨂 Tracing
🎁 Treats
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
“Fixture”
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
1. Fully isolated Playwright page
“Fixture”
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page, context }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
2. Fully isolated Playwright context for multi-page tests
“Fixture”
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page, context, browserName }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
3. Browser name: ‘chromium’, ‘firefox’ or ‘webkit’
“Fixture”
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page, context, browserName, isMobile }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
4. “true” when running in mobile browser
“Fixture”
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page, context, browserName, isMobile }) => {
await page.goto('https://playwright.dev/');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
4. “true” when running in mobile browser
“Fixture”
5. channel
6. timezoneId
7. locale
8. ...
Concept: “Fixtures” 🦄
● Borrowed from PyTest
● Isolated configurable environment for each test
● Playwright Test comes with many ready-to-use fixtures
● Create your own fixtures instead of “beforeEach” / “afterEach” hooks
○ Organize tests semantically, not by environment
○ Fixtures are only initialized when required by test
○ Fixtures are ~20% less code
● Read more: https:/
/playwright.dev/docs/test-fixtures
💎 Artifacts
Act III
Configuration
🚀 Getting Started
🦄 Fixtures
🔧 Configuration
󰨂 Tracing
Configuration
1. Global configuration via configuration file
2. Granular configuration via test.use()
3. Data-driven configuration
Configuration File
● JavaScript: playwright.config.js
● TypeScript: playwright.config.ts
Configuration File
● JavaScript: playwright.config.js
● TypeScript: playwright.config.ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
};
export default config;
● globalSetup
● globalTeardown
● ...
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
};
export default config;
● globalSetup
● globalTeardown
● ...
T
y
p
e
S
c
r
i
p
t
First-Party:
● dot
● list
● line
● json
● junit
Third-Party:
● experimental-allure-playwright 🔥
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
};
export default config;
● globalSetup
● globalTeardown
● ...
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
}]};
export default config;
● globalSetup
● globalTeardown
● ...
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
}]};
export default config;
● globalSetup
● globalTeardown
● ...
● outputDir
● testDir
● ...
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'chromium',
},
}]};
export default config;
● globalSetup
● globalTeardown
● ...
● outputDir
● testDir
● ...
T
y
p
e
S
c
r
i
p
t
● browserName
● headless
● screenshot
● trace
● ...
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'chromium',
},
}]};
export default config;
● globalSetup
● globalTeardown
● ...
● outputDir
● testDir
● ...
● browserName
● headless
● screenshot
● trace
● ...
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'chromium',
},
}]};
export default config;
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
page; // chromium page
});
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'chromium',
},
}]};
export default config;
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
page; // chromium page
});
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'chromium',
},
}]};
export default config;
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
page; // chromium page
});
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
// 1. Runner configuration
reporter: 'list',
projects: [{
// 2. Project configuration
name: 'chromium',
retries: 0,
timeout: 30000,
// 3. Fixtures configuration
use: {
browserName: 'webkit',
},
}]};
export default config;
T
y
p
e
S
c
r
i
p
t
// test.spec.ts
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
page; // webkit page
});
● javaScriptEnabled
● launchOptions
● locale
● offline
● permissions
● proxy
● screenshot
● storageState
● timezoneId
● trace
● userAgent
● video
● viewport
● acceptDownloads
● baseURL
● browserName
● bypassCSP
● channel
● colorScheme
● deviceScaleFactor
● extraHTPHeaders
● geolocation
● hasTouch
● headless
● httpCredentials
● ignoreHTTPSErrors
Fixtures Configuration
Granular Fixtures Configuration
● Per-file configuration
● Per-suite configuration
Granular Fixtures Configuration
● Per-file configuration
● Per-suite configuration
// france.spec.ts
import { test, expect } from '@playwright/test';
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
test('should work', async ({ page }) => { /* ... test goes here ... */ });
test('should use euro', async ({ page }) => { /* ... */ });
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
test('should work', async ({ page }) => { /* ... test goes here ... */ });
test('should use euro', async ({ page }) => { /* ... */ });
test.describe('light theme', () => {
});
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
test('should work', async ({ page }) => { /* ... test goes here ... */ });
test('should use euro', async ({ page }) => { /* ... */ });
test.describe('light theme', () => {
test.use({ colorScheme: 'light' }); // per-suite configuration
});
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
test('should work', async ({ page }) => { /* ... test goes here ... */ });
test('should use euro', async ({ page }) => { /* ... */ });
test.describe('light theme', () => {
test.use({ colorScheme: 'light' }); // per-suite configuration
test('should be light', async ({ page }) => { /* ... */ });
});
T
y
p
e
S
c
r
i
p
t
// france.spec.ts
import { test, expect } from '@playwright/test';
// per-file configuration
test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' });
test('should work', async ({ page }) => { /* ... test goes here ... */ });
test('should use euro', async ({ page }) => { /* ... */ });
test.describe('light theme', () => {
test.use({ colorScheme: 'light' }); // per-suite configuration
test('should be light', async ({ page }) => { /* ... */ });
});
test.describe('dark theme', () => {
test.use({ colorScheme: 'dark' }); // per-suite configuration
test('should be dark', async ({ page }) => { /* ... */ });
});
T
y
p
e
S
c
r
i
p
t
Data-Driven Tests
Data-Driven Tests
Data-Driven Tests
// check-urls.spec.ts
import { test, expect } from '@playwright/test';
T
y
p
e
S
c
r
i
p
t
// check-urls.spec.ts
import { test, expect } from '@playwright/test';
const urls = require('./urls.json');
T
y
p
e
S
c
r
i
p
t
// check-urls.spec.ts
import { test, expect } from '@playwright/test';
const urls = require('./urls.json');
for (const url of urls) {
}
T
y
p
e
S
c
r
i
p
t
// check-urls.spec.ts
import { test, expect } from '@playwright/test';
const urls = require('./urls.json');
for (const url of urls) {
test(`check ${url}`, async ({ page }) => {
await page.goto(url);
});
}
T
y
p
e
S
c
r
i
p
t
// check-urls.spec.ts
import { test, expect } from '@playwright/test';
const urls = require('./urls.json');
for (const url of urls) {
test(`check ${url}`, async ({ page }) => {
await page.goto(url);
});
}
T
y
p
e
S
c
r
i
p
t
NOTE: Make sure to have
different test titles
🍿 Demo: iPhone 🍿
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config : PlaywrightTestConfig = {
projects: [
{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
{
name: 'iphone',
use: { ...devices['iPhone 12 Pro'], },
},
]
};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config : PlaywrightTestConfig = {
projects: [
{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
{
name: 'iphone',
use: { ...devices['iPhone 12 Pro'], },
},
]
};
export default config;
1. Import Devices
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config : PlaywrightTestConfig = {
projects: [
{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
{
name: 'iphone',
use: { ...devices['iPhone 12 Pro'], },
},
]
};
export default config;
1. Import Devices
T
y
p
e
S
c
r
i
p
t
2. Run tests on iPhone
// test.spec.ts
import { test, expect } from '@playwright/test';
test('should work', async ({ page, isMobile }) => {
await page.goto('https://playwright.dev');
if (isMobile)
await page.click('[aria-label="Navigation bar toggle"]');
await page.click('a:visible:has-text("Docs")');
expect(page.url()).toBe('https://playwright.dev/docs/intro');
});
T
y
p
e
S
c
r
i
p
t
Launching Playwright Inspector
Playwright Inspector
Act IV
Artifacts Management
🚀 Getting Started
🦄 Fixtures
🛠 Configuration
💎 Artifacts
󰨂 Tracing
Playwright Test Artifacts 💎
Test Artifacts – any by-product of test running that helps debug test failures.
All artifacts are stored by default in test-results folder.
Playwright Test Artifacts 💎
Test Artifacts – any by-product of test running that helps debug test failures.
All artifacts are stored by default in test-results folder.
1. screenshots
Playwright Test Artifacts 💎
Test Artifacts – any by-product of test running that helps debug test failures.
All artifacts are stored by default in test-results folder.
1. screenshots 2. videos
Playwright Test Artifacts 💎
Test Artifacts – any by-product of test running that helps debug test failures.
All artifacts are stored by default in test-results folder.
1. screenshots
��♂
3. traces
2. videos
D
i
s
c
u
s
s
e
d
l
a
t
e
r
t
o
d
a
y
!
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
retries: 2,
use: {
screenshot: 'only-on-failure',
video: 'off',
trace: 'on-first-retry',
},
projects: [{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
]};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
retries: 2,
use: {
screenshot: 'only-on-failure',
video: 'off',
trace: 'on-first-retry',
},
projects: [{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
]};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
retries: 2,
use: {
screenshot: 'only-on-failure',
video: 'off',
trace: 'on-first-retry',
},
projects: [{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
]};
export default config;
T
y
p
e
S
c
r
i
p
t
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config : PlaywrightTestConfig = {
retries: 2,
use: {
screenshot: 'only-on-failure',
video: 'off',
trace: 'on-first-retry',
},
projects: [{
name: 'Desktop Chromium',
use: { browserName: 'chromium', },
},
]};
export default config;
T
y
p
e
S
c
r
i
p
t
Recommended 👍
Screenshot Artifacts
● “on” – always record screenshot after the test is finished
● “off” – never record screenshot after the test is finished
● “only-on-failure” – record screenshot after the test is failed
Screenshot Artifacts
● “on” – always record screenshot after the test is finished
● “off” – never record screenshot after the test is finished
● “only-on-failure” – record screenshot after the test is failed
Recommended 👍
Video Artifacts
● “on” – always record video of a test
● “off” – never record video of a test
● “retain-on-failure” – always record video of a test, but keep only videos of
failed test runs.
● “on-first-retry” – only record video when retrying test
Video Artifacts
● “on” – always record video of a test
● “off” – never record video of a test
● “retain-on-failure” – always record video of a test, but keep only videos of
failed test runs.
● “on-first-retry” – only record video when retrying test
Recommended 👍
Trace Artifacts
● “on” – always record trace of a test
● “off” – never record trace of a test
● “retain-on-failure” – always record trace of a test, but keep only traces of
failed test runs.
● “on-first-retry” – only record trace when retrying test
��
Trace Artifacts
● “on” – always record trace of a test
● “off” – never record trace of a test
● “retain-on-failure” – always record trace of a test, but keep only traces of
failed test runs.
● “on-first-retry” – only record trace when retrying test
��
Recommended 👍
# .github/workflows/tests.yml
on: [push]
jobs:
run_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npx playwright install-deps
- run: npx playwright install
- run: npx playwright test
G
i
t
h
u
b
A
c
t
i
o
n
s
# .github/workflows/tests.yml
on: [push]
jobs:
run_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npx playwright install-deps
- run: npx playwright install
- run: npx playwright test
- uses: actions/upload-artifact@v1
if: always()
with:
name: test-results
path: test-results
G
i
t
h
u
b
A
c
t
i
o
n
s
Uploading Artifacts
Act V
Playwright Tracing
🚀 Getting Started
🦄 Fixtures
🛠 Configuration
💎 Artifacts
󰨂 Tracing
Playwright Tracing
● Playwright actions
● Playwright events
● DOM snapshots 🔥
● Screenshots
● Network log
● Console log
Playwright Tracing
trace.zip files
● Playwright actions
● Playwright events
● DOM snapshots 🔥
● Screenshots
● Network log
● Console log
Playwright Tracing
● GUI tool to explore trace
files
● Bundled with Playwright
trace.zip files Trace Viewer
● Playwright actions
● Playwright events
● DOM snapshots 🔥
● Screenshots
● Network log
● Console log
Playwright Tracing
● GUI tool to explore trace
files
● Bundled with Playwright
trace.zip files Trace Viewer
Time Travel Debugging
🍿 Demo: Trace Viewer 🍿
Opening Playwright Trace
Timeline
Actions
Details
DOM Snapshot 🔥
🍿 Demo: Post-mortem 🍿
Demo Recap
● “Right click → Inspect” to open DevTools on DOM Snapshot
Demo Recap
Demo Recap
● “Right click → Inspect” to open DevTools on DOM Snapshot
● “playwright.selector($0)” in DevTools console to generate selector
Conclusion?
🚀 Getting Started
🦄 Fixtures
🛠 Configuration
💎 Artifacts
󰨂 Tracing
Web Testing
can be
Fun
Andrey Lushnikov
@playwrightweb
Q
u
e
s
t
i
o
n
s
?
Playwright Test
https:/
/aka.ms/playwright-slack
microsoft/playwright
@aslushnikov
aslushnikov@gmail.com
Introducing Playwright's New Test Runner

Introducing Playwright's New Test Runner

  • 1.
  • 2.
  • 3.
    What is PlaywrightTest? https:/ /github.com/microsoft/playwright
  • 4.
    ● New productfrom Playwright Team What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 5.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 6.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing ○ TypeScript support out-of-the-box What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 7.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing ○ TypeScript support out-of-the-box ○ Parallel execution out-of-the-box What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 8.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing ○ TypeScript support out-of-the-box ○ Parallel execution out-of-the-box ○ Cross-browser, Snapshots, Fixtures, ... What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 9.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing ○ TypeScript support out-of-the-box ○ Parallel execution out-of-the-box ○ Cross-browser, Snapshots, Fixtures, … ○ Time-travel debugging 🔥 What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 10.
    ● New productfrom Playwright Team ● Batteries-included test framework for end-to-end testing ○ TypeScript support out-of-the-box ○ Parallel execution out-of-the-box ○ Cross-browser, Snapshots, Fixtures, … ○ Time-travel debugging 🔥 ● Open Source, Free What is Playwright Test? https:/ /github.com/microsoft/playwright
  • 11.
    Agenda 1. Getting Started🚀 2. Fixtures 🦄 3. Configuration 🛠 4. Artifacts Management 💎 5. Playwright Tracing 󰨂
  • 12.
    Act I Getting Started 🚀Getting Started 🦄 Fixtures 🛠 Configuration 💎 Artifacts 󰨂 Tracing
  • 13.
    🍿 Demo: GettingStarted 🍿
  • 14.
  • 15.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t
  • 16.
  • 17.
    # .github/workflows/tests.yml on: [push] jobs: run_tests: runs-on:ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 - run: npm ci - run: npx playwright install-deps - run: npx playwright install - run: npx playwright test G i t h u b A c t i o n s
  • 20.
    💎 Artifacts Act II Fixtures 🚀Getting Started 🦄 Fixtures 🛠 Configuration 󰨂 Tracing 🎁 Treats
  • 21.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t
  • 22.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t
  • 23.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t “Fixture”
  • 24.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t 1. Fully isolated Playwright page “Fixture”
  • 25.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page, context }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t 2. Fully isolated Playwright context for multi-page tests “Fixture”
  • 26.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page, context, browserName }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t 3. Browser name: ‘chromium’, ‘firefox’ or ‘webkit’ “Fixture”
  • 27.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page, context, browserName, isMobile }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t 4. “true” when running in mobile browser “Fixture”
  • 28.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('test', async ({ page, context, browserName, isMobile }) => { await page.goto('https://playwright.dev/'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t 4. “true” when running in mobile browser “Fixture” 5. channel 6. timezoneId 7. locale 8. ...
  • 29.
    Concept: “Fixtures” 🦄 ●Borrowed from PyTest ● Isolated configurable environment for each test ● Playwright Test comes with many ready-to-use fixtures ● Create your own fixtures instead of “beforeEach” / “afterEach” hooks ○ Organize tests semantically, not by environment ○ Fixtures are only initialized when required by test ○ Fixtures are ~20% less code ● Read more: https:/ /playwright.dev/docs/test-fixtures
  • 30.
    💎 Artifacts Act III Configuration 🚀Getting Started 🦄 Fixtures 🔧 Configuration 󰨂 Tracing
  • 31.
    Configuration 1. Global configurationvia configuration file 2. Granular configuration via test.use() 3. Data-driven configuration
  • 32.
    Configuration File ● JavaScript:playwright.config.js ● TypeScript: playwright.config.ts
  • 33.
    Configuration File ● JavaScript:playwright.config.js ● TypeScript: playwright.config.ts
  • 34.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { }; export default config; T y p e S c r i p t
  • 35.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { }; export default config; T y p e S c r i p t
  • 36.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { }; export default config; T y p e S c r i p t
  • 37.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { }; export default config; T y p e S c r i p t
  • 38.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', }; export default config; ● globalSetup ● globalTeardown ● ... T y p e S c r i p t
  • 39.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', }; export default config; ● globalSetup ● globalTeardown ● ... T y p e S c r i p t First-Party: ● dot ● list ● line ● json ● junit Third-Party: ● experimental-allure-playwright 🔥
  • 40.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', }; export default config; ● globalSetup ● globalTeardown ● ... T y p e S c r i p t
  • 41.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ }]}; export default config; ● globalSetup ● globalTeardown ● ... T y p e S c r i p t
  • 42.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, }]}; export default config; ● globalSetup ● globalTeardown ● ... ● outputDir ● testDir ● ... T y p e S c r i p t
  • 43.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'chromium', }, }]}; export default config; ● globalSetup ● globalTeardown ● ... ● outputDir ● testDir ● ... T y p e S c r i p t ● browserName ● headless ● screenshot ● trace ● ...
  • 44.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'chromium', }, }]}; export default config; ● globalSetup ● globalTeardown ● ... ● outputDir ● testDir ● ... ● browserName ● headless ● screenshot ● trace ● ... T y p e S c r i p t
  • 45.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'chromium', }, }]}; export default config; T y p e S c r i p t // test.spec.ts import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { page; // chromium page });
  • 46.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'chromium', }, }]}; export default config; T y p e S c r i p t // test.spec.ts import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { page; // chromium page });
  • 47.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'chromium', }, }]}; export default config; T y p e S c r i p t // test.spec.ts import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { page; // chromium page });
  • 48.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { // 1. Runner configuration reporter: 'list', projects: [{ // 2. Project configuration name: 'chromium', retries: 0, timeout: 30000, // 3. Fixtures configuration use: { browserName: 'webkit', }, }]}; export default config; T y p e S c r i p t // test.spec.ts import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { page; // webkit page });
  • 49.
    ● javaScriptEnabled ● launchOptions ●locale ● offline ● permissions ● proxy ● screenshot ● storageState ● timezoneId ● trace ● userAgent ● video ● viewport ● acceptDownloads ● baseURL ● browserName ● bypassCSP ● channel ● colorScheme ● deviceScaleFactor ● extraHTPHeaders ● geolocation ● hasTouch ● headless ● httpCredentials ● ignoreHTTPSErrors Fixtures Configuration
  • 50.
    Granular Fixtures Configuration ●Per-file configuration ● Per-suite configuration
  • 51.
    Granular Fixtures Configuration ●Per-file configuration ● Per-suite configuration
  • 52.
    // france.spec.ts import {test, expect } from '@playwright/test'; T y p e S c r i p t
  • 53.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); T y p e S c r i p t
  • 54.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); test('should work', async ({ page }) => { /* ... test goes here ... */ }); test('should use euro', async ({ page }) => { /* ... */ }); T y p e S c r i p t
  • 55.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); test('should work', async ({ page }) => { /* ... test goes here ... */ }); test('should use euro', async ({ page }) => { /* ... */ }); test.describe('light theme', () => { }); T y p e S c r i p t
  • 56.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); test('should work', async ({ page }) => { /* ... test goes here ... */ }); test('should use euro', async ({ page }) => { /* ... */ }); test.describe('light theme', () => { test.use({ colorScheme: 'light' }); // per-suite configuration }); T y p e S c r i p t
  • 57.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); test('should work', async ({ page }) => { /* ... test goes here ... */ }); test('should use euro', async ({ page }) => { /* ... */ }); test.describe('light theme', () => { test.use({ colorScheme: 'light' }); // per-suite configuration test('should be light', async ({ page }) => { /* ... */ }); }); T y p e S c r i p t
  • 58.
    // france.spec.ts import {test, expect } from '@playwright/test'; // per-file configuration test.use({ locale: 'fr-FR', timezoneId: 'Europe/Paris' }); test('should work', async ({ page }) => { /* ... test goes here ... */ }); test('should use euro', async ({ page }) => { /* ... */ }); test.describe('light theme', () => { test.use({ colorScheme: 'light' }); // per-suite configuration test('should be light', async ({ page }) => { /* ... */ }); }); test.describe('dark theme', () => { test.use({ colorScheme: 'dark' }); // per-suite configuration test('should be dark', async ({ page }) => { /* ... */ }); }); T y p e S c r i p t
  • 59.
  • 60.
  • 61.
  • 62.
    // check-urls.spec.ts import {test, expect } from '@playwright/test'; T y p e S c r i p t
  • 63.
    // check-urls.spec.ts import {test, expect } from '@playwright/test'; const urls = require('./urls.json'); T y p e S c r i p t
  • 64.
    // check-urls.spec.ts import {test, expect } from '@playwright/test'; const urls = require('./urls.json'); for (const url of urls) { } T y p e S c r i p t
  • 65.
    // check-urls.spec.ts import {test, expect } from '@playwright/test'; const urls = require('./urls.json'); for (const url of urls) { test(`check ${url}`, async ({ page }) => { await page.goto(url); }); } T y p e S c r i p t
  • 66.
    // check-urls.spec.ts import {test, expect } from '@playwright/test'; const urls = require('./urls.json'); for (const url of urls) { test(`check ${url}`, async ({ page }) => { await page.goto(url); }); } T y p e S c r i p t NOTE: Make sure to have different test titles
  • 67.
  • 68.
    // playwright.config.ts import {PlaywrightTestConfig, devices } from '@playwright/test'; const config : PlaywrightTestConfig = { projects: [ { name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, { name: 'iphone', use: { ...devices['iPhone 12 Pro'], }, }, ] }; export default config; T y p e S c r i p t
  • 69.
    // playwright.config.ts import {PlaywrightTestConfig, devices } from '@playwright/test'; const config : PlaywrightTestConfig = { projects: [ { name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, { name: 'iphone', use: { ...devices['iPhone 12 Pro'], }, }, ] }; export default config; 1. Import Devices T y p e S c r i p t
  • 70.
    // playwright.config.ts import {PlaywrightTestConfig, devices } from '@playwright/test'; const config : PlaywrightTestConfig = { projects: [ { name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, { name: 'iphone', use: { ...devices['iPhone 12 Pro'], }, }, ] }; export default config; 1. Import Devices T y p e S c r i p t 2. Run tests on iPhone
  • 71.
    // test.spec.ts import {test, expect } from '@playwright/test'; test('should work', async ({ page, isMobile }) => { await page.goto('https://playwright.dev'); if (isMobile) await page.click('[aria-label="Navigation bar toggle"]'); await page.click('a:visible:has-text("Docs")'); expect(page.url()).toBe('https://playwright.dev/docs/intro'); }); T y p e S c r i p t
  • 72.
  • 73.
  • 74.
    Act IV Artifacts Management 🚀Getting Started 🦄 Fixtures 🛠 Configuration 💎 Artifacts 󰨂 Tracing
  • 75.
    Playwright Test Artifacts💎 Test Artifacts – any by-product of test running that helps debug test failures. All artifacts are stored by default in test-results folder.
  • 76.
    Playwright Test Artifacts💎 Test Artifacts – any by-product of test running that helps debug test failures. All artifacts are stored by default in test-results folder. 1. screenshots
  • 77.
    Playwright Test Artifacts💎 Test Artifacts – any by-product of test running that helps debug test failures. All artifacts are stored by default in test-results folder. 1. screenshots 2. videos
  • 78.
    Playwright Test Artifacts💎 Test Artifacts – any by-product of test running that helps debug test failures. All artifacts are stored by default in test-results folder. 1. screenshots ��♂ 3. traces 2. videos D i s c u s s e d l a t e r t o d a y !
  • 79.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { retries: 2, use: { screenshot: 'only-on-failure', video: 'off', trace: 'on-first-retry', }, projects: [{ name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, ]}; export default config; T y p e S c r i p t
  • 80.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { retries: 2, use: { screenshot: 'only-on-failure', video: 'off', trace: 'on-first-retry', }, projects: [{ name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, ]}; export default config; T y p e S c r i p t
  • 81.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { retries: 2, use: { screenshot: 'only-on-failure', video: 'off', trace: 'on-first-retry', }, projects: [{ name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, ]}; export default config; T y p e S c r i p t
  • 82.
    // playwright.config.ts import {PlaywrightTestConfig } from '@playwright/test'; const config : PlaywrightTestConfig = { retries: 2, use: { screenshot: 'only-on-failure', video: 'off', trace: 'on-first-retry', }, projects: [{ name: 'Desktop Chromium', use: { browserName: 'chromium', }, }, ]}; export default config; T y p e S c r i p t Recommended 👍
  • 83.
    Screenshot Artifacts ● “on”– always record screenshot after the test is finished ● “off” – never record screenshot after the test is finished ● “only-on-failure” – record screenshot after the test is failed
  • 84.
    Screenshot Artifacts ● “on”– always record screenshot after the test is finished ● “off” – never record screenshot after the test is finished ● “only-on-failure” – record screenshot after the test is failed Recommended 👍
  • 85.
    Video Artifacts ● “on”– always record video of a test ● “off” – never record video of a test ● “retain-on-failure” – always record video of a test, but keep only videos of failed test runs. ● “on-first-retry” – only record video when retrying test
  • 86.
    Video Artifacts ● “on”– always record video of a test ● “off” – never record video of a test ● “retain-on-failure” – always record video of a test, but keep only videos of failed test runs. ● “on-first-retry” – only record video when retrying test Recommended 👍
  • 87.
    Trace Artifacts ● “on”– always record trace of a test ● “off” – never record trace of a test ● “retain-on-failure” – always record trace of a test, but keep only traces of failed test runs. ● “on-first-retry” – only record trace when retrying test ��
  • 88.
    Trace Artifacts ● “on”– always record trace of a test ● “off” – never record trace of a test ● “retain-on-failure” – always record trace of a test, but keep only traces of failed test runs. ● “on-first-retry” – only record trace when retrying test �� Recommended 👍
  • 89.
    # .github/workflows/tests.yml on: [push] jobs: run_tests: runs-on:ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 - run: npm ci - run: npx playwright install-deps - run: npx playwright install - run: npx playwright test G i t h u b A c t i o n s
  • 90.
    # .github/workflows/tests.yml on: [push] jobs: run_tests: runs-on:ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 - run: npm ci - run: npx playwright install-deps - run: npx playwright install - run: npx playwright test - uses: actions/upload-artifact@v1 if: always() with: name: test-results path: test-results G i t h u b A c t i o n s Uploading Artifacts
  • 91.
    Act V Playwright Tracing 🚀Getting Started 🦄 Fixtures 🛠 Configuration 💎 Artifacts 󰨂 Tracing
  • 92.
  • 93.
    ● Playwright actions ●Playwright events ● DOM snapshots 🔥 ● Screenshots ● Network log ● Console log Playwright Tracing trace.zip files
  • 94.
    ● Playwright actions ●Playwright events ● DOM snapshots 🔥 ● Screenshots ● Network log ● Console log Playwright Tracing ● GUI tool to explore trace files ● Bundled with Playwright trace.zip files Trace Viewer
  • 95.
    ● Playwright actions ●Playwright events ● DOM snapshots 🔥 ● Screenshots ● Network log ● Console log Playwright Tracing ● GUI tool to explore trace files ● Bundled with Playwright trace.zip files Trace Viewer Time Travel Debugging
  • 96.
    🍿 Demo: TraceViewer 🍿
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
    ● “Right click→ Inspect” to open DevTools on DOM Snapshot Demo Recap
  • 102.
    Demo Recap ● “Rightclick → Inspect” to open DevTools on DOM Snapshot ● “playwright.selector($0)” in DevTools console to generate selector
  • 103.
    Conclusion? 🚀 Getting Started 🦄Fixtures 🛠 Configuration 💎 Artifacts 󰨂 Tracing
  • 104.
  • 105.