Playwright Test
Playwright Test is a test runner designed specifically to accommodate the needs of browser-based end-to-end test automation using Playwright integration library.
Playwright supports all modern rendering engines including Chromium, WebKit, and Firefox. It also lets you execute test scenarios on Windows, Linux, and macOS, locally or on CI, headless or headed with native mobile emulation of Google Chrome for Android and Mobile Safari.
If you want to add Serenity/JS to an existing Playwright Test suite, check out Extending Playwright Test with Serenity/JS.
In this article, you will learn:
- How to use Serenity/JS reporting services, including the Serenity BDD reporter, even if your test scenarios don't follow the Screenplay Pattern yet
- How to implement Playwright Test scenarios using reusable Serenity/JS Screenplay Pattern APIs and the Serenity/JS Playwright module
- How to augment native Playwright Test HTML reports with information gathered by your Serenity/JS actors
Examples and Project Templatesโ
If you'd like to dive straight into the code, Serenity/JS GitHub repository provides:
- Serenity/JS + Playwright project templates, which are the easiest way to start with the framework,
- several reference implementations, demonstrating using Serenity/JS with Playwright and Playwright Test to write web-based acceptance tests
Using Serenity/JS reporting servicesโ
To use Serenity/JS reporting services in a Playwright Test project, you need to:
- use
playwright.config.ts
to configure Serenity/JS to use the reporting services you want to use, such as theConsoleReporter
orSerenityBDDReporter
- optionally, use Serenity/JS Playwright Test
describe
andit
functions to define your test scenarios and inject Serenity/JS actors
Serenity/JS test runner adapters turn internal, test runner-specific events into Serenity/JS domain events that can contribute to test execution reports produced by Serenity/JS reporting services.
@serenity-js/playwright-test
module provides a test runner adapter
you can attach to your Playwright Test runner just like any other standard Playwright Test reporter.
Installing Serenity/JS Playwright and Playwright Test modulesโ
Follow Playwright Test installation instructions to create a new Playwright Test project:
npm init playwright@latest
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
โ Do you want to use TypeScript or JavaScript? ยท TypeScript
โ Where to put your end-to-end tests? ยท tests
โ Add a GitHub Actions workflow? (y/N) ยท false
โ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) ยท true
Playwright Test installation wizard will ask you whether you want to use TypeScript or JavaScript to implement your test scenarios. Choosing TypeScript offers improved tooling support in IDEs such as JetBrains and Visual Studio Code.
Next, add Serenity/JS Playwright and web integration modules:
You might also want to install Serenity/JS reporting services, to accompany your native Playwright Test reports:
To do the above, run the following command in your terminal:
- npm
- Yarn
npm install --save-dev @serenity-js/core @serenity-js/console-reporter @serenity-js/playwright @serenity-js/playwright-test @serenity-js/web @serenity-js/serenity-bdd
yarn add --dev @serenity-js/core @serenity-js/console-reporter @serenity-js/playwright @serenity-js/playwright-test @serenity-js/web @serenity-js/serenity-bdd
Configuring Serenity/JSโ
To use Serenity/JS reporting services, list them under crew
in
your playwright.config.ts
, alongside any other native Playwright Test reporters you might want to use:
import type { PlaywrightTestConfig } from '@playwright/test'
const config: PlaywrightTestConfig = {
reporter: [
[ '@serenity-js/playwright-test', {
crew: [
'@serenity-js/console-reporter',
'@serenity-js/serenity-bdd',
[ '@serenity-js/core:ArtifactArchiver', { outputDirectory: 'target/site/serenity' } ],
]
}],
// other native Playwright Test reporters
[ 'html', { open: 'never' } ], // built-in Playwright HTML reporter
],
// Other configuration omitted for brevity
// For details, see https://playwright.dev/docs/test-configuration
}
export default config
Learn more about configuring Serenity/JS Playwright Test reporter and Serenity/JS reporting services.
Defining Playwright Test scenariosโ
When Serenity/JS reports on Playwright Test scenarios, it assumes you're following a common convention
where the outermost describe
block describes the name of the feature or component under test,
and any nested describe
blocks contribute to the name of the test scenario.
For example, Serenity/JS will report the below scenario as:
- feature:
Todo List App
- scenario:
when the user is a guest their list is empty
import { describe, it } from '@playwright/test'
describe('Todo List App', () => { // - feature or component name
describe('when the user is', () => { // - one or more nested `describe` blocks
describe('a guest', () => { // to group scenarios
describe('their list', () => { // by context in which they apply
it('is empty', async ({ actor }) => { // - expected behaviour of the feature or component
})
})
})
})
})
Using the same name for the outermost describe
block in several different spec files makes
Serenity BDD associate the different test scenarios with the same logical "feature" or "component"
and produce feature coverage metrics.
Using Serenity/JS Screenplay Pattern APIsโ
Serenity/JS actor model works great with Playwright Test and Serenity/JS Screenplay Pattern APIs can help your team implement Playwright Test scenarios that are easy to read and understand.
The fastest way to get started with Serenity/JS and Playwright Test is to use one of the Serenity/JS + Playwright Test project templates. However, if you're adding Serenity/JS to an existing project or simply want to understand how the integration works, this guide is for you.
Referring to actors in test scenariosโ
To start using Serenity/JS Screenplay Pattern APIs in your Playwright Test scenarios,
define your test scenarios using the describe
and it
functions
from @serenity-js/playwright-test
instead of @playwright/test
:
- import { describe, it, test } from '@playwright/test'
+ import { describe, it, test } from '@serenity-js/playwright-test'
That's it!
Serenity/JS Playwright Test module provides Playwright fixtures
that automatically configure all the actors injected
via actor
and
actorCalled
with abilities to BrowseTheWebWithPlaywright
and TakeNotes
.
import { describe, it } from '@serenity-js/playwright-test'
import { Navigate, PageElements, By } from '@serenity-js/web'
import { Ensure, equals } from '@serenity-js/assertions'
describe('Todo List', () => { // - feature or component name
const displayedItems = () =>
PageElements.located(By.css('.todo-list li'))
.describedAs('displayed items')
describe('when the user is', () => { // - one or more nested `describe` blocks
describe('a guest', () => { // to group scenarios
describe('their list', () => { // by context in which they apply
it('is empty', async ({ actor }) => { // - verify expected behaviour
await actor.attemptsTo( // using a default `actor`
Navigate.to('https://todo-app.serenity-js.org/'),
Ensure.that(displayedItems().count(), equals(0))
)
})
})
})
})
})
Configuring a custom cast of actorsโ
If you'd like to change the default settings, you can override the relevant configuration options
either in playwright.config.ts
, or in your test file, depending on the type of override you want to make.
For example, you can change the name given to the default actor and register a Photographer
service
in playwright.config.ts
(note the PlaywrightTestConfig
import from @serenity-js/playwright-test
instead of the default @playwright/test
):
import type { PlaywrightTestConfig } from '@serenity-js/playwright-test'
const config: PlaywrightTestConfig = {
use: {
defaultActorName: 'Tess',
crew: [
// [ '@serenity-js/web:Photographer', { strategy: 'TakePhotosOfFailures' } ]
[ '@serenity-js/web:Photographer', { strategy: 'TakePhotosOfInteractions' } ]
],
},
reporter: [
[ '@serenity-js/playwright-test', {
crew: [
'@serenity-js/console-reporter',
'@serenity-js/serenity-bdd',
[ '@serenity-js/core:ArtifactArchiver', { outputDirectory: 'target/site/serenity' } ],
]
}],
],
}
export default config
If you'd like to use a custom Cast
of actors instead of the default one,
you'll need to do that in a spec file as the ability to BrowseTheWebWithPlaywright
requires access
to Playwright browser
object, which the config file doesn't offer.
For example, you could define a custom Cast
where each actor gets their own browser,
but they share their notes:
import { describe, it, test } from '@serenity-js/playwright-test'
import { Cast, Notepad, TakeNotes, notes } from '@serenity-js/core'
import { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'
import { Navigate, PageElements, By } from '@serenity-js/web'
import { Ensure, equals } from '@serenity-js/assertions'
interface SharedNotes {
numberOfItemsThatAliceSaw: number
}
test.use({
actors: async ({ browser, contextOptions }, use) => {
const sharedNotepad = Notepad.empty<SharedNotes>();
const cast = Cast.where(actor => actor.whoCan(
BrowseTheWebWithPlaywright.using(browser, {
...contextOptions,
userAgent: `${ actor.name }`
}),
TakeNotes.using(sharedNotepad),
))
await use(cast)
},
})
describe('Todo List App', () => {
const displayedItems = () =>
PageElements.located(By.css('.todo-list li'))
.describedAs('displayed items')
it('support multiple users', async ({ actorCalled }) => {
// Alice and Bob use separate browser windows
await actorCalled('Alice').attemptsTo(
Navigate.to('https://todo-app.serenity-js.org/'),
notes<SharedNotes>().set('numberOfItemsThatAliceSaw', displayedItems().count())
)
// Bob doesn't have access to the browser that Alice uses,
// but he can access their shared notepad
await actorCalled('Bob').attemptsTo(
Ensure.that(notes<SharedNotes>().get('numberOfItemsThatAliceSaw'), equals(0)),
)
})
})