This is an example of a Playwright project that uses the page object model design pattern. In general, Playwright best practices are followed where possible and the configuration is largely the default configuration generated when you install Playwright.
The site under test is Acme Store, a demo ecommerce store built with Next.js, Vercel, and Shopify.
Previously, the site under test was Automation Exercise. This site was quite outdated and had random pop-up ads that would appear, which made it difficult to test. The Acme Store is far more mordern and a much better candidate for a Playwright boilerplate project in 2023.
pageObjects
├── base.page.ts
├── base.pageComponent.ts
├── pageFixture.ts
├── components
└── *.pageComponent.ts
└── pages
└── *.page.ts
This directory contains our base page class, base page component class, and all page object classes that extend those base classes.
base.page.ts
- The base page class is intended to include Locators and functionality that is shared across all pages. It takes a
Page
instance as a constructor parameter.
- The base page class is intended to include Locators and functionality that is shared across all pages. It takes a
base.pageComponent.ts
- I like to use page components to logically separate page elements that are common across multiple pages from pages themselves. This class takes a
Locator
parameter in addition to aPage
instance. Typically, page components are instantiated within other page classes, and not within the spec file itself. - You can see page components being instantiated in our home.page.ts file. These components can then be used in our tests in an easy-to-read format. See here.
- I like to use page components to logically separate page elements that are common across multiple pages from pages themselves. This class takes a
pageFixture.ts
- This is a fixture used to instantiate all of our page objects so they can be used across all of our tests, saving us the hassle of importing and instantiating them in every spec file. You can see how the page objects are passed into our test as parameters, which can then be used throughout the test.
I'm using the @axe-core/playwright
for accessibility testing in axe.spec.ts. These are failing miserably on the test site I'm using so they are currently skipped with the skip()
annotation.
I'm using Prettier for formatting. I've added an npm script to make excution simpler, although it's currently not tied to any automation. I just make sure to run this before checking in code.
I've made some changes to the default Github Actions workflow that Playwright generates.
Test execution takes place in a job called playwright_test.
-
I'm using Playwright's Docker container in Actions to avoid having to install browsers and system dependencies on each Actions run. The container version is grabbed from the Playwright version on the
node_modules
directory. -
I'm using Playwright's sharding feature to run the tests in parallel. See line 25 of the Actions workflow for the matrix configuration and line 64 for the step that runs the tests in parallel. Output from sharded tests is uploaded for use in the reporting job.
I'm using multiple methods of reporting here. Reporting tasks are done in a separate job that executes after all test shard execution has completed.
- Test results from sharded tests are combined into a single report and uploaded to Github Pages. See the badge at the top of this README for a link to the latest test report. I've added a step to automatically comment on the pull request with a link to the report.
- I'm also using dorny/test-reporter for displaying a test report within Actions itself. Here's what this report looks like. This is handy for getting a quick overview of test results and is easy to set up.
- Tesults is a third-party reporting service that has basic free accounts that are perfect for a boilerplate project like this (and I've also used the paid tiers in a professional setting with great success). They have a playwright-reporter npm package that works with very little configuration, but I took it a step further with a quick and dirty js script to automatically create targets in Tesults for new pull requests/branches. This script is used in our Actions file to set up a target for the current branch. Results are then posted to that target via the Tesults playwright-reporter. Similar to the Github Pages report, I've added a step to automatically comment on the pull request with a link to the report. You can see the dashboard for this project here at https://www.tesults.com/angelo-loria/acme-store-demo.
Upon a pull request being closed, the Tesults branch target is deleted via the same script with another Github Actions job. This is done to keep the number of targets in Tesults to a minimum on my free account.
I'm using the Google Lighthouse NPM package for performance and additional accessibility testing. The test setup and execution is a bit unique tests so I've separated them into their own spec file, they use a unique config file, and they are uploaded to Tesults separately from the other tests. See the directory here. I've added a specific script in the package.json file for executing these tests with their specific config file and running the tesults-lighthouse.js script afterwards. The script uses the Tesults npm package to upload the results to Tesults to a specific target that's set up with the results interpretation feature to display the individual Lighthouse scores for each page. It looks pretty slick. Tesults is hosting the Lighthouse HTML reports and they're uploaded as artifacts to Github Actions as well. Here's what one of those reports looks like.
The visual tests are done using Playwright's toHaveScreenshot(). I did have to come up with a way to regenerate them via Actions, which you can see in the workflows directory. This workflow uses Playwright's --update-snapshots
CLI command to generate the new snapshots and then commits them to the branch via stefanzweifel/git-auto-commit-action
.