What is Play Wright:
Playwright is an open-source test automation Node.Js library initially developed by Microsoft contributors to automate Chromium, Firefox, Webkit. It supports programming languages such as Java, Python, C#, and NodeJS. Playwright comes with Apache 2.0 License and is most popular with NodeJS with Javascript/Typescript. This Playwright tutorial will help set up with NodeJS using Visual Studio Code.
Advantages:
Playwright is the next upcoming popular automation tool after Selenium which has the following features
Easy Set up
Support Multiple languages.
Support Multiple Tab/windows
Auto Wait
Parallel Execution
Cross Browser support
Playwright Inspector, VSCode Debugger, Browser Developer Tools, and Trace Viewers Console Logs.
Support Functional, End-End, API testing. With third party plugin playwright can be integrated with Accessibility testing.
CI/CD support
Built in reports.
No configuration required for typescript
Limitations:
No support to IE11
No mobile App support.
New to Market so less community support.
Installation Step:
Ways to Install Playwright:
option 1: Can be installed as Visual studio Extension. Open-> Settings->Extensions-> Playwright-> Install
Option 2: Install as node Library
npm i playwright
Create New Project with Playwright:
Run the below cmd to create new project from visual studio code. This command will create the configuration files.
npm init playwright@latest new-project
The above cmd creates test folder for the scripts, Package.json for dependencies, Playwright.config.js for global playwright configurations, .gitignore
Steps to create POM and test scripts.
Login.js
Login.spec.js
Command to run npx palywright test
Command to run for specific bro
npx palywright test — project=chromium
Command to run in head mode
npx playwright test — project=chromium — headed
Command to run specific spec
npx playwright test specPath/test.js
to run tests under npx playwright test folderPath
to run tests with specific text in file name — npx playwright test my-spec my-spec-2
to run tests with specific title— npx playwright test -g “add a todo item”
to disable parallel execution — npx playwright test — workers=1
to generate report — npx playwright test — reporter=dot
to run in debug mode npx playwright test — debug
Assertions: To assert the test in palywright, it uses inbuild expect library. refer https://jestjs.io/docs/expect
Test Fixtures: If you noticed in the above Login.spec.js file {page} is used inside test hooks. this is test fixture. Fixture are object created for each test run. Playwright comes with its set of fixtures. During execution playwright looks for each test declarations, analyse the set of fixtures declared for it and prepared those fixtures for it.
eg:Page, context, Browser, BrowserName
Test hooks: test.BeforeAll, test.BeforeEach, test.AfterEach,test.AfterAll, playwright supports these hooks for set up and teardown.
Inputs:
Fill — to type text.
await page.fill(locator,value)
checkboxes/radio buttons:
/ Check the checkbox
await page.check(‘#agree’);
// Assert the checked state
expect(await page.isChecked(‘#agree’)).toBeTruthy()
// Uncheck by input <label>.
await page.uncheck(‘#subscribe-label’);
// Select the radio button
await page.check(‘text=XL’);
click — to click an element
await page.click(locator,value)
select options:
Selects one or multiple options in the <select>
element. You can specify option value
, label
or elementHandle
to select. Multiple options can be selected.
// Single selection matching the value
await page.selectOption('select#colors', 'blue');// Single selection matching the label
await page.selectOption('select#colors', { label: 'Blue' });// Multiple selected items
await page.selectOption('select#colors', ['red', 'green', 'blue']);// Select the option via element handle
const option = await page.$('#best-option');
await page.selectOption('select#colors', option);
MouseClick:
// Generic click
await page.click(‘button#submit’);
// Double click
await page.dblclick(‘#item’);
// Right click
await page.click(‘#item’, { button: ‘right’ });
// Shift + click
await page.click(‘#item’, { modifiers: [‘Shift’] });
// Hover over element
await page.hover(‘#item’);
// Click the top left corner
await page.click(‘#item’, { position: { x: 0, y: 0} });
await page.click(‘button#submit’, { force: true });
Type characters
Type into the field character by character, as if it was a user with a real keyboard.
// Type character by character
await page.type('#area', 'Hello World!');
Keys and shortcuts
// Hit Enter
await page.press('#submit', 'Enter');// Dispatch Control+Right
await page.press('#name', 'Control+ArrowRight');// Press $ sign on keyboard
await page.press('#value', '$');
Upload files
You can select input files for upload using the page.setInputFiles(selector, files[, options]) method. It expects first argument to point to an input element with the type "file"
. Multiple files can be passed in the array. If some of the file paths are relative, they are resolved relative to the current working directory. Empty array clears the selected files.
// Select one file
await page.setInputFiles('input#upload', 'myfile.pdf');// Select multiple files
await page.setInputFiles('input#upload', ['file1.txt', 'file2.txt']);// Remove all the selected files
await page.setInputFiles('input#upload', []);// Upload buffer from memory
await page.setInputFiles('input#upload', {
name: 'file.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test')
});
If you don’t have input element in hand (it is created dynamically), you can handle the page.on(‘filechooser’) event or use a corresponding waiting method upon your action:
// Note that Promise.all prevents a race condition
// between clicking and waiting for the file chooser.
const [fileChooser] = await Promise.all([
// It is important to call waitForEvent before click to set up waiting.
page.waitForEvent('filechooser'),
page.locator('upload').click(),
]);
await fileChooser.setFiles('myfile.pdf');
Focus element
For the dynamic pages that handle focus events, you can focus the given element.
await page.focus('input#name');
TimeOuts:
Playwright Test has multiple configurable timeouts for various tasks.
TimeoutDefaultDescriptionTest timeout30000 msTimeout for each test, includes test, hooks and fixtures:
SET DEFAULTconfig = { timeout: 60000 }
OVERRIDEtest.setTimeout(120000)
Expect timeout5000 msTimeout for each assertion:
SET DEFAULTconfig = { expect: { timeout: 10000 } }
OVERRIDEexpect(locator).toBeVisible({ timeout: 10000 })
Action timeoutno timeoutTimeout for each action:
SET DEFAULTconfig = { use: { actionTimeout: 10000 } }
OVERRIDElocator.click({ timeout: 10000 })
Navigation timeoutno timeoutTimeout for each navigation action:
SET DEFAULTconfig = { use: { navigationTimeout: 30000 } }
OVERRIDEpage.goto('/', { timeout: 30000 })
Global timeoutno timeoutGlobal timeout for the whole test run:
SET IN CONFIGconfig = { globalTimeout: 60*60*1000 }
Fixture timeoutno timeoutTimeout for an individual fixture:
SET IN FIXTURE{ scope: 'test', timeout: 30000 }
Test timeout
Playwright Test enforces a timeout for each test, 30 seconds by default. Time spent by the test function, fixtures, beforeEach
and afterEach
hooks is included in the test timeout.
Timed out test produces the following error:
example.spec.ts:3:1 › basic test ===========================Timeout of 30000ms exceeded.
The same test timeout also applies to beforeAll
and afterAll
hooks.
Set test timeout in the config
- TypeScript
- JavaScript
// playwright.config.js
// @ts-check/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
timeout: 5 * 60 * 1000,
};module.exports = config;
API reference: testConfig.timeout.
Set timeout for a single test
- TypeScript
- JavaScript
const { test, expect } = require('@playwright/test');test('slow test', async ({ page }) => {
test.slow(); // Easy way to triple the default timeout
// ...
});test('very slow test', async ({ page }) => {
test.setTimeout(120000);
// ...
});
API reference: test.setTimeout(timeout) and test.slow().
Change timeout from a hook
const { test, expect } = require('@playwright/test');test.beforeEach(async ({ page }, testInfo) => {
// Extend timeout for all tests running this hook by 30 seconds.
testInfo.setTimeout(testInfo.timeout + 30000);
});
API reference: testInfo.setTimeout(timeout).
Expect timeout
Web-first assertions like expect(locator).toHaveText()
have a separate timeout, 5 seconds by default. Assertion timeout is unrelated to the test timeout. It produces the following error:
example.spec.ts:3:1 › basic test ===========================Error: expect(received).toHaveText(expected)Expected string: "my text"
Received string: ""
Call log:
- expect.toHaveText with timeout 5000ms
- waiting for selector "button"
Set expect timeout in the config
- TypeScript
- JavaScript
// playwright.config.js
// @ts-check/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
expect: {
timeout: 10 * 1000,
},
};module.exports = config;
API reference: testConfig.expect.
Set timeout for a single assertion
const { test, expect } = require('@playwright/test');test('basic test', async ({ page }) => {
await expect(page.locator('button')).toHaveText('Sign in', { timeout: 10000 });
});
Action and navigation timeouts
Test usually performs some actions by calling Playwright APIs, for example locator.click()
. These actions do not have a timeout by default, but you can set one. Action that timed out produces the following error:
example.spec.ts:3:1 › basic test ===========================locator.click: Timeout 1000ms exceeded.
=========================== logs ===========================
waiting for selector "button"
============================================================
Playwright also allows to set a separate timeout for navigation actions like page.goto()
because loading a page is usually slower.
Set action and navigation timeouts in the config
// playwright.config.js
// @ts-check
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
use: {
actionTimeout: 10 * 1000,
navigationTimeout: 30 * 1000,
},
};module.exports = config;
API reference: testOptions.actionTimeout and testOptions.navigationTimeout.
Set timeout for a single action
const { test, expect } = require('@playwright/test');test('basic test', async ({ page }) => {
await page.goto('https://playwright.dev', { timeout: 30000 });
await page.locator('text=Get Started').click({ timeout: 10000 });
});
Global timeout
Playwright Test supports a timeout for the whole test run. This prevents excess resource usage when everything went wrong. There is no default global timeout, but you can set a reasonable one in the config, for example one hour. Global timeout produces the following error:
Running 1000 tests using 10 workers 514 skipped
486 passed
Timed out waiting 3600s for the entire test run
You can set global timeout in the config.
// playwright.config.js
// @ts-check/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
globalTimeout: 60 * 60 * 1000,
};module.exports = config;
API reference: testConfig.globalTimeout.
Fixture timeout
By default, fixture shares timeout with the test. However, for slow fixtures, especially worker-scoped ones, it is convenient to have a separate timeout. This way you can keep the overall test timeout small, and give the slow fixture more time.
const { test: base, expect } = require('@playwright/test');const test = base.extend({
slowFixture: [async ({}, use) => {
// ... perform a slow operation ...
await use('hello');
}, { timeout: 60000 }]
});test('example test', async ({ slowFixture }) => {
// ...
});