SlideShare a Scribd company logo
1 of 150
Download to read offline
🎭 Playwright
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
● 2011-...
Chrome DevTools Protocol
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
● 2011-...
Chrome DevTools Protocol
● 2015-2016
Node.js Debugger
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
● 2011-...
Chrome DevTools Protocol
● 2015-2016
Node.js Debugger
● 2017-2019
Puppeteer
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
● 2011-...
Chrome DevTools Protocol
● 2015-2016
Node.js Debugger
● 2017-2019
Puppeteer
Who We Are
● 2009-2019
WebKit Web Inspector
Chrome Developer Tools
● 2011-...
Chrome DevTools Protocol
● 2015-2016
Node.js Debugger
● 2017-2019
Puppeteer
● 2019-...
Playwright
Who We Are
Playwright
github.com/microsoft/playwright
🍿 Demo Time! 🍿
import {chromium, firefox, webkit} from 'playwright';
for (const browserType of [chromium, firefox, webkit]) {
const browser = await browserType.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.screenshot({path: `image-${browserType.name()}.png`});
await browser.close();
}
import {chromium, firefox, webkit} from 'playwright';
for (const browserType of [chromium, firefox, webkit]) {
const browser = await browserType.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.screenshot({path: `image-${browserType.name()}.png`});
await browser.close();
}
J
a
v
a
S
c
r
i
p
t
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
for browser_type in [p.chromium, p.firefox, p.webkit]:
browser = browser_type.launch()
page = browser.new_page()
page.goto("https://playwright.dev")
page.screenshot(path="image-" + browser_type.name + ".png")
browser.close()
P
y
t
h
o
n
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
List<BrowserType> browserTypes = Arrays.asList(
playwright.chromium(), playwright.webkit(), playwright.firefox()
);
for (BrowserType browserType : browserTypes) {
try (Browser browser = browserType.launch()) {
Page page = browser.newPage();
page.navigate("http://playwright.dev");
page.screenshot(new Page.ScreenshotOptions()
.setPath(Paths.get("image-" + browserType.name() + ".png")));
}
}
}
}
J
a
v
a
Why Playwright?
Playwright:
✅ dependable
✅ efficient
✅ capable
✅ ubiquitous
✅ delightful
✅ lively
Act I
Dependable
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
Dependable
👌 We Triage Issues in <48 hours
📚 We Fix Issues (>1600 fixed)
✈ We Take Full Responsibility
github.com/microsoft/playwright
Downloads API
Downloads API
Level 1: Browser Engineering
C++
- Chromium Development
- Improving Chrome DevTools Protocol
- Google Chrome, Microsoft Edge, Opera, etc
Level 1: Browser Engineering
C++
- Chromium Development
- Improving Chrome DevTools Protocol
- Google Chrome, Microsoft Edge, Opera, etc
- WebKit Development
- Improving Web Inspector Protocol
- Safari, Mobile Safari, Epiphany, etc
Level 1: Browser Engineering
C++
- Chromium Development
- Improving Chrome DevTools Protocol
- Google Chrome, Microsoft Edge, Opera, etc
- WebKit Development
- Improving Web Inspector Protocol
- Safari, Mobile Safari, Epiphany, etc
- Firefox Development
- Improving “Juggler” Protocol
- Mozilla Firefox
Level 1: Browser Engineering
C++
- Chromium Development
- Improving Chrome DevTools Protocol
- Google Chrome, Microsoft Edge, Opera, etc
- WebKit Development
- Improving Web Inspector Protocol
- Safari, Mobile Safari, Epiphany, etc
- Firefox Development
- Improving “Juggler” Protocol
- Mozilla Firefox
Level 1: Browser Engineering
C++
Level 2: Playwright Driver
Level 1: Browser Engineering
C++
TypeScript
- Single web automation protocol
- Unify all remote debugging protocols
- Expose “Downloads API” in driver
Level 2: Playwright Driver
🎭 Playwright Driver
Level 1: Browser Engineering
C++
TypeScript
Level 3: Language Bindings
🎭 Playwright Driver
Level 1: Browser Engineering
C++
Level 2: Playwright Driver
TypeScript
Level 3: Language Bindings
🎭 Playwright Driver
Level 1: Browser Engineering
C++
Level 2: Playwright Driver
Playwright
Playwright
for
Java
Playwright
for
Python
Playwright
for
C#
Expose language idiomatic API to
control downloads
TypeScript
Level 3: Language Bindings
🎭 Playwright Driver
Level 1: Browser Engineering
C++
Level 2: Playwright Driver
Playwright
Playwright
for
Java
Playwright
for
Python
Playwright
for
C#
Expose language idiomatic API to
control downloads
TypeScript
Level 3: Language Bindings
🎭 Playwright Driver
Level 1: Browser Engineering
C++
Level 2: Playwright Driver
Playwright
Playwright
for
Java
Playwright
for
Python
Playwright
for
C#
Expose language idiomatic API to
control downloads
TypeScript
Being Dependable
🎭 Playwright Driver
C++
Playwright
Playwright
for
Java
Playwright
for
Python
Playwright
for
C#
Cross-Browser Testing Tool
● 👀 8 teams from multiple companies
● 🐌 Slow feedback loop (months /
years)
Playwright
● 💫 1 team from a single company
● 🐆 Fast feedback loop (days / weeks)
More Like This
● Downloads API
● Screencast API
● Drag & Drop API
● Clipboard API
● Browser-Level cookies
● Browser Contexts
● Per-context HTTP proxy
● ...
Summary: Playwright is Dependable
👌 We Triage Issues in <48 hours
📚 We Fix Issues (>1600 fixed)
✈ We Take Full Responsibility
Act II
Efficient
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
What is “Efficient”?
Efficient = Fast
?
Automation Costs
● Throughput = spend less CPU cycles
● Latency = run tests fast
● Flakiness = reliable runs
Playwright Being Efficient
● Trick 1: Browser Contexts
● Trick 2: Auto-waiting
Trick 1: Browser Contexts
❌ Never Restart a Browser
● Slow instantiation (>100ms)
● Huge memory overhead
✅ Always create Browser Contexts
● Full isolation
● Fast instantiation (~1ms)
● Low overhead Browser Context
Trick 1: Browser Contexts
Context 1
Trick 1: Browser Contexts
Context 1 Context 2
Trick 1: Browser Contexts
Context 1 Context 2
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
for (let i = 0; i < 10; ++i) {
// Fast, simple, configurable!
const context = await browser.newContext()
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.close();
}
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
for (let i = 0; i < 10; ++i) {
// Fast, simple, configurable!
const context = await browser.newContext()
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.close();
}
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
for (let i = 0; i < 10; ++i) {
// Fast, simple, configurable!
const context = await browser.newContext()
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.close();
}
Form Filling: No Autowait
Form Filling: No Autowait
e-mail..
Form Filling: No Autowait
e-mail..
Form Filling: No Autowait
e-mail..
Form Filling: No Autowait
passwd...
Form Filling: No Autowait
passwd...
Form Filling: No Autowait
passwd...
Form Filling: No Autowait
submitting...
Form Filling: No Autowait
submitting...
Form Filling: No Autowait
MISSED
Form Filling: No Autowait
MISSED
Disabled button!
await page.goto('https://form.example.com');
// Shall we wait for fields to be enabled?..
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
// Wait for button to get enabled and click submit
setTimeout(async () => {
await page.click('#submit');
}, 1000);
N
o
n
-
P
l
a
y
w
r
i
g
h
t
P
s
e
u
d
o
-
C
o
d
e
await page.goto('https://form.example.com');
// Shall we wait for fields to be enabled?..
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
// Wait for button to get enabled and click submit
setTimeout(async () => {
await page.click('#submit');
}, 1000);
N
o
n
-
P
l
a
y
w
r
i
g
h
t
P
s
e
u
d
o
-
C
o
d
e
await page.goto('https://form.example.com');
// Shall we wait for fields to be enabled?..
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
// Wait for button to get enabled and click submit
setTimeout(async () => {
await page.click('#submit');
}, 1000);
N
o
n
-
P
l
a
y
w
r
i
g
h
t
P
s
e
u
d
o
-
C
o
d
e
Time Does Not Exist in the Cloud!
Trick 2: Auto-waiting ✨
Auto-Waiting..
Trick 2: Auto-waiting ✨
Successful!
Enabled!
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
// ✨ Playwright auto-waiting by default!
await page.goto('https://form.example.com');
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
await page.click('#submit');
P
l
a
y
w
r
i
g
h
t
// ✨ Playwright auto-waiting by default!
await page.goto('https://form.example.com');
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
await page.click('#submit');
P
l
a
y
w
r
i
g
h
t
// ✨ Playwright auto-waiting by default!
await page.goto('https://form.example.com');
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
await page.click('#submit');
P
l
a
y
w
r
i
g
h
t
// ✨ Playwright auto-waiting by default!
await page.goto('https://form.example.com');
await page.fill('#email', 'aslushnikov@gmail.com');
await page.fill('#password', 'mypassword');
await page.click('#submit');
P
l
a
y
w
r
i
g
h
t
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Trick 2: Auto-waiting ✨
Summary: Playwright is Efficient
● Trick 1: Browser Contexts
● Trick 2: Auto-waiting
Act III
Capable
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
import {webkit, devices} from 'playwright';
const browser = await webkit.launch();
const context = await browser.newContext({
...devices['iPhone 12 Pro'],
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await browser.close();
📱
D
e
v
i
c
e
E
m
u
l
a
t
i
o
n
import {webkit, devices} from 'playwright';
const browser = await webkit.launch();
const context = await browser.newContext({
...devices['iPhone 12 Pro'],
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await browser.close();
📱
D
e
v
i
c
e
E
m
u
l
a
t
i
o
n
import {webkit, devices} from 'playwright';
const browser = await webkit.launch();
const context = await browser.newContext({
...devices['iPhone 12 Pro'],
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await browser.close();
📱
D
e
v
i
c
e
E
m
u
l
a
t
i
o
n
import {chromium, firefox, webkit} from 'playwright';
const browser = await firefox.launch();
const context = await browser.newContext({
geolocation: { longitude: 48.858455, latitude: 2.294474 },
permissions: ['geolocation']
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.setGeolocation({
longitude: 29.97, latitude: 31.13
});
G
e
o
l
o
c
a
t
i
o
n
&
P
e
r
m
i
s
s
i
o
n
s
import {chromium, firefox, webkit} from 'playwright';
const browser = await firefox.launch();
const context = await browser.newContext({
geolocation: { longitude: 48.858455, latitude: 2.294474 },
permissions: ['geolocation']
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.setGeolocation({
longitude: 29.97, latitude: 31.13
});
G
e
o
l
o
c
a
t
i
o
n
&
P
e
r
m
i
s
s
i
o
n
s
import {chromium, firefox, webkit} from 'playwright';
const browser = await firefox.launch();
const context = await browser.newContext({
geolocation: { longitude: 48.858455, latitude: 2.294474 },
permissions: ['geolocation']
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.setGeolocation({
longitude: 29.97, latitude: 31.13
});
G
e
o
l
o
c
a
t
i
o
n
&
P
e
r
m
i
s
s
i
o
n
s
import {chromium, firefox, webkit} from 'playwright';
const browser = await firefox.launch();
const context = await browser.newContext({
geolocation: { longitude: 48.858455, latitude: 2.294474 },
permissions: ['geolocation']
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await context.setGeolocation({
longitude: 29.97, latitude: 31.13
});
G
e
o
l
o
c
a
t
i
o
n
&
P
e
r
m
i
s
s
i
o
n
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
recordVideo: {
dir: 'videos/',
size: { width: 800, height: 600 },
},
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await page.close();
🎥
V
i
d
e
o
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
recordVideo: {
dir: 'videos/',
size: { width: 800, height: 600 },
},
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await page.close();
🎥
V
i
d
e
o
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
recordVideo: {
dir: 'videos/',
size: { width: 800, height: 600 },
},
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await page.close();
🎥
V
i
d
e
o
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await webkit.launch();
const page = await browser.newPage();
page.on('request', r => console.log(r.method(), r.url()));
page.on('websocket', ws => console.log(ws.url()));
await page.goto('https://playwright.dev');
await browser.close();
🌎
N
e
t
w
o
r
k
&
W
e
b
S
o
c
k
e
t
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await webkit.launch();
const page = await browser.newPage();
page.on('request', r => console.log(r.method(), r.url()));
page.on('websocket', ws => console.log(ws.url()));
await page.goto('https://playwright.dev');
await browser.close();
🌎
N
e
t
w
o
r
k
&
W
e
b
S
o
c
k
e
t
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await firefox.launch();
const page = await browser.newPage();
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
await page.goto('https://playwright.dev');
await browser.close();
P
a
g
e
R
e
q
u
e
s
t
I
n
t
e
r
c
e
p
t
i
o
n
import {webkit, chromium, firefox} from 'playwright';
const browser = await firefox.launch();
const context = await browser.newContext();
await context.route('**/*.{png,jpg,jpeg}', route => route.abort());
const page = await page.newPage();
await page.goto('https://playwright.dev');
await browser.close();
C
o
n
t
e
x
t
R
e
q
u
e
s
t
I
n
t
e
r
c
e
p
t
i
o
n
import {webkit, chromium, firefox} from 'playwright';
const browser = await webkit.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
const [ download ] = await Promise.all([
page.waitForEvent('download'),
page.click('button#delayed-download')
]);
console.log(await download.path());
await browser.close();
D
o
w
n
l
o
a
d
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
import {webkit, chromium, firefox} from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://playwright.dev');
await page.click('button'); // CSS selector
await page.click('xpath=//button'); // XPath selector
await page.click('text=Log in'); // Text selector
await page.click(':nth-match(:text("Buy"), 3)'); // N-th match
await page.click('div:right-of(:text("Name"))'); // Layout 😱
await page.click(`xpath=//form >> text=Submit`); // Composite
S
m
a
r
t
S
e
l
e
c
t
o
r
s
// text content
const content = await page.textContent('nav:first-child');
expect(content).toBe('home');
// Attributes
const alt = await page.getAttribute('input', 'alt');
expect(alt).toBe('Text');
// Checkbox state
const checked = await page.isChecked('input');
expect(checked).toBeTruthy();
// Visibility
const visible = await page.isVisible('input');
expect(visible).toBeTruthy();
A
s
s
e
r
t
i
o
n
s
// text content
const content = await page.textContent('nav:first-child');
expect(content).toBe('home');
// Attributes
const alt = await page.getAttribute('input', 'alt');
expect(alt).toBe('Text');
// Checkbox state
const checked = await page.isChecked('input');
expect(checked).toBeTruthy();
// Visibility
const visible = await page.isVisible('input');
expect(visible).toBeTruthy();
A
s
s
e
r
t
i
o
n
s
// text content
const content = await page.textContent('nav:first-child');
expect(content).toBe('home');
// Attributes
const alt = await page.getAttribute('input', 'alt');
expect(alt).toBe('Text');
// Checkbox state
const checked = await page.isChecked('input');
expect(checked).toBeTruthy();
// Visibility
const visible = await page.isVisible('input');
expect(visible).toBeTruthy();
A
s
s
e
r
t
i
o
n
s
// text content
const content = await page.textContent('nav:first-child');
expect(content).toBe('home');
// Attributes
const alt = await page.getAttribute('input', 'alt');
expect(alt).toBe('Text');
// Checkbox state
const checked = await page.isChecked('input');
expect(checked).toBeTruthy();
// Visibility
const visible = await page.isVisible('input');
expect(visible).toBeTruthy();
A
s
s
e
r
t
i
o
n
s
import {chromium} from 'playwright';
const browser = await chromium.launch({
// Can be 'chrome', 'chrome-beta', 'msedge-beta', 'msedge-dev'
channel: 'msedge',
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await browser.close();
M
i
c
r
o
s
o
f
t
E
d
g
e
import {chromium} from 'playwright';
const browser = await chromium.launch({
// Can be 'chrome', 'chrome-beta', 'msedge-beta', 'msedge-dev'
channel: 'msedge',
});
const page = await context.newPage();
await page.goto('https://playwright.dev');
await browser.close();
M
i
c
r
o
s
o
f
t
E
d
g
e
More Features
● Built-in Shadow DOM piercing
● Idiomatic frames API
● Custom Selector Engines
● TimeZone / Locale / Color Scheme emulation
● Per-Context HTTP Proxy
● Workers / Service Workers
● Console sniffing
● Dialogs
● File Uploads
● Element Handles
● ...
● ubuntu-18.04 (chromium)
● ubuntu-18.04 (firefox)
● ubuntu-18.04 (webkit)
● ubuntu-20.04 (chromium)
● ubuntu-20.04 (firefox)
● ubuntu-20.04 (webkit)
● macos-10.14 (chromium)
● macos-10.14 (firefox)
● macos-10.14 (webkit)
● macos-10.15 (chromium)
● macos-10.15 (firefox)
● macos-10.15 (webkit)
● macos-11.0 (chromium)
● macos-11.0 (firefox)
● macos-11.0 (webkit)
● macos-11.0 arm64 (chromium)
● macos-11.0 arm64 (firefox)
● macos-11.0 arm64 (webkit)
Rigorous Testing ● Windows (chromium)
● Windows (firefox)
● Windows (webkit)
● test-package-installations (^10.17.0)
● test-package-installations (^12.0.0)
● test-package-installations (^14.1.0)
● Headful Linux (chromium)
● Headful Linux (firefox)
● Headful Linux (webkit)
● Transport (driver)
● Transport (service)
● Video Linux (chromium)
● Video Linux (firefox)
● Video Linux (webkit)
● Android Emulator (shard 1)
● Android Emulator (shard 2)
● Chrome Stable (Linux)
● Chrome Stable (Win)
● Chrome Stable (Mac)
● Edge Stable (Win)
● Electron Linux
Act IV
Ubiquitous
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
WebKit Availability
Headed
Headless
❌
❌ ❌ ❌
✅
WebKit Availability
Headed
Headless
❌
❌ ❌ ❌
✅
🎭 Playwright WebKit Availability
Headed
Headless
✅
✅
✅
✅
✅
✅
● All Browsers
○ Chrome, Safari, Firefox
🎭 Playwright is Ubiquitous
● All Browsers
○ Chrome, Safari, Firefox
● All OS
○ Linux, Mac, Windows
🎭 Playwright is Ubiquitous
🎭 Playwright is Ubiquitous
● All Browsers
○ Chrome, Safari, Firefox
● All OS
○ Linux, Mac, Windows
● All Popular Languages
○ JavaScript / TypeScript
○ Java
○ Python
○ C# (alpha)
CI/CD, Services, Clients
● Any CI/CD
○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI,
AWS, GCP, …
● Any CI/CD
○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI,
AWS, GCP, …
● Docker Containers
○ docker pull mcr.microsoft.com/playwright
○ docker pull mcr.microsoft.com/playwright-java
CI/CD, Services, Clients
CI/CD, Services, Clients
● Any CI/CD
○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI,
AWS, GCP, …
● Docker Containers
○ docker pull mcr.microsoft.com/playwright
○ docker pull mcr.microsoft.com/playwright-java
● Third-Party integrations
○ applitools.com
○ saucelabs.com
○ Checklyhq.com
○ www.testim.io
○ github.com/aerokube/moon
○ seleniumbox.com
CI/CD, Services, Clients
● Any CI/CD
○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI,
AWS, GCP, …
● Docker Containers
○ docker pull mcr.microsoft.com/playwright
○ docker pull mcr.microsoft.com/playwright-java
● Third-Party integrations
○ applitools.com
○ saucelabs.com
○ Checklyhq.com
○ www.testim.io
○ github.com/aerokube/moon
○ seleniumbox.com
Playwright ❤ WebDriver
Chrome
DevTools
Protocol
Historical Context
Chrome
DevTools
Protocol
ChromeDriver
2013
Historical Context
Chrome
DevTools
Protocol
Playwright
2013
Historical Context
ChromeDriver
WebDriver Integration
WebDriver-Grid
WebDriver-Grid
WebDriver-Grid
WebDriver Integration
Chrome
DevTools
Protocol
WebDriver-Grid
WebDriver-Grid
WebDriver-Grid
WebDriver Integration
chromium.connectOverCDP()
Chrome
DevTools
Protocol
🎭 Playwright
WebDriver-Grid
WebDriver-Grid
WebDriver-Grid
Act V
Delightful Authoring & Debugging
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
🍿 Demo Time 🍿
Authoring & Debugging
- Code Generation
- npx playwright codegen
- Built-In Inspector
- PWDEBUG=1 node snippet.js
- Devtools Console integration
- playwright.$
- Simple Node.js Debugging
- Logging
- DEBUG=pw:api node snippet.js
- Storage State re-use
Act VI
Lively
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
Lively 🐈
● Active Development
○ 2500+ commits in the last year
○ 1600+ closed issues
● Growing Team
○ We’re hiring!
● Expanding Horizons
const { _electron } = require('playwright');
(async () => {
const electronApp = await _electron.launch({ args: ['main.js'] });
const window = await electronApp.firstWindow();
console.log(await window.title());
await window.screenshot({ path: 'intro.png' });
await window.click('text=Click me');
await electronApp.close();
})();
🧪
E
x
p
e
r
i
m
e
n
t
a
l
:
E
l
e
c
t
r
o
n
.
j
s
const { _android } = require('playwright');
(async () => {
const [device] = await _android.devices();
await device.shell('am force-stop com.android.chrome');
const context = await device.launchBrowser();
const page = await context.newPage();
await page.goto('https://playwright.dev/');
await page.screenshot({ path: 'page.png' });
await context.close();
await device.close();
})();
🧪
E
x
p
e
r
i
m
e
n
t
a
l
:
A
n
d
r
o
i
d
Conclusion?
Dependable
Efficient
Capable
Ubiquitous
Delightful
Lively
Web Automation
can be
Fun
🎭 playwright.dev
@aslushnikov
aslushnikov@gmail.com
Andrey Lushnikov
@playwrightweb
https:/
/aka.ms/playwright-slack
microsoft/playwright
Playwright
@aslushnikov
aslushnikov@gmail.com
Andrey Lushnikov
@playwrightweb
https:/
/aka.ms/playwright-slack
microsoft/playwright
Q
u
e
s
t
i
o
n
s
?
Playwright
How-To: Authentication Re-use
Context 1
1. npx playwright codegen --save-storage=auth.json
How-To: Authentication Re-use
Context 1
Storage State
2. Extract & Save Storage State
1. npx playwright codegen --save-storage=auth.json
How-To: Authentication Re-use
Context 1 Context N
Storage State
2. Extract & Save Storage State
3. Re-Use Storage State
1. npx playwright codegen --save-storage=auth.json
🎁
Authentication Re-Use
Authentication is Slow
Authentication is Slow
Authentication is Slow
Authentication is Slow Too Slow!
🍿 Demo Time 🍿
const context = await browser.newContext({
storageState: require('auth.json'),
});
A
u
t
h
e
n
t
i
c
a
t
i
o
n
R
e
-
U
s
e
const context = await browser.newContext({
storageState: require('auth.json'),
});
A
u
t
h
e
n
t
i
c
a
t
i
o
n
R
e
-
U
s
e

More Related Content

What's hot

Cypress-vs-Playwright-Rematch-Applitools.pdf
Cypress-vs-Playwright-Rematch-Applitools.pdfCypress-vs-Playwright-Rematch-Applitools.pdf
Cypress-vs-Playwright-Rematch-Applitools.pdfApplitools
 
Test Automation and Selenium
Test Automation and SeleniumTest Automation and Selenium
Test Automation and SeleniumKarapet Sarkisyan
 
Jmeter Performance Testing
Jmeter Performance TestingJmeter Performance Testing
Jmeter Performance TestingAtul Pant
 
Hybrid automation framework
Hybrid automation frameworkHybrid automation framework
Hybrid automation frameworkdoai tran
 
A Top Down Approach to End-to-End Testing
A Top Down Approach to End-to-End TestingA Top Down Approach to End-to-End Testing
A Top Down Approach to End-to-End TestingSmartBear
 
No drama here - E2E-testing django with playwright
No drama here - E2E-testing django with playwrightNo drama here - E2E-testing django with playwright
No drama here - E2E-testing django with playwrightMastacheata1
 
Introduction to jest
Introduction to jestIntroduction to jest
Introduction to jestpksjce
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework IntroductionPekka Klärck
 
Test automation
Test automationTest automation
Test automationXavier Yin
 
Selenium test automation
Selenium test automationSelenium test automation
Selenium test automationSrikanth Vuriti
 
RESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsRESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsQASymphony
 

What's hot (20)

Apache jMeter
Apache jMeterApache jMeter
Apache jMeter
 
Cypress-vs-Playwright-Rematch-Applitools.pdf
Cypress-vs-Playwright-Rematch-Applitools.pdfCypress-vs-Playwright-Rematch-Applitools.pdf
Cypress-vs-Playwright-Rematch-Applitools.pdf
 
Browser_Stack_Intro
Browser_Stack_IntroBrowser_Stack_Intro
Browser_Stack_Intro
 
Cypress Automation
Cypress  AutomationCypress  Automation
Cypress Automation
 
Test Automation and Selenium
Test Automation and SeleniumTest Automation and Selenium
Test Automation and Selenium
 
Automated UI Testing
Automated UI TestingAutomated UI Testing
Automated UI Testing
 
Jmeter Performance Testing
Jmeter Performance TestingJmeter Performance Testing
Jmeter Performance Testing
 
Introduction to Robot Framework
Introduction to Robot FrameworkIntroduction to Robot Framework
Introduction to Robot Framework
 
Hybrid automation framework
Hybrid automation frameworkHybrid automation framework
Hybrid automation framework
 
A Top Down Approach to End-to-End Testing
A Top Down Approach to End-to-End TestingA Top Down Approach to End-to-End Testing
A Top Down Approach to End-to-End Testing
 
TestNG with selenium
TestNG with seleniumTestNG with selenium
TestNG with selenium
 
Selenium ppt
Selenium pptSelenium ppt
Selenium ppt
 
No drama here - E2E-testing django with playwright
No drama here - E2E-testing django with playwrightNo drama here - E2E-testing django with playwright
No drama here - E2E-testing django with playwright
 
Introduction to jest
Introduction to jestIntroduction to jest
Introduction to jest
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework Introduction
 
Test automation
Test automationTest automation
Test automation
 
BDD with Cucumber
BDD with CucumberBDD with Cucumber
BDD with Cucumber
 
Automation testing
Automation testingAutomation testing
Automation testing
 
Selenium test automation
Selenium test automationSelenium test automation
Selenium test automation
 
RESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and JenkinsRESTful API Testing using Postman, Newman, and Jenkins
RESTful API Testing using Postman, Newman, and Jenkins
 

Similar to Playwright: A New Test Automation Framework for the Modern Web

Build and Deploy a Python Web App to Amazon in 30 Mins
Build and Deploy a Python Web App to Amazon in 30 MinsBuild and Deploy a Python Web App to Amazon in 30 Mins
Build and Deploy a Python Web App to Amazon in 30 MinsJeff Hull
 
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...Serdar Basegmez
 
You Can Work on the Web Patform! (GOSIM 2023)
You Can Work on the Web Patform! (GOSIM 2023)You Can Work on the Web Patform! (GOSIM 2023)
You Can Work on the Web Patform! (GOSIM 2023)Igalia
 
playwrightmeetup-14jan2021-210114173639.pdf
playwrightmeetup-14jan2021-210114173639.pdfplaywrightmeetup-14jan2021-210114173639.pdf
playwrightmeetup-14jan2021-210114173639.pdfManjuBiradar6
 
AWS Community Day 2022 Angelo Mandato_First Lambda function using VSCode - C...
AWS Community Day 2022  Angelo Mandato_First Lambda function using VSCode - C...AWS Community Day 2022  Angelo Mandato_First Lambda function using VSCode - C...
AWS Community Day 2022 Angelo Mandato_First Lambda function using VSCode - C...AWS Chicago
 
Hacking the browser with puppeteer sharp .NET conf AR 2018
Hacking the browser with puppeteer sharp .NET conf AR 2018Hacking the browser with puppeteer sharp .NET conf AR 2018
Hacking the browser with puppeteer sharp .NET conf AR 2018Darío Kondratiuk
 
Scraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHPScraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHPPaul Redmond
 
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...Patrick Meenan
 
Behat Workshop at WeLovePHP
Behat Workshop at WeLovePHPBehat Workshop at WeLovePHP
Behat Workshop at WeLovePHPMarcos Quesada
 
Building Kick Ass Video Games for the Cloud
Building Kick Ass Video Games for the CloudBuilding Kick Ass Video Games for the Cloud
Building Kick Ass Video Games for the CloudChris Schalk
 
Debugging Web Apps on Real Mobile Devices
Debugging Web Apps on Real Mobile DevicesDebugging Web Apps on Real Mobile Devices
Debugging Web Apps on Real Mobile DevicesDale Lane
 
Yet Another Continuous Integration Story
Yet Another Continuous Integration StoryYet Another Continuous Integration Story
Yet Another Continuous Integration StoryAnton Serdyuk
 
iPhone Development For Experienced Web Developers
iPhone Development For Experienced Web DevelopersiPhone Development For Experienced Web Developers
iPhone Development For Experienced Web Developerslisab517
 
Creating a Responsive Website From Scratch
Creating a Responsive Website From ScratchCreating a Responsive Website From Scratch
Creating a Responsive Website From ScratchCorky Brown
 
Introducing chrome apps (ogura)
Introducing chrome apps (ogura)Introducing chrome apps (ogura)
Introducing chrome apps (ogura)Kazuhiro Ogura
 
08 - Data Fetch (Monica).pptx
08 - Data Fetch (Monica).pptx08 - Data Fetch (Monica).pptx
08 - Data Fetch (Monica).pptxAliDaanish1
 
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJSFestUA
 
Modern Web 2016: Using Golang to build a smart IM Bot
Modern Web 2016: Using Golang to build a smart IM Bot Modern Web 2016: Using Golang to build a smart IM Bot
Modern Web 2016: Using Golang to build a smart IM Bot Evan Lin
 

Similar to Playwright: A New Test Automation Framework for the Modern Web (20)

Build and Deploy a Python Web App to Amazon in 30 Mins
Build and Deploy a Python Web App to Amazon in 30 MinsBuild and Deploy a Python Web App to Amazon in 30 Mins
Build and Deploy a Python Web App to Amazon in 30 Mins
 
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...
Engage 2022: The Superpower of Integrating External APIs for Notes and Domino...
 
You Can Work on the Web Patform! (GOSIM 2023)
You Can Work on the Web Patform! (GOSIM 2023)You Can Work on the Web Patform! (GOSIM 2023)
You Can Work on the Web Patform! (GOSIM 2023)
 
playwrightmeetup-14jan2021-210114173639.pdf
playwrightmeetup-14jan2021-210114173639.pdfplaywrightmeetup-14jan2021-210114173639.pdf
playwrightmeetup-14jan2021-210114173639.pdf
 
AWS Community Day 2022 Angelo Mandato_First Lambda function using VSCode - C...
AWS Community Day 2022  Angelo Mandato_First Lambda function using VSCode - C...AWS Community Day 2022  Angelo Mandato_First Lambda function using VSCode - C...
AWS Community Day 2022 Angelo Mandato_First Lambda function using VSCode - C...
 
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
 
Hacking the browser with puppeteer sharp .NET conf AR 2018
Hacking the browser with puppeteer sharp .NET conf AR 2018Hacking the browser with puppeteer sharp .NET conf AR 2018
Hacking the browser with puppeteer sharp .NET conf AR 2018
 
Scraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHPScraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHP
 
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
 
Behat Workshop at WeLovePHP
Behat Workshop at WeLovePHPBehat Workshop at WeLovePHP
Behat Workshop at WeLovePHP
 
Building Kick Ass Video Games for the Cloud
Building Kick Ass Video Games for the CloudBuilding Kick Ass Video Games for the Cloud
Building Kick Ass Video Games for the Cloud
 
Debugging Web Apps on Real Mobile Devices
Debugging Web Apps on Real Mobile DevicesDebugging Web Apps on Real Mobile Devices
Debugging Web Apps on Real Mobile Devices
 
Yet Another Continuous Integration Story
Yet Another Continuous Integration StoryYet Another Continuous Integration Story
Yet Another Continuous Integration Story
 
iPhone Development For Experienced Web Developers
iPhone Development For Experienced Web DevelopersiPhone Development For Experienced Web Developers
iPhone Development For Experienced Web Developers
 
Creating a Responsive Website From Scratch
Creating a Responsive Website From ScratchCreating a Responsive Website From Scratch
Creating a Responsive Website From Scratch
 
Introducing chrome apps (ogura)
Introducing chrome apps (ogura)Introducing chrome apps (ogura)
Introducing chrome apps (ogura)
 
08 - Data Fetch (Monica).pptx
08 - Data Fetch (Monica).pptx08 - Data Fetch (Monica).pptx
08 - Data Fetch (Monica).pptx
 
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by DefaultJS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
JS Fest 2019. Minko Gechev. Building Fast Angular Applications by Default
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Modern Web 2016: Using Golang to build a smart IM Bot
Modern Web 2016: Using Golang to build a smart IM Bot Modern Web 2016: Using Golang to build a smart IM Bot
Modern Web 2016: Using Golang to build a smart IM Bot
 

More from Applitools

Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonApplitools
 
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...Applitools
 
Visual AI for eCommerce: Improving Conversions with a Flawless UI
Visual AI for eCommerce: Improving Conversions with a Flawless UIVisual AI for eCommerce: Improving Conversions with a Flawless UI
Visual AI for eCommerce: Improving Conversions with a Flawless UIApplitools
 
A Test Automation Platform Designed for the Future
A Test Automation Platform Designed for the FutureA Test Automation Platform Designed for the Future
A Test Automation Platform Designed for the FutureApplitools
 
Add AI to Your SDLC, presented by Applitools and Curiosity
Add AI to Your SDLC, presented by Applitools and CuriosityAdd AI to Your SDLC, presented by Applitools and Curiosity
Add AI to Your SDLC, presented by Applitools and CuriosityApplitools
 
The Future of AI-Based Test Automation
The Future of AI-Based Test AutomationThe Future of AI-Based Test Automation
The Future of AI-Based Test AutomationApplitools
 
Test Automation at Scale: Lessons from Top-Performing Distributed Teams
Test Automation at Scale: Lessons from Top-Performing Distributed TeamsTest Automation at Scale: Lessons from Top-Performing Distributed Teams
Test Automation at Scale: Lessons from Top-Performing Distributed TeamsApplitools
 
Can AI Autogenerate and Run Automated Tests?
Can AI Autogenerate and Run Automated Tests?Can AI Autogenerate and Run Automated Tests?
Can AI Autogenerate and Run Automated Tests?Applitools
 
Triple Assurance: AI-Powered Test Automation in UI Design and Functionality
Triple Assurance: AI-Powered Test Automation in UI Design and FunctionalityTriple Assurance: AI-Powered Test Automation in UI Design and Functionality
Triple Assurance: AI-Powered Test Automation in UI Design and FunctionalityApplitools
 
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing Teams
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing TeamsNavigating the Challenges of Testing at Scale: Lessons from Top-Performing Teams
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing TeamsApplitools
 
Introducing the Applitools Self Healing Execution Cloud.pdf
Introducing the Applitools Self Healing Execution Cloud.pdfIntroducing the Applitools Self Healing Execution Cloud.pdf
Introducing the Applitools Self Healing Execution Cloud.pdfApplitools
 
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...Applitools
 
Collaborating From Design To Experience: Introducing Centra
Collaborating From Design To Experience: Introducing CentraCollaborating From Design To Experience: Introducing Centra
Collaborating From Design To Experience: Introducing CentraApplitools
 
What the QA Position Will Look Like in the Future
What the QA Position Will Look Like in the FutureWhat the QA Position Will Look Like in the Future
What the QA Position Will Look Like in the FutureApplitools
 
Getting Started with Visual Testing
Getting Started with Visual TestingGetting Started with Visual Testing
Getting Started with Visual TestingApplitools
 
Workshop: Head-to-Head Web Testing: Part 1 with Cypress
Workshop: Head-to-Head Web Testing: Part 1 with CypressWorkshop: Head-to-Head Web Testing: Part 1 with Cypress
Workshop: Head-to-Head Web Testing: Part 1 with CypressApplitools
 
From Washing Cars To Automating Test Applications
From Washing Cars To Automating Test ApplicationsFrom Washing Cars To Automating Test Applications
From Washing Cars To Automating Test ApplicationsApplitools
 
A Holistic Approach to Testing in Continuous Delivery
A Holistic Approach to Testing in Continuous DeliveryA Holistic Approach to Testing in Continuous Delivery
A Holistic Approach to Testing in Continuous DeliveryApplitools
 
AI-Powered-Cross-Browser Testing
AI-Powered-Cross-Browser TestingAI-Powered-Cross-Browser Testing
AI-Powered-Cross-Browser TestingApplitools
 
Workshop: An Introduction to API Automation with Javascript
Workshop: An Introduction to API Automation with JavascriptWorkshop: An Introduction to API Automation with Javascript
Workshop: An Introduction to API Automation with JavascriptApplitools
 

More from Applitools (20)

Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
 
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...
Streamlining Your Tech Stack: A Blueprint for Enhanced Efficiency and Coverag...
 
Visual AI for eCommerce: Improving Conversions with a Flawless UI
Visual AI for eCommerce: Improving Conversions with a Flawless UIVisual AI for eCommerce: Improving Conversions with a Flawless UI
Visual AI for eCommerce: Improving Conversions with a Flawless UI
 
A Test Automation Platform Designed for the Future
A Test Automation Platform Designed for the FutureA Test Automation Platform Designed for the Future
A Test Automation Platform Designed for the Future
 
Add AI to Your SDLC, presented by Applitools and Curiosity
Add AI to Your SDLC, presented by Applitools and CuriosityAdd AI to Your SDLC, presented by Applitools and Curiosity
Add AI to Your SDLC, presented by Applitools and Curiosity
 
The Future of AI-Based Test Automation
The Future of AI-Based Test AutomationThe Future of AI-Based Test Automation
The Future of AI-Based Test Automation
 
Test Automation at Scale: Lessons from Top-Performing Distributed Teams
Test Automation at Scale: Lessons from Top-Performing Distributed TeamsTest Automation at Scale: Lessons from Top-Performing Distributed Teams
Test Automation at Scale: Lessons from Top-Performing Distributed Teams
 
Can AI Autogenerate and Run Automated Tests?
Can AI Autogenerate and Run Automated Tests?Can AI Autogenerate and Run Automated Tests?
Can AI Autogenerate and Run Automated Tests?
 
Triple Assurance: AI-Powered Test Automation in UI Design and Functionality
Triple Assurance: AI-Powered Test Automation in UI Design and FunctionalityTriple Assurance: AI-Powered Test Automation in UI Design and Functionality
Triple Assurance: AI-Powered Test Automation in UI Design and Functionality
 
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing Teams
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing TeamsNavigating the Challenges of Testing at Scale: Lessons from Top-Performing Teams
Navigating the Challenges of Testing at Scale: Lessons from Top-Performing Teams
 
Introducing the Applitools Self Healing Execution Cloud.pdf
Introducing the Applitools Self Healing Execution Cloud.pdfIntroducing the Applitools Self Healing Execution Cloud.pdf
Introducing the Applitools Self Healing Execution Cloud.pdf
 
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...
Unlocking the Power of ChatGPT and AI in Testing - NextSteps, presented by Ap...
 
Collaborating From Design To Experience: Introducing Centra
Collaborating From Design To Experience: Introducing CentraCollaborating From Design To Experience: Introducing Centra
Collaborating From Design To Experience: Introducing Centra
 
What the QA Position Will Look Like in the Future
What the QA Position Will Look Like in the FutureWhat the QA Position Will Look Like in the Future
What the QA Position Will Look Like in the Future
 
Getting Started with Visual Testing
Getting Started with Visual TestingGetting Started with Visual Testing
Getting Started with Visual Testing
 
Workshop: Head-to-Head Web Testing: Part 1 with Cypress
Workshop: Head-to-Head Web Testing: Part 1 with CypressWorkshop: Head-to-Head Web Testing: Part 1 with Cypress
Workshop: Head-to-Head Web Testing: Part 1 with Cypress
 
From Washing Cars To Automating Test Applications
From Washing Cars To Automating Test ApplicationsFrom Washing Cars To Automating Test Applications
From Washing Cars To Automating Test Applications
 
A Holistic Approach to Testing in Continuous Delivery
A Holistic Approach to Testing in Continuous DeliveryA Holistic Approach to Testing in Continuous Delivery
A Holistic Approach to Testing in Continuous Delivery
 
AI-Powered-Cross-Browser Testing
AI-Powered-Cross-Browser TestingAI-Powered-Cross-Browser Testing
AI-Powered-Cross-Browser Testing
 
Workshop: An Introduction to API Automation with Javascript
Workshop: An Introduction to API Automation with JavascriptWorkshop: An Introduction to API Automation with Javascript
Workshop: An Introduction to API Automation with Javascript
 

Recently uploaded

办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 

Recently uploaded (20)

2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 

Playwright: A New Test Automation Framework for the Modern Web

  • 3. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools Who We Are
  • 4. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools Who We Are
  • 5. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools Who We Are
  • 6. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools ● 2011-... Chrome DevTools Protocol Who We Are
  • 7. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools ● 2011-... Chrome DevTools Protocol ● 2015-2016 Node.js Debugger Who We Are
  • 8. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools ● 2011-... Chrome DevTools Protocol ● 2015-2016 Node.js Debugger ● 2017-2019 Puppeteer Who We Are
  • 9. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools ● 2011-... Chrome DevTools Protocol ● 2015-2016 Node.js Debugger ● 2017-2019 Puppeteer Who We Are
  • 10. ● 2009-2019 WebKit Web Inspector Chrome Developer Tools ● 2011-... Chrome DevTools Protocol ● 2015-2016 Node.js Debugger ● 2017-2019 Puppeteer ● 2019-... Playwright Who We Are
  • 13. import {chromium, firefox, webkit} from 'playwright'; for (const browserType of [chromium, firefox, webkit]) { const browser = await browserType.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.screenshot({path: `image-${browserType.name()}.png`}); await browser.close(); }
  • 14. import {chromium, firefox, webkit} from 'playwright'; for (const browserType of [chromium, firefox, webkit]) { const browser = await browserType.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.screenshot({path: `image-${browserType.name()}.png`}); await browser.close(); } J a v a S c r i p t
  • 15. from playwright.sync_api import sync_playwright with sync_playwright() as p: for browser_type in [p.chromium, p.firefox, p.webkit]: browser = browser_type.launch() page = browser.new_page() page.goto("https://playwright.dev") page.screenshot(path="image-" + browser_type.name + ".png") browser.close() P y t h o n
  • 16. public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { List<BrowserType> browserTypes = Arrays.asList( playwright.chromium(), playwright.webkit(), playwright.firefox() ); for (BrowserType browserType : browserTypes) { try (Browser browser = browserType.launch()) { Page page = browser.newPage(); page.navigate("http://playwright.dev"); page.screenshot(new Page.ScreenshotOptions() .setPath(Paths.get("image-" + browserType.name() + ".png"))); } } } } J a v a
  • 18. Playwright: ✅ dependable ✅ efficient ✅ capable ✅ ubiquitous ✅ delightful ✅ lively
  • 20. Dependable 👌 We Triage Issues in <48 hours 📚 We Fix Issues (>1600 fixed) ✈ We Take Full Responsibility github.com/microsoft/playwright
  • 23. Level 1: Browser Engineering C++
  • 24. - Chromium Development - Improving Chrome DevTools Protocol - Google Chrome, Microsoft Edge, Opera, etc Level 1: Browser Engineering C++
  • 25. - Chromium Development - Improving Chrome DevTools Protocol - Google Chrome, Microsoft Edge, Opera, etc - WebKit Development - Improving Web Inspector Protocol - Safari, Mobile Safari, Epiphany, etc Level 1: Browser Engineering C++
  • 26. - Chromium Development - Improving Chrome DevTools Protocol - Google Chrome, Microsoft Edge, Opera, etc - WebKit Development - Improving Web Inspector Protocol - Safari, Mobile Safari, Epiphany, etc - Firefox Development - Improving “Juggler” Protocol - Mozilla Firefox Level 1: Browser Engineering C++
  • 27. - Chromium Development - Improving Chrome DevTools Protocol - Google Chrome, Microsoft Edge, Opera, etc - WebKit Development - Improving Web Inspector Protocol - Safari, Mobile Safari, Epiphany, etc - Firefox Development - Improving “Juggler” Protocol - Mozilla Firefox Level 1: Browser Engineering C++
  • 28. Level 2: Playwright Driver Level 1: Browser Engineering C++
  • 29. TypeScript - Single web automation protocol - Unify all remote debugging protocols - Expose “Downloads API” in driver Level 2: Playwright Driver 🎭 Playwright Driver Level 1: Browser Engineering C++
  • 30. TypeScript Level 3: Language Bindings 🎭 Playwright Driver Level 1: Browser Engineering C++ Level 2: Playwright Driver
  • 31. TypeScript Level 3: Language Bindings 🎭 Playwright Driver Level 1: Browser Engineering C++ Level 2: Playwright Driver Playwright Playwright for Java Playwright for Python Playwright for C# Expose language idiomatic API to control downloads
  • 32. TypeScript Level 3: Language Bindings 🎭 Playwright Driver Level 1: Browser Engineering C++ Level 2: Playwright Driver Playwright Playwright for Java Playwright for Python Playwright for C# Expose language idiomatic API to control downloads
  • 33. TypeScript Level 3: Language Bindings 🎭 Playwright Driver Level 1: Browser Engineering C++ Level 2: Playwright Driver Playwright Playwright for Java Playwright for Python Playwright for C# Expose language idiomatic API to control downloads
  • 34. TypeScript Being Dependable 🎭 Playwright Driver C++ Playwright Playwright for Java Playwright for Python Playwright for C# Cross-Browser Testing Tool ● 👀 8 teams from multiple companies ● 🐌 Slow feedback loop (months / years) Playwright ● 💫 1 team from a single company ● 🐆 Fast feedback loop (days / weeks)
  • 35. More Like This ● Downloads API ● Screencast API ● Drag & Drop API ● Clipboard API ● Browser-Level cookies ● Browser Contexts ● Per-context HTTP proxy ● ...
  • 36. Summary: Playwright is Dependable 👌 We Triage Issues in <48 hours 📚 We Fix Issues (>1600 fixed) ✈ We Take Full Responsibility
  • 39. Automation Costs ● Throughput = spend less CPU cycles ● Latency = run tests fast ● Flakiness = reliable runs
  • 40. Playwright Being Efficient ● Trick 1: Browser Contexts ● Trick 2: Auto-waiting
  • 41. Trick 1: Browser Contexts ❌ Never Restart a Browser ● Slow instantiation (>100ms) ● Huge memory overhead ✅ Always create Browser Contexts ● Full isolation ● Fast instantiation (~1ms) ● Low overhead Browser Context
  • 42. Trick 1: Browser Contexts Context 1
  • 43. Trick 1: Browser Contexts Context 1 Context 2
  • 44. Trick 1: Browser Contexts Context 1 Context 2
  • 45. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); for (let i = 0; i < 10; ++i) { // Fast, simple, configurable! const context = await browser.newContext() const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.close(); }
  • 46. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); for (let i = 0; i < 10; ++i) { // Fast, simple, configurable! const context = await browser.newContext() const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.close(); }
  • 47. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); for (let i = 0; i < 10; ++i) { // Fast, simple, configurable! const context = await browser.newContext() const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.close(); }
  • 48. Form Filling: No Autowait
  • 49. Form Filling: No Autowait e-mail..
  • 50. Form Filling: No Autowait e-mail..
  • 51. Form Filling: No Autowait e-mail..
  • 52. Form Filling: No Autowait passwd...
  • 53. Form Filling: No Autowait passwd...
  • 54. Form Filling: No Autowait passwd...
  • 55. Form Filling: No Autowait submitting...
  • 56. Form Filling: No Autowait submitting...
  • 57. Form Filling: No Autowait MISSED
  • 58. Form Filling: No Autowait MISSED Disabled button!
  • 59. await page.goto('https://form.example.com'); // Shall we wait for fields to be enabled?.. await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); // Wait for button to get enabled and click submit setTimeout(async () => { await page.click('#submit'); }, 1000); N o n - P l a y w r i g h t P s e u d o - C o d e
  • 60. await page.goto('https://form.example.com'); // Shall we wait for fields to be enabled?.. await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); // Wait for button to get enabled and click submit setTimeout(async () => { await page.click('#submit'); }, 1000); N o n - P l a y w r i g h t P s e u d o - C o d e
  • 61. await page.goto('https://form.example.com'); // Shall we wait for fields to be enabled?.. await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); // Wait for button to get enabled and click submit setTimeout(async () => { await page.click('#submit'); }, 1000); N o n - P l a y w r i g h t P s e u d o - C o d e Time Does Not Exist in the Cloud!
  • 62. Trick 2: Auto-waiting ✨ Auto-Waiting..
  • 63. Trick 2: Auto-waiting ✨ Successful! Enabled!
  • 66. // ✨ Playwright auto-waiting by default! await page.goto('https://form.example.com'); await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); await page.click('#submit'); P l a y w r i g h t
  • 67. // ✨ Playwright auto-waiting by default! await page.goto('https://form.example.com'); await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); await page.click('#submit'); P l a y w r i g h t
  • 68. // ✨ Playwright auto-waiting by default! await page.goto('https://form.example.com'); await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); await page.click('#submit'); P l a y w r i g h t
  • 69. // ✨ Playwright auto-waiting by default! await page.goto('https://form.example.com'); await page.fill('#email', 'aslushnikov@gmail.com'); await page.fill('#password', 'mypassword'); await page.click('#submit'); P l a y w r i g h t
  • 77. Summary: Playwright is Efficient ● Trick 1: Browser Contexts ● Trick 2: Auto-waiting
  • 79. import {webkit, devices} from 'playwright'; const browser = await webkit.launch(); const context = await browser.newContext({ ...devices['iPhone 12 Pro'], }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await browser.close(); 📱 D e v i c e E m u l a t i o n
  • 80. import {webkit, devices} from 'playwright'; const browser = await webkit.launch(); const context = await browser.newContext({ ...devices['iPhone 12 Pro'], }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await browser.close(); 📱 D e v i c e E m u l a t i o n
  • 81. import {webkit, devices} from 'playwright'; const browser = await webkit.launch(); const context = await browser.newContext({ ...devices['iPhone 12 Pro'], }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await browser.close(); 📱 D e v i c e E m u l a t i o n
  • 82. import {chromium, firefox, webkit} from 'playwright'; const browser = await firefox.launch(); const context = await browser.newContext({ geolocation: { longitude: 48.858455, latitude: 2.294474 }, permissions: ['geolocation'] }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.setGeolocation({ longitude: 29.97, latitude: 31.13 }); G e o l o c a t i o n & P e r m i s s i o n s
  • 83. import {chromium, firefox, webkit} from 'playwright'; const browser = await firefox.launch(); const context = await browser.newContext({ geolocation: { longitude: 48.858455, latitude: 2.294474 }, permissions: ['geolocation'] }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.setGeolocation({ longitude: 29.97, latitude: 31.13 }); G e o l o c a t i o n & P e r m i s s i o n s
  • 84. import {chromium, firefox, webkit} from 'playwright'; const browser = await firefox.launch(); const context = await browser.newContext({ geolocation: { longitude: 48.858455, latitude: 2.294474 }, permissions: ['geolocation'] }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.setGeolocation({ longitude: 29.97, latitude: 31.13 }); G e o l o c a t i o n & P e r m i s s i o n s
  • 85. import {chromium, firefox, webkit} from 'playwright'; const browser = await firefox.launch(); const context = await browser.newContext({ geolocation: { longitude: 48.858455, latitude: 2.294474 }, permissions: ['geolocation'] }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.setGeolocation({ longitude: 29.97, latitude: 31.13 }); G e o l o c a t i o n & P e r m i s s i o n s
  • 86. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const context = await browser.newContext({ recordVideo: { dir: 'videos/', size: { width: 800, height: 600 }, }, }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await page.close(); 🎥 V i d e o s
  • 87. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const context = await browser.newContext({ recordVideo: { dir: 'videos/', size: { width: 800, height: 600 }, }, }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await page.close(); 🎥 V i d e o s
  • 88. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const context = await browser.newContext({ recordVideo: { dir: 'videos/', size: { width: 800, height: 600 }, }, }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await page.close(); 🎥 V i d e o s
  • 89. import {webkit, chromium, firefox} from 'playwright'; const browser = await webkit.launch(); const page = await browser.newPage(); page.on('request', r => console.log(r.method(), r.url())); page.on('websocket', ws => console.log(ws.url())); await page.goto('https://playwright.dev'); await browser.close(); 🌎 N e t w o r k & W e b S o c k e t s
  • 90. import {webkit, chromium, firefox} from 'playwright'; const browser = await webkit.launch(); const page = await browser.newPage(); page.on('request', r => console.log(r.method(), r.url())); page.on('websocket', ws => console.log(ws.url())); await page.goto('https://playwright.dev'); await browser.close(); 🌎 N e t w o r k & W e b S o c k e t s
  • 91. import {webkit, chromium, firefox} from 'playwright'; const browser = await firefox.launch(); const page = await browser.newPage(); await page.route('**/*.{png,jpg,jpeg}', route => route.abort()); await page.goto('https://playwright.dev'); await browser.close(); P a g e R e q u e s t I n t e r c e p t i o n
  • 92. import {webkit, chromium, firefox} from 'playwright'; const browser = await firefox.launch(); const context = await browser.newContext(); await context.route('**/*.{png,jpg,jpeg}', route => route.abort()); const page = await page.newPage(); await page.goto('https://playwright.dev'); await browser.close(); C o n t e x t R e q u e s t I n t e r c e p t i o n
  • 93. import {webkit, chromium, firefox} from 'playwright'; const browser = await webkit.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); const [ download ] = await Promise.all([ page.waitForEvent('download'), page.click('button#delayed-download') ]); console.log(await download.path()); await browser.close(); D o w n l o a d s
  • 94. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 95. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 96. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 97. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 98. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 99. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 100. import {webkit, chromium, firefox} from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://playwright.dev'); await page.click('button'); // CSS selector await page.click('xpath=//button'); // XPath selector await page.click('text=Log in'); // Text selector await page.click(':nth-match(:text("Buy"), 3)'); // N-th match await page.click('div:right-of(:text("Name"))'); // Layout 😱 await page.click(`xpath=//form >> text=Submit`); // Composite S m a r t S e l e c t o r s
  • 101. // text content const content = await page.textContent('nav:first-child'); expect(content).toBe('home'); // Attributes const alt = await page.getAttribute('input', 'alt'); expect(alt).toBe('Text'); // Checkbox state const checked = await page.isChecked('input'); expect(checked).toBeTruthy(); // Visibility const visible = await page.isVisible('input'); expect(visible).toBeTruthy(); A s s e r t i o n s
  • 102. // text content const content = await page.textContent('nav:first-child'); expect(content).toBe('home'); // Attributes const alt = await page.getAttribute('input', 'alt'); expect(alt).toBe('Text'); // Checkbox state const checked = await page.isChecked('input'); expect(checked).toBeTruthy(); // Visibility const visible = await page.isVisible('input'); expect(visible).toBeTruthy(); A s s e r t i o n s
  • 103. // text content const content = await page.textContent('nav:first-child'); expect(content).toBe('home'); // Attributes const alt = await page.getAttribute('input', 'alt'); expect(alt).toBe('Text'); // Checkbox state const checked = await page.isChecked('input'); expect(checked).toBeTruthy(); // Visibility const visible = await page.isVisible('input'); expect(visible).toBeTruthy(); A s s e r t i o n s
  • 104. // text content const content = await page.textContent('nav:first-child'); expect(content).toBe('home'); // Attributes const alt = await page.getAttribute('input', 'alt'); expect(alt).toBe('Text'); // Checkbox state const checked = await page.isChecked('input'); expect(checked).toBeTruthy(); // Visibility const visible = await page.isVisible('input'); expect(visible).toBeTruthy(); A s s e r t i o n s
  • 105. import {chromium} from 'playwright'; const browser = await chromium.launch({ // Can be 'chrome', 'chrome-beta', 'msedge-beta', 'msedge-dev' channel: 'msedge', }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await browser.close(); M i c r o s o f t E d g e
  • 106. import {chromium} from 'playwright'; const browser = await chromium.launch({ // Can be 'chrome', 'chrome-beta', 'msedge-beta', 'msedge-dev' channel: 'msedge', }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await browser.close(); M i c r o s o f t E d g e
  • 107. More Features ● Built-in Shadow DOM piercing ● Idiomatic frames API ● Custom Selector Engines ● TimeZone / Locale / Color Scheme emulation ● Per-Context HTTP Proxy ● Workers / Service Workers ● Console sniffing ● Dialogs ● File Uploads ● Element Handles ● ...
  • 108. ● ubuntu-18.04 (chromium) ● ubuntu-18.04 (firefox) ● ubuntu-18.04 (webkit) ● ubuntu-20.04 (chromium) ● ubuntu-20.04 (firefox) ● ubuntu-20.04 (webkit) ● macos-10.14 (chromium) ● macos-10.14 (firefox) ● macos-10.14 (webkit) ● macos-10.15 (chromium) ● macos-10.15 (firefox) ● macos-10.15 (webkit) ● macos-11.0 (chromium) ● macos-11.0 (firefox) ● macos-11.0 (webkit) ● macos-11.0 arm64 (chromium) ● macos-11.0 arm64 (firefox) ● macos-11.0 arm64 (webkit) Rigorous Testing ● Windows (chromium) ● Windows (firefox) ● Windows (webkit) ● test-package-installations (^10.17.0) ● test-package-installations (^12.0.0) ● test-package-installations (^14.1.0) ● Headful Linux (chromium) ● Headful Linux (firefox) ● Headful Linux (webkit) ● Transport (driver) ● Transport (service) ● Video Linux (chromium) ● Video Linux (firefox) ● Video Linux (webkit) ● Android Emulator (shard 1) ● Android Emulator (shard 2) ● Chrome Stable (Linux) ● Chrome Stable (Win) ● Chrome Stable (Mac) ● Edge Stable (Win) ● Electron Linux
  • 112. 🎭 Playwright WebKit Availability Headed Headless ✅ ✅ ✅ ✅ ✅ ✅
  • 113. ● All Browsers ○ Chrome, Safari, Firefox 🎭 Playwright is Ubiquitous
  • 114. ● All Browsers ○ Chrome, Safari, Firefox ● All OS ○ Linux, Mac, Windows 🎭 Playwright is Ubiquitous
  • 115. 🎭 Playwright is Ubiquitous ● All Browsers ○ Chrome, Safari, Firefox ● All OS ○ Linux, Mac, Windows ● All Popular Languages ○ JavaScript / TypeScript ○ Java ○ Python ○ C# (alpha)
  • 116. CI/CD, Services, Clients ● Any CI/CD ○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI, AWS, GCP, …
  • 117. ● Any CI/CD ○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI, AWS, GCP, … ● Docker Containers ○ docker pull mcr.microsoft.com/playwright ○ docker pull mcr.microsoft.com/playwright-java CI/CD, Services, Clients
  • 118. CI/CD, Services, Clients ● Any CI/CD ○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI, AWS, GCP, … ● Docker Containers ○ docker pull mcr.microsoft.com/playwright ○ docker pull mcr.microsoft.com/playwright-java ● Third-Party integrations ○ applitools.com ○ saucelabs.com ○ Checklyhq.com ○ www.testim.io ○ github.com/aerokube/moon ○ seleniumbox.com
  • 119. CI/CD, Services, Clients ● Any CI/CD ○ Github Actions, Travis CI, Azure Pipelines, Jenkins, Circle CI, AWS, GCP, … ● Docker Containers ○ docker pull mcr.microsoft.com/playwright ○ docker pull mcr.microsoft.com/playwright-java ● Third-Party integrations ○ applitools.com ○ saucelabs.com ○ Checklyhq.com ○ www.testim.io ○ github.com/aerokube/moon ○ seleniumbox.com
  • 127. Act V Delightful Authoring & Debugging Dependable Efficient Capable Ubiquitous Delightful Lively
  • 128. 🍿 Demo Time 🍿
  • 129. Authoring & Debugging - Code Generation - npx playwright codegen - Built-In Inspector - PWDEBUG=1 node snippet.js - Devtools Console integration - playwright.$ - Simple Node.js Debugging - Logging - DEBUG=pw:api node snippet.js - Storage State re-use
  • 131. Lively 🐈 ● Active Development ○ 2500+ commits in the last year ○ 1600+ closed issues ● Growing Team ○ We’re hiring! ● Expanding Horizons
  • 132. const { _electron } = require('playwright'); (async () => { const electronApp = await _electron.launch({ args: ['main.js'] }); const window = await electronApp.firstWindow(); console.log(await window.title()); await window.screenshot({ path: 'intro.png' }); await window.click('text=Click me'); await electronApp.close(); })(); 🧪 E x p e r i m e n t a l : E l e c t r o n . j s
  • 133. const { _android } = require('playwright'); (async () => { const [device] = await _android.devices(); await device.shell('am force-stop com.android.chrome'); const context = await device.launchBrowser(); const page = await context.newPage(); await page.goto('https://playwright.dev/'); await page.screenshot({ path: 'page.png' }); await context.close(); await device.close(); })(); 🧪 E x p e r i m e n t a l : A n d r o i d
  • 139.
  • 140. How-To: Authentication Re-use Context 1 1. npx playwright codegen --save-storage=auth.json
  • 141. How-To: Authentication Re-use Context 1 Storage State 2. Extract & Save Storage State 1. npx playwright codegen --save-storage=auth.json
  • 142. How-To: Authentication Re-use Context 1 Context N Storage State 2. Extract & Save Storage State 3. Re-Use Storage State 1. npx playwright codegen --save-storage=auth.json
  • 148. 🍿 Demo Time 🍿
  • 149. const context = await browser.newContext({ storageState: require('auth.json'), }); A u t h e n t i c a t i o n R e - U s e
  • 150. const context = await browser.newContext({ storageState: require('auth.json'), }); A u t h e n t i c a t i o n R e - U s e