1656302389
Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
Headless execution is supported for all the browsers on all platforms. Check out system requirements for details.
Looking for Playwright for Python, .NET, or Java?
Playwright has its own test runner for end-to-end tests, we call it Playwright Test.
The easiest way to get started with Playwright Test is to run the init command.
# Run from your project's root directory
npm init playwright@latest
# Or create a new project
npm init playwright@latest new-project
This will create a configuration file, optionally add examples, a GitHub Action workflow and a first test example.spec.ts. You can now jump directly to writing assertions section.
Add dependency and install browsers.
npm i -D @playwright/test
# install supported browsers
npx playwright install
You can optionally install only selected browsers, see install browsers for more details. Or you can install no browsers at all and use existing browser channels.
Auto-wait. Playwright waits for elements to be actionable prior to performing actions. It also has rich set of introspection events. The combination of the two eliminate the need for artificial timeouts - primary cause of flaky tests.
Web-first assertions. Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met.
Tracing. Configure test retry strategy, capture execution trace, videos, screenshots to eliminate flakes.
Browsers run web content belonging to different origins in different processes. Playwright is aligned with the modern browsers architecture and runs tests out-of-process. This makes Playwright free of the typical in-process test runner limitations.
Multiple everything. Test scenarios that span multiple tabs, multiple origins and multiple users. Create scenarios with different contexts for different users and run them against your server, all in one test.
Trusted events. Hover elements, interact with dynamic controls, produce trusted events. Playwright uses real browser input pipeline indistinguishable from the real user.
Test frames, pierce Shadow DOM. Playwright selectors pierce shadow DOM and allow entering frames seamlessly.
Browser contexts. Playwright creates a browser context for each test. Browser context is equivalent to a brand new browser profile. This delivers full test isolation with zero overhead. Creating a new browser context only takes a handful of milliseconds.
Log in once. Save the authentication state of the context and reuse it in all the tests. This bypasses repetitive log-in operations in each test, yet delivers full isolation of independent tests.
Codegen. Generate tests by recording your actions. Save them into any language.
Playwright inspector. Inspect page, generate selectors, step through the test execution, see click points, explore execution logs.
Trace Viewer. Capture all the information to investigate the test failure. Playwright trace contains test execution screencast, live DOM snapshots, action explorer, test source and many more.
Looking for Playwright for TypeScript, JavaScript, Python, .NET, or Java?
To learn how to run these Playwright Test examples, check out our getting started docs.
This code snippet navigates to whatsmyuseragent.org and saves a screenshot.
import { test } from '@playwright/test';
test('Page Screenshot', async ({ page }) => {
await page.goto('http://whatsmyuseragent.org/');
await page.screenshot({ path: `example.png` });
});
This snippet emulates Mobile Safari on a device at a given geolocation, navigates to maps.google.com, performs action and takes a screenshot.
import { test, devices } from '@playwright/test';
test.use({
...devices['iPhone 13 Pro'],
locale: 'en-US',
geolocation: { longitude: 12.492507, latitude: 41.889938 },
permissions: ['geolocation'],
})
test('Mobile and geolocation', async ({ page }) => {
await page.goto('https://maps.google.com');
await page.locator('text="Your location"').click();
await page.waitForRequest(/.*preview\/pwa/);
await page.screenshot({ path: 'colosseum-iphone.png' });
});
This code snippet navigates to example.com, and executes a script in the page context.
import { test } from '@playwright/test';
test('Evaluate in browser context', async ({ page }) => {
await page.goto('https://www.example.com/');
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
}
});
console.log(dimensions);
});
This code snippet sets up request routing for a page to log all network requests.
import { test } from '@playwright/test';
test('Intercept network requests', async ({ page }) => {
// Log and continue all network requests
await page.route('**', route => {
console.log(route.request().url());
route.continue();
});
await page.goto('http://todomvc.com');
});
Download Details:
Author: Microsoft
Source Code: https://github.com/Microsoft/playwright
License: Apache-2.0 license
#playwright #test #testing
1656173059
Jest Playwright examples
Demonstrates the usage of Playwright (cross-browser automation library in Node.js) in combination with Jest on GitHub Actions to test various sites.
Author: Playwright-community
Source Code: https://github.com/playwright-community/playwright-jest-examples
License: MIT license
1656165660
π demo.playwright
This repo is used to demo various testing scenarios with Playwright π, using the official test-runner and scripts authored in TypeScript.
The test.yml GitHub Action workflow is used to:
accessibility - runs accessibility checks against https://www.w3.org
android - runs a basic test using Android's WebView.
basic - basic tests to show interactions, element selectors, assertions, upload files, read a response, mock a response, and page object model (POM).
chrome-extension - basic test that gets a handle to the background page of Chrome extension.
drag-and-drop - runs example drag-and-drop test utilizing https://www.w3schools.com/html/html5_draganddrop.asp.
electron - runs a basic test for Electron application, controlling main electron process and working with Electron window.
fixtures - runs example tests utilizing test and worker fixtures.
github-api - uses GitHub API to test creation of a new repo, bug, and feature, then deletion of repo.
oauth - runs oauth tests for LinkedIn, Facebook, and Google, to login to https://courses.ultimateqa.com/users/sign_in.
performance - web performance tests using resource timing API, DevTools, and lighthouse, run against https://fastestwebsite.net
svgomg - End-to-end tests for SVGOMG! site, hosted at https://demo.playwright.dev/svgomg
todomvc - End-to-end tests for ToDoMVC site, hosted at https://demo.playwright.dev/todomvc
visual-comparison - visually compares snapshots with golden screenshots and text content for playwright.dev landing page.
When the above tests are finished, the results are published to GitHub pages:
The baseURL value for most tests is set as a workflow environment variable. This allows flexibility for the URL of the sites tested. By not hardcoding a URL in page.goTo('')
we can simply pass baseURL without changing the test script e.g. test.site.com -> stage.site.com -> prod.site.com
Please open an issue with details.
Author: MarcusFelling
Source Code: https://github.com/MarcusFelling/Demo.Playwright
License: Apache-2.0 license
1656161700
Moon is a commercial closed-source enterprise Selenium implementation using Kubernetes to launch browsers.
The main idea behind Moon is to be easily installable and require zero maintenance.
Having a running Kubernetes cluster and kubectl
pointing to it you can launch free Moon cluster with this one-liner:
$ git clone https://github.com/aerokube/moon-deploy.git && cd moon-deploy && kubectl apply -f moon.yaml
To obtain Moon load balancer IP address use the following command:
$ kubectl get svc -n moon
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
moon LoadBalancer 10.63.242.109 104.154.161.58 4444:31894/TCP,8080:30625/TCP 1m
Now use the following Selenium URL in your code:
http://104.154.161.58:4444/wd/hub
We also provide detailed installation video.
Complete reference guide can be found at: http://aerokube.com/moon/latest/
Author: Aerokube
Source Code: https://github.com/aerokube/moon
License: Apache-2.0 license
1656153906
ESLint Plugin Playwright
ESLint plugin for your Playwright testing needs.
Yarn
yarn add -D eslint-plugin-playwright
NPM
npm install -D eslint-plugin-playwright
This plugin bundles two configurations to work with both @playwright/test
or jest-playwright
.
{
"extends": ["plugin:playwright/playwright-test"]
}
{
"extends": ["plugin:playwright/jest-playwright"]
}
missing-playwright-await
π§Identify false positives when async Playwright APIs are not properly awaited.
Example of incorrect code for this rule:
expect(page).toMatchText('text');
test.step('clicks the button', async () => {
await page.click('button');
});
Example of correct code for this rule:
await expect(page).toMatchText('text');
await test.step('clicks the button', async () => {
await page.click('button');
});
The rule accepts a non-required option which can be used to specify custom matchers which this rule should also warn about. This is useful when creating your own async expect
matchers.
{
"playwright/missing-playwright-await": [
"error",
{ "customMatchers": ["toBeCustomThing"] }
]
}
no-page-pause
Prevent usage of page.pause()
.
Example of incorrect code for this rule:
await page.click('button');
await page.pause();
Example of correct code for this rule:
await page.click('button');
no-element-handle
Disallow the creation of element handles with page.$
or page.$$
.
Examples of incorrect code for this rule:
// Element Handle
const buttonHandle = await page.$('button');
await buttonHandle.click();
// Element Handles
const linkHandles = await page.$$('a');
Example of correct code for this rule:
const buttonLocator = page.locator('button');
await buttonLocator.click();
no-eval
Disallow usage of page.$eval
and page.$$eval
.
Examples of incorrect code for this rule:
const searchValue = await page.$eval('#search', (el) => el.value);
const divCounts = await page.$$eval(
'div',
(divs, min) => divs.length >= min,
10
);
await page.$eval('#search', (el) => el.value);
await page.$$eval('#search', (el) => el.value);
Example of correct code for this rule:
await page.locator('button').evaluate((node) => node.innerText);
await page.locator('div').evaluateAll((divs, min) => divs.length >= min, 10);
no-focused-test
Disallow usage of .only()
annotation
Examples of incorrect code for this rule:
test.only('focus this test', async ({ page }) => {});
test.describe.only('focus two tests', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
test.describe.parallel.only('focus two tests in parallel mode', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
test.describe.serial.only('focus two tests in serial mode', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
Examples of correct code for this rule:
test('this test', async ({ page }) => {});
test.describe('two tests', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
test.describe.parallel('two tests in parallel mode', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
test.describe.serial('two tests in serial mode', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
no-wait-for-timeout
Disallow usage of page.waitForTimeout()
.
Example of incorrect code for this rule:
await page.waitForTimeout(5000);
Examples of correct code for this rule:
// Use signals such as network events, selectors becoming visible and others instead.
await page.waitForLoadState();
await page.waitForUrl('/home');
await page.waitForFunction(() => window.innerWidth < 100);
no-skipped-test
Disallow usage of the .skip()
annotation.
Examples of incorrect code for this rule:
test.skip('skip this test', async ({ page }) => {});
test.describe.skip('skip two tests', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
test.describe('skip test inside describe', () => {
test.skip();
});
test.describe('skip test conditionally', async ({ browserName }) => {
test.skip(browserName === 'firefox', 'Working on it');
});
Examples of correct code for this rule:
test('this test', async ({ page }) => {});
test.describe('two tests', () => {
test('one', async ({ page }) => {});
test('two', async ({ page }) => {});
});
no-force-option
Disallow usage of the { force: true }
option.
Examples of incorrect code for this rule:
await page.locator('button').click({ force: true });
await page.locator('check').check({ force: true });
await page.locator('input').fill('something', { force: true });
Examples of correct code for this rule:
await page.locator('button').click();
await page.locator('check').check();
await page.locator('input').fill('something');
max-nested-describe
Enforces a maximum depth to nested .describe()
calls. Useful for improving readability and parallelization of tests.
Uses a default max depth option of { "max": 5 }
.
Examples of incorrect code for this rule (using defaults):
test.describe('level 1', () => {
test.describe('level 2', () => {
test.describe('level 3', () => {
test.describe('level 4', () => {
test.describe('level 5', () => {
test.describe('level 6', () => {
test('this test', async ({ page }) => {});
test('that test', async ({ page }) => {});
});
});
});
});
});
});
Examples of correct code for this rule (using defaults):
test.describe('first level', () => {
test.describe('second level', () => {
test('this test', async ({ page }) => {});
test('that test', async ({ page }) => {});
});
});
The rule accepts a non-required option to override the default maximum nested describe depth (5).
{
"playwright/max-nested-describe": ["error", { "max": 3 }]
}
no-conditional-in-test
Disallow conditional statements such as if
, switch
, and ternary expressions within tests.
Examples of incorrect code for this rule:
test('foo', async ({ page }) => {
if (someCondition) {
bar();
}
});
test('bar', async ({ page }) => {
switch (mode) {
case 'single':
generateOne();
break;
case 'double':
generateTwo();
break;
case 'multiple':
generateMany();
break;
}
await expect(page.locator('.my-image').count()).toBeGreaterThan(0);
});
test('baz', async ({ page }) => {
const hotkey =
process.platform === 'linux' ? ['Control', 'Alt', 'f'] : ['Alt', 'f'];
await Promise.all(hotkey.map((x) => page.keyboard.down(x)));
expect(actionIsPerformed()).toBe(true);
});
Examples of correct code for this rule:
test.describe('my tests', () => {
if (someCondition) {
test('foo', async ({ page }) => {
bar();
});
}
});
beforeEach(() => {
switch (mode) {
case 'single':
generateOne();
break;
case 'double':
generateTwo();
break;
case 'multiple':
generateMany();
break;
}
});
test('bar', async ({ page }) => {
await expect(page.locator('.my-image').count()).toBeGreaterThan(0);
});
const hotkey =
process.platform === 'linux' ? ['Control', 'Alt', 'f'] : ['Alt', 'f'];
test('baz', async ({ page }) => {
await Promise.all(hotkey.map((x) => page.keyboard.down(x)));
expect(actionIsPerformed()).toBe(true);
});
Author: Playwright-community
Source Code: https://github.com/playwright-community/eslint-plugin-playwright
License: MIT license
1656146400
The Playwright test runner includes all the matchers in this repo plus many more to make testing your projects easy. This doesn't mean, that we stop with maintaining this package.
This library provides utility matchers for Jest in combination with Playwright. All of them are exposed on the expect
object. You can use them either directly or invert them via the .not
property like shown in a example below.
npm install -D expect-playwright
To activate with the Playwright test runner, use expect.extend()
in the config to add the expect-playwright
matchers.
// playwright.config.ts
import { expect } from "@playwright/test"
import { matchers } from "expect-playwright"
expect.extend(matchers)
// ...
To activate it in your Jest environment you have to include it in your configuration.
{
"setupFilesAfterEnv": ["expect-playwright"]
}
The Playwright API is great, but it is low level and not designed for integration testing. So this package tries to provide a bunch of utility functions to perform the common checks easier.
Example which should wait and compare the text content of a paragraph on the page.
// before
await page.waitForSelector("#foo")
const textContent = await page.$eval("#foo", (el) => el.textContent)
expect(textContent).stringContaining("my text")
// after by using expect-playwright
await expect(page).toMatchText("#foo", "my text")
But that's not all! Our matchers also work inside of iframes and accept an ElementHandle which targets an iframe
element or a Frame obtained by calling element.contentFrame()
. Not only that, but if you pass a promise, we will automatically resolve it for you!
// before
const element = await page.$("iframe")
const frame = await element.contentFrame()
await expect(frame).toBeChecked("#foo")
// after
await expect(page.$("iframe")).toBeChecked("#foo")
This function checks if a given element is checked.
You can do this via a selector on the whole page:
await expect(page).toBeChecked("#my-element")
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toBeChecked()
This function checks if a given element is disabled.
You can do this via a selector on the whole page:
await expect(page).toBeDisabled("#my-element")
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toBeDisabled()
This function checks if a given element is enabled.
You can do this via a selector on the whole page:
await expect(page).toBeEnabled("#my-element")
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toBeEnabled()
This function checks if a given element is focused.
You can do this via a selector on the whole page:
await expect(page).toHaveFocus("#foobar")
Or by passing a Playwright ElementHandle:
const element = await page.$("#foobar")
await expect(element).toHaveFocus()
This function waits as a maximum as the timeout exceeds for a given selector once it appears on the page.
await expect(page).toHaveSelector("#foobar")
When used with not
, toHaveSelector
will wait until the element is not visible or not attached. See the Playwright waitForSelector docs for more details.
await expect(page).not.toHaveSelector("#foobar")
This function checks if the count of a given selector is the same as the provided value.
await expect(page).toHaveSelectorCount(".my-element", 3)
This function checks if an element's attribute matches the provided string or regex pattern.
You can do this via a selector on the whole page:
await expect(page).toMatchAttribute("#foo", "href", "https://playwright.dev")
await expect(page).toMatchAttribute("#foo", "href", /playwright/)
Or by passing a Playwright ElementHandle:
const element = await page.$("#foo")
await expect(element).toMatchAttribute("href", "https://playwright.dev")
await expect(element).toMatchAttribute("href", /playwright/)
This function checks if an element's computed style property matches the provided string or regex pattern.
You can do this via a selector on the whole page:
await expect(page).toMatchComputedStyle("#my-element", "color", "rgb(0, 0, 0)")
await expect(page).toMatchComputedStyle("#my-element", "color", /rgb/)
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toMatchComputedStyle("color", "rgb(0, 0, 0)")
await expect(element).toMatchComputedStyle("color", /rgb/)
This function checks if the textContent
of a given element matches the provided string or regex pattern.
You can do this via a selector on the whole page:
await expect(page).toMatchText("#my-element", "Playwright")
await expect(page).toMatchText("#my-element", /Play.+/)
Or without a selector which will use the body
element:
await expect(page).toMatchText("Playwright")
await expect(page).toMatchText(/Play.+/)
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toMatchText("Playwright")
await expect(element).toMatchText(/Play.+/)
This function checks if the page or frame title matches the provided string or regex pattern.
await expect(page).toMatchTitle("My app - page 1")
await expect(page).toMatchTitle(/My app - page \d/)
This function checks if the current page's URL matches the provided string or regex pattern.
await expect(page).toMatchURL("https://github.com")
await expect(page).toMatchURL(/github\.com/)
This function checks if the value
of a given element is the same as the provided string or regex pattern.
You can do this via a selector or the element directly:
await expect(page).toMatchValue("#my-element", "Playwright")
await expect(page).toMatchValue("#my-element", /Play.+/)
Or by passing a Playwright ElementHandle:
const element = await page.$("#my-element")
await expect(element).toMatchValue("Playwright")
await expect(element).toMatchValue(/Play.+/)
import playwright from "playwright-chromium"
describe("GitHub Playwright project", () => {
it("should should have Playwright in the README heading", async () => {
const browser = await playwright.chromium.launch()
const page = await browser.newPage()
await page.goto("https://github.com/microsoft/playwright")
await expect(page).toMatchText("#readme h1", "Playwright")
// or also all of them via the not property
await expect(page).not.toMatchText("this-is-no-anywhere", {
timeout: 1 * 1000,
})
await browser.close()
})
})
There are typings available. For that just import
import "expect-playwright"
at the top of your test file or include it globally in your tsconfig.json
.
β οΈ We recommend the official Playwright test runner β οΈ
Author: Playwright-community
Source Code: https://github.com/playwright-community/expect-playwright
License: MIT license
1656138780
Fluent API around Playwright
npm i --save playwright-fluent
If not already installed, the playwright
package should also be installed with a version >= 1.12.0
import { PlaywrightFluent, userDownloadsDirectory } from 'playwright-fluent';
const p = new PlaywrightFluent();
await p
.withBrowser('chromium')
.withOptions({ headless: false })
.withCursor()
.withDialogs()
.recordPageErrors()
.recordFailedRequests()
.recordDownloadsTo(userDownloadsDirectory)
.emulateDevice('iPhone 6 landscape')
.navigateTo('https://reactstrap.github.io/components/form/')
.click('#exampleEmail')
.typeText('foo.bar@baz.com')
.pressKey('Tab')
.expectThatSelector('#examplePassword')
.hasFocus()
.typeText("don't tell!")
.pressKey('Tab')
.expectThatSelector('#examplePassword')
.hasClass('is-valid')
.hover('#exampleCustomSelect')
.select('Value 3')
.in('#exampleCustomSelect')
.close();
This package provides also a Selector API that enables to find and target a DOM element or a collection of DOM elements embedded in complex DOM Hierarchy:
const selector = p
.selector('[role="row"]') // will get all dom elements, within the current page, with the attribute role="row"
.withText('foobar') // will filter only those that contain the text 'foobar'
.find('td') // from previous result(s), find all embedded <td> elements
.nth(2); // take only the second cell
await p.expectThat(selector).hasText('foobar-2');
This fluent API enables to seamlessly navigate inside an iframe and switch back to the page:
const p = new PlaywrightFluent();
const selector = 'iframe';
const inputInIframe = '#input-inside-iframe';
const inputInMainPage = '#input-in-main-page';
await p
.withBrowser('chromium')
.withOptions({ headless: false })
.withCursor()
.navigateTo(url)
.hover(selector)
.switchToIframe(selector)
.click(inputInIframe)
.typeText('hey I am in the iframe')
.switchBackToPage()
.click(inputInMainPage)
.typeText('hey I am back in the page!');
This fluent API enables to handle alert
, prompt
and confirm
dialogs:
const p = new PlaywrightFluent();
await p
.withBrowser(browser)
.withOptions({ headless: true })
.WithDialogs()
.navigateTo(url)
// do some stuff that will open a dialog
.waitForDialog()
.expectThatDialog()
.isOfType('prompt')
.expectThatDialog()
.hasMessage('Please say yes or no')
.expectThatDialog()
.hasValue('yes')
.typeTextInDialogAndSubmit('foobar');
This fluent API enables to handle the playwright
tracing API in the following way:
const p = new PlaywrightFluent();
await p
.withBrowser(browser)
.withOptions({ headless: true })
.withTracing()
.withCursor()
.startTracing({ title: 'my first trace' })
.navigateTo(url)
// do some stuff on the opened page
.stopTracingAndSaveTrace({ path: path.join(__dirname, 'trace1.zip') })
// do other stuff
.startTracing({ title: 'my second trace' })
// do other stuff
.stopTracingAndSaveTrace({ path: path.join(__dirname, 'trace2.zip') });
This fluent API enables to perform actions and assertions on a collection of DOM elements with a forEach()
operator.
See it below in action on ag-grid
where all athletes with Julia
in their name must be selected:
const p = new PlaywrightFluent();
const url = `https://www.ag-grid.com/javascript-data-grid/keyboard-navigation/`;
const cookiesConsentButton = p
.selector('#onetrust-button-group')
.find('button')
.withText('Accept All Cookies');
const gridContainer = 'div#myGrid';
const rowsContainer = 'div.ag-body-viewport div.ag-center-cols-container';
const rows = p.selector(gridContainer).find(rowsContainer).find('div[role="row"]');
const filter = p.selector(gridContainer).find('input[aria-label="Athlete Filter Input"]').parent();
await p
.withBrowser('chromium')
.withOptions({ headless: false })
.withCursor()
.navigateTo(url)
.click(cookiesConsentButton)
.switchToIframe('iframe[title="grid-keyboard-navigation"]')
.hover(gridContainer)
.click(filter)
.typeText('Julia')
.pressKey('Enter')
.expectThat(rows.nth(1))
.hasText('Julia');
await rows.forEach(async (row) => {
const checkbox = row
.find('input')
.withAriaLabel('Press Space to toggle row selection (unchecked)')
.parent();
await p.click(checkbox);
});
This package provides a way to write tests as functional components called Story
:
stories.ts
import { Story, StoryWithProps } from 'playwright-fluent';
export interface StartAppProps {
browser: BrowserName;
isHeadless: boolean;
url: string;
}
// first story: start the App
export const startApp: StoryWithProps<StartAppProps> = async (p, props) => {
await p
.withBrowser(props.browser)
.withOptions({ headless: props.isHeadless })
.withCursor()
.navigateTo(props.url);
}
// second story: fill in the form
export const fillForm: Story = async (p) => {
await p
.click(selector)
.select(option)
.in(customSelect)
...;
};
// threrd story: submit form
export const submitForm: Story = async (p) => {
await p
.click(selector);
};
// fourth story: assert
export const elementIsVisible: Story = async (p) => {
await p
.expectThatSelector(selector)
.isVisible();
};
test.ts
import { startApp, fillForm } from 'stories';
import { PlaywrightFluent } from 'playwright-fluent';
const p = new PlaywrightFluent();
await p
.runStory(startApp, { browser: 'chrome', isHeadless: false, url: 'http://example.com' })
.runStory(fillForm)
.close();
// Also methods synonyms are available to achieve better readability
const user = new PlaywrightFluent();
await user
.do(startApp, { browser: 'chrome', isHeadless: false, url: 'http://example.com' })
.and(fillForm)
.attemptsTo(submitForm)
.verifyIf(elementIsVisible)
.close();
This fluent API provides a generic and simple infrastructure for massive request interception and response mocking.
This Mock API leverages the Playwright
request interception infrastructure and will enable you to mock all HTTP requests in order to test the front in complete isolation from the backend.
Read more about the Fluent Mock API
This API is still a draft and is in early development, but stay tuned!
Check out our contributing guide.
playwright-fluent
is just a wrapper around the Playwright API. It leverages the power of Playwright by giving a Fluent API, that enables to consume the Playwright API with chainable actions and assertions. The purpose of playwright-fluent
is to be able to write e2e tests in a way that makes tests more readable, reusable and maintainable.
Yes you can.
import { PlaywrightFluent } from 'playwright-fluent';
// just create a new instance with playwright's browser and page instances
const p = new PlaywrightFluent(browser, page);
// you can also create a new instance with playwright's browser and frame instances
const p = new PlaywrightFluent(browser, frame);
// now you can use the fluent API
Yes you can. To use the Playwright API, call the currentBrowser()
and/or currentPage()
methods exposed by the fluent API:
const browser = 'chromium';
const p = new PlaywrightFluent();
await p
.withBrowser(browser)
.emulateDevice('iPhone 6 landscape')
.withCursor()
.navigateTo('https://reactstrap.github.io/components/form/')
...;
// now if you want to use the playwright API from this point:
const browser = p.currentBrowser();
const page = p.currentPage();
// the browser and page objects are standard playwright objects
// so now you are ready to go by using the playwright API
The documentations:
reflect the current status of the development and are inline with the published package.
Yes, have a look to this demo project with jest, this demo project with cucumber-js v6 or this demo project with cucumber-js v7.
Fluent API | Selector API | Assertion API | Mock API | FAQ | with jest | with cucumber-js v6 | with cucumber-js v7
Author: Hdorgeval
Source Code: https://github.com/hdorgeval/playwright-fluent
License: MIT license
1656123381
playwright-perl
Perl bindings for playwright, the amazing cross browser testing framework from Microsoft
You're writing some acceptance test with Selenium::Remote:Driver, but you figure out selenium is a dead protocol? Finally, a solution!
A little node webserver written in express is spun up which exposes the entire playwright API. We ensure the node deps are installed in a BEGIN block, and then spin up the proxy server. You then use playwright more or less as normal; see the POD in Playwright.pm for more details.
See example.pl for usage examples.
Everything newer than 5.28 is supported.
Things should work on 5.20 or newer, but... Tests might fail due to Temp file weirdness with Test::MockFile.
Everything seems to work fine on OSX and Linux.
On Windows, you will have to approve a UAC prompt to exempt playwright_server
from being firewalled off.
Everything should more or less set itself up automatically, or explode and tell you what to do. I assume you know how to get cpanm.
You might want to use distro packages for some of these:
sudo cpanm Dist::Zilla
dzil authordeps --missing | sudo cpanm
dzil listdeps --missing | sudo cpanm
From there you'll need nvm to get the latest verison of node working:
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
source ~/.bashrc
nvm install
nvm use
Running dzil test should let you know if your kit is good to develop.
Actually running stuff will look like this after you generate the API json and modules:
PATH="$(pwd)/bin:$PATH" perl -Ilib example.pl
Playwright doesn't ship their api.json with the distribution on NPM. You have to generate it from their repo.
clone it in a directory that is the same as the one containing this repository. then run generate_api_json.sh
to get things working such that the build scripts know what to do.
Then run generate_perl_modules.pl
to get the accessor classes built based off of the spec, and insert the spec JSON into the playwright_server binary.
To make life simple, you can just run run_example
in the TLD when debugging.
Hop into the playwright slack, and check out the #playwright-perl channel therein. I'm watching that space and should be able to answer your questions. https://aka.ms/playwright-slack
Apparently Microsoft is trying to migrate to Github's built in forums, so I've activated discussions on this project too (see the tab at the top).
Author: Teodesian
Source Code: https://github.com/teodesian/playwright-perl
License: MIT license
1656083520
π Playwright for Rust
Playwright is a rust library to automate Chromium, Firefox and WebKit built on top of Node.js library.
[dependencies]
playwright = "0.0.18"
use playwright::Playwright;
#[tokio::main]
async fn main() -> Result<(), playwright::Error> {
let playwright = Playwright::initialize().await?;
playwright.prepare()?; // Install browsers
let chromium = playwright.chromium();
let browser = chromium.launcher().headless(true).launch().await?;
let context = browser.context_builder().build().await?;
let page = context.new_page().await?;
page.goto_builder("https://example.com/").goto().await?;
// Exec in browser and Deserialize with serde
let s: String = page.eval("() => location.href").await?;
assert_eq!(s, "https://example.com/");
page.click_builder("a").click().await?;
Ok(())
}
These runtimes have passed tests. You can disable tokio, the default feature, and then choose another.
Functions do not have default arguments in rust. Functions with two or more optional arguments are now passed with the builder pattern.
Playwright is designed as a server-client. All playwright client dependent on the driver: zip of core js library and Node.js. Application uses this library will be bundled the driver into rust binary at build time. There is an overhead of unzipping on the first run.
playwright-rust redistributes Playwright licensed under the Apache 2.0.
Playwright has NOTICE:
"""
Playwright
Copyright (c) Microsoft Corporation
This software contains code derived from the Puppeteer project (https://github.com/puppeteer/puppeteer),
available under the Apache 2.0 license (https://github.com/puppeteer/puppeteer/blob/master/LICENSE).
"""
Author: Octaltree
Source Code: https://github.com/octaltree/playwright-rust
License:
1656076140
π Playwright for Crystal
Playwright-cr is a Crystal library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast. See how Playwright is better.
Linux | macOS | Windows | |
---|---|---|---|
Chromium 89.0.4344.0 | β | β | β |
WebKit 14.1 | β | β | β |
Firefox 85.0b1 | β | β | β |
Headless execution is supported for all the browsers on all platforms. Check out system requirements for details.
Playwright Dependencies
Playwright Crystal relies on two external components: The Playwright driver and the browsers.
Playwright drivers will be downloaded to the bin/driver
folder, and browsers will be installed at shard installation time.
Add the dependency to your shard.yml
:
dependencies:
playwright:
github: naqvis/playwright-cr
Run shards install
This code snippet navigates to whatsmyuseragent.org in Chromium, Firefox and WebKit, and saves 3 screenshots.
require "playwright"
playwright = Playwright.create
browser_types = [playwright.chromium,
playwright.webkit,
playwright.firefox]
browser_types.each do |browser_type|
browser = browser_type.launch
context = browser.new_context(Playwright::Browser::NewContextOptions.new(
viewport: Playwright::Page::ViewPort.new(800, 600)))
page = context.new_page
page.goto("http://whatsmyuseragent.org/")
page.screenshot(Playwright::Page::ScreenshotOptions.new(path: Path["screenshot-#{browser_type.name}.png"]))
browser.close
end
playwright.close
This snippet emulates Mobile Chromium on a device at a given geolocation, navigates to openstreetmap.org, performs action and takes a screenshot.
require "playwright"
playwright = Playwright.create
browser = playwright.chromium.launch(Playwright::BrowserType::LaunchOptions.new(headless: false))
pixel2 = playwright.devices["Pixel 2"]
context = browser.new_context(Playwright::Browser::NewContextOptions.new(
viewport: Playwright::Page::ViewPort.new(pixel2.viewport.width, pixel2.viewport.height),
user_agent: pixel2.user_agent,
device_scale_factor: pixel2.device_scale_factor.to_i,
is_mobile: pixel2.is_mobile,
has_touch: pixel2.has_touch,
locale: "en-US",
geolocation: Playwright::Geolocation.new(41.889938, 12.492507),
permissions: ["geolocation"]))
page = context.new_page
page.goto("https://www.openstreetmap.org/")
page.click("a[data-original-title=\"Show My Location\"]")
page.screenshot(Playwright::Page::ScreenshotOptions.new(path: Path["colosseum-pixel2.png"]))
browser.close
playwright.close
This code snippet navigates to example.com in Firefox, and executes a script in the page context.
require "playwright"
playwright = Playwright.create
browser = playwright.firefox.launch(Playwright::BrowserType::LaunchOptions.new(headless: false))
context = browser.new_context
page = context.new_page
page.goto("https://www.example.com/")
dimensions = page.evaluate(%(
() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
}
}
))
puts dimensions # => {"width" => 1280, "height" => 720, "deviceScaleFactor" => 1}
browser.close
playwright.close
This code snippet sets up request routing for a WebKit page to log all network requests.
require "playwright"
playwright = Playwright.create
browser = playwright.webkit.launch
context = browser.new_context
page = context.new_page
page.route("**", Playwright::Consumer(Playwright::Route).new { |route|
puts route.request.url
route.continue
})
page.goto("http://todomvc.com")
browser.close
playwright.close
Refer to spec
for more samples and usages. This shard comes with 350+ test cases :)
To run all tests:
crystal spec
By Default browser is chromium
, but you can change the browser via setting environment variable of BROWSER=firefox
or BROWSER=webkit
for specs to run using different browser. By default tests are run in headless mode. But if you would like the tests to run in headful way, set the environment variable HEADFUL=true
.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)Author: Naqvis
Source Code: https://github.com/naqvis/playwright-cr
License: MIT license
1656068700
π Playwright client for Ruby
gem 'playwright-ruby-client'
and then 'bundle install'.
Since playwright-ruby-client doesn't include the playwright driver, we have to install playwright in advance.
npm install playwright
./node_modules/.bin/playwright install
And set playwright_cli_executable_path: './node_modules/.bin/playwright'
Prefer playwrighting without Node.js?
Instead of npm, you can also directly download playwright driver from playwright.azureedge.net/builds/. The URL can be easily detected from here
require 'playwright'
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
playwright.chromium.launch(headless: false) do |browser|
page = browser.new_page
page.goto('https://github.com/YusukeIwaki')
page.screenshot(path: './YusukeIwaki.png')
end
end
require 'playwright'
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
playwright.chromium.launch(headless: false) do |browser|
page = browser.new_page
page.goto('https://github.com/')
form = page.query_selector("form.js-site-search-form")
search_input = form.query_selector("input.header-search-input")
search_input.click
page.keyboard.type("playwright")
page.expect_navigation {
page.keyboard.press("Enter")
}
list = page.query_selector("ul.repo-list")
items = list.query_selector_all("div.f4")
items.each do |item|
title = item.eval_on_selector("a", "a => a.innerText")
puts("==> #{title}")
end
end
end
$ bundle exec ruby main.rb
==> microsoft/playwright
==> microsoft/playwright-python
==> microsoft/playwright-cli
==> checkly/headless-recorder
==> microsoft/playwright-sharp
==> playwright-community/jest-playwright
==> microsoft/playwright-test
==> mxschmitt/playwright-go
==> microsoft/playwright-java
==> MarketSquare/robotframework-browser
require 'playwright'
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
devices = playwright.android.devices
unless devices.empty?
device = devices.last
begin
puts "Model: #{device.model}"
puts "Serial: #{device.serial}"
puts device.shell('ls /system')
device.launch_browser do |context|
page = context.pages.first
page.goto('https://github.com/YusukeIwaki')
page.click('header button')
page.click('input[name="q"]')
page.keyboard.type('puppeteer')
page.expect_navigation {
page.keyboard.press('Enter')
}
page.screenshot(path: 'YusukeIwaki.android.png')
end
ensure
device.close
end
end
end
We have to download android-driver for Playwright in advance.
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver-target.apk -O /path/to/playwright-driver/package/bin/android-driver-target.apk
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver.apk -O /path/to/playwright-driver/package/bin/android-driver.apk
(If you downloaded Playwright via npm, replace /path/to/playwright-driver/package/
with ./node_modules/playwright/
above.)
require 'playwright'
Playwright.create(playwright_cli_executable_path: ENV['PLAYWRIGHT_CLI_EXECUTABLE_PATH']) do |playwright|
devices = playwright.android.devices
unless devices.empty?
device = devices.last
begin
device.shell('input keyevent POWER')
device.shell('input keyevent POWER')
device.shell('input keyevent 82')
sleep 1
device.shell('cmd statusbar expand-notifications')
# pp device.tree
# pp device.info(res: 'com.android.systemui:id/clock')
device.tap_on(res: 'com.android.systemui:id/clock')
ensure
device.close
end
end
end
If your environment doesn't accept installing browser or creating browser process, consider separating Ruby client and Playwright server.
For launching Playwright server, just execute:
npx playwright install && npx playwright run-server --port 8080
and we can connect to the server with the code like this:
Playwright.connect_to_playwright_server('ws://127.0.0.1:8080') do |playwright|
playwright.chromium.launch do |browser|
page = browser.new_page
page.goto('https://github.com/YusukeIwaki')
page.screenshot(path: './YusukeIwaki.png')
end
end
When Playwright.connect_to_playwright_server
is used, playwright_cli_executable_path is not required.
For more detailed instraction, refer this article: https://playwright-ruby-client.vercel.app/docs/article/guides/playwright_on_alpine_linux
Everyone interacting in the Playwright projectβs codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Author: YusukeIwaki
Source Code: https://github.com/YusukeIwaki/playwright-ruby-client
License: MIT license
1656061260
π Playwright for Go
Playwright is a Go library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
Linux | macOS | Windows | |
---|---|---|---|
Chromium 101.0.4929.0 | β | β | β |
WebKit 15.4 | β | β | β |
Firefox 97.0.1 | β | β | β |
Headless execution is supported for all the browsers on all platforms.
go get github.com/playwright-community/playwright-go
Install the browsers and OS dependencies:
go run github.com/playwright-community/playwright-go/cmd/playwright install --with-deps
# Or
go install github.com/playwright-community/playwright-go/cmd/playwright
playwright install --with-deps
Alternatively you can do it inside your program via which downloads the driver and browsers:
err := playwright.Install()
Playwright is built to automate the broad and growing set of web browser capabilities used by Single Page Apps and Progressive Web Apps.
The following example crawls the current top voted items from Hacker News.
package main
import (
"fmt"
"log"
"github.com/playwright-community/playwright-go"
)
func main() {
pw, err := playwright.Run()
if err != nil {
log.Fatalf("could not start playwright: %v", err)
}
browser, err := pw.Chromium.Launch()
if err != nil {
log.Fatalf("could not launch browser: %v", err)
}
page, err := browser.NewPage()
if err != nil {
log.Fatalf("could not create page: %v", err)
}
if _, err = page.Goto("https://news.ycombinator.com"); err != nil {
log.Fatalf("could not goto: %v", err)
}
entries, err := page.QuerySelectorAll(".athing")
if err != nil {
log.Fatalf("could not get entries: %v", err)
}
for i, entry := range entries {
titleElement, err := entry.QuerySelector("td.title > a")
if err != nil {
log.Fatalf("could not get title element: %v", err)
}
title, err := titleElement.TextContent()
if err != nil {
log.Fatalf("could not get text content: %v", err)
}
fmt.Printf("%d: %s\n", i+1, title)
}
if err = browser.Close(); err != nil {
log.Fatalf("could not close browser: %v", err)
}
if err = pw.Stop(); err != nil {
log.Fatalf("could not stop Playwright: %v", err)
}
}
Playwright is a Node.js library which uses:
These patches are based on the original sources of the browsers and don't modify the browser behaviour so the browsers are basically the same (see here) as you see them in the wild. The support for different programming languages is based on exposing a RPC server in the Node.js land which can be used to allow other languages to use Playwright without implementing all the custom logic:
The bridge between Node.js and the other languages is basically a Node.js runtime combined with Playwright which gets shipped for each of these languages (around 50MB) and then communicates over stdio to send the relevant commands. This will also download the pre-compiled browsers.
We are ready for your feedback, but we are still covering Playwright Go with the tests.
API reference | Example recipes
Author: Playwright-community
Source Code: https://github.com/playwright-community/playwright-go
License: MIT license
1656057480
π Playwright for Java
Playwright is a Java library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
Linux | macOS | Windows |
---|---|---|
Chromium 102.0.5005.40 | β | β |
WebKit 15.4 | β | β |
Firefox 99.0.1 | β | β |
Playwright requires Java 8 or newer.
Playwright is distributed as a set of Maven modules. The easiest way to use it is to add one dependency to your Maven pom.xml
file as described below. If you're not familiar with Maven please refer to its documentation.
To run Playwright simply add following dependency to your Maven project:
<dependency> <groupId>com.microsoft.playwright</groupId> <artifactId>playwright</artifactId> <version>1.17.0</version></dependency>
No, Playwright is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create multiple Playwright instances each on its own thread.
You can find Maven project with the examples here.
This code snippet navigates to whatsmyuseragent.org in Chromium, Firefox and WebKit, and saves 3 screenshots.
import com.microsoft.playwright.*;import java.nio.file.Paths;import java.util.Arrays;import java.util.List;public class PageScreenshot { 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()) { BrowserContext context = browser.newContext(); Page page = context.newPage(); page.navigate("http://whatsmyuseragent.org/"); page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot-" + browserType.name() + ".png"))); } } } }}
This snippet emulates Mobile Chromium on a device at a given geolocation, navigates to openstreetmap.org, performs action and takes a screenshot.
import com.microsoft.playwright.options.*;import com.microsoft.playwright.*;import java.nio.file.Paths;import static java.util.Arrays.asList;public class MobileAndGeolocation { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.chromium().launch(); BrowserContext context = browser.newContext(new Browser.NewContextOptions() .setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36") .setViewportSize(411, 731) .setDeviceScaleFactor(2.625) .setIsMobile(true) .setHasTouch(true) .setLocale("en-US") .setGeolocation(41.889938, 12.492507) .setPermissions(asList("geolocation"))); Page page = context.newPage(); page.navigate("https://www.openstreetmap.org/"); page.click("a[data-original-title=\"Show My Location\"]"); page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("colosseum-pixel2.png"))); } }}
This code snippet navigates to example.com in Firefox, and executes a script in the page context.
import com.microsoft.playwright.*;public class EvaluateInBrowserContext { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.firefox().launch(); BrowserContext context = browser.newContext(); Page page = context.newPage(); page.navigate("https://www.example.com/"); Object dimensions = page.evaluate("() => {\n" + " return {\n" + " width: document.documentElement.clientWidth,\n" + " height: document.documentElement.clientHeight,\n" + " deviceScaleFactor: window.devicePixelRatio\n" + " }\n" + "}"); System.out.println(dimensions); } }}
This code snippet sets up request routing for a WebKit page to log all network requests.
import com.microsoft.playwright.*;public class InterceptNetworkRequests { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.webkit().launch(); BrowserContext context = browser.newContext(); Page page = context.newPage(); page.route("**", route -> { System.out.println(route.request().url()); route.resume(); }); page.navigate("http://todomvc.com"); } }}
Check out our official documentation site.
You can also browse javadoc online.
Follow the instructions to build the project from source and install the driver.
Yes, Playwright for Java is ready. v1.10.0 is the first stable release. Going forward we will adhere to semantic versioning of the API.
Author: Microsoft
Source Code: https://github.com/microsoft/playwright-java
License: Apache-2.0 license
1656050040
Playwright for .NET π
Playwright for .NET is the official language port of Playwright, the library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
Linux | macOS | Windows | |
---|---|---|---|
Chromium 103.0.5060.24 | β | β | β |
WebKit 15.4 | β | β | β |
Firefox 99.0.1 | β | β | β |
https://playwright.dev/dotnet/docs/api/class-playwright
using System.Threading.Tasks;
using Microsoft.Playwright;
class Program
{
public static async Task Main()
{
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = false });
var page = await browser.NewPageAsync();
await page.GotoAsync("https://playwright.dev/dotnet");
await page.ScreenshotAsync(new() { Path = "screenshot.png" });
}
}
More comfortable in another programming language? Playwright is also available in
https://playwright.dev/dotnet/docs/intro
Author: Microsoft
Source Code: https://github.com/microsoft/playwright-dotnet
License: MIT license
1656042600
π Playwright for Python
Playwright is a Python library to automate Chromium, Firefox and WebKit browsers with a single API. Playwright delivers automation that is ever-green, capable, reliable and fast. See how Playwright is better.
Linux | macOS | Windows | |
---|---|---|---|
Chromium 102.0.5005.61 | β | β | β |
WebKit 15.4 | β | β | β |
Firefox 99.0.1 | β | β | β |
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('http://whatsmyuseragent.org/')
page.screenshot(path=f'example-{browser_type.name}.png')
browser.close()
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
for browser_type in [p.chromium, p.firefox, p.webkit]:
browser = await browser_type.launch()
page = await browser.new_page()
await page.goto('http://whatsmyuseragent.org/')
await page.screenshot(path=f'example-{browser_type.name}.png')
await browser.close()
asyncio.run(main())
More comfortable in another programming language? Playwright is also available in
https://playwright.dev/python/docs/intro
https://playwright.dev/python/docs/api/class-playwright
Author: Microsoft
Source Code: https://github.com/microsoft/playwright-python
License: Apache-2.0 license