Playwright
Overview
This document guides you through the steps required to run Playwright tests using Signadot's Continuous Testing (CT) feature.
Running Tests as a Signadot Job
Running a test as a Signadot Job provides context awareness, meaning that if the sandbox referenced in the test is terminated, closed, or in any other failed state, the test will automatically fail. This makes the tests more reliable.
Create Job Runner Group
To start with Signadot CT, we need to create a Job Runner Group
name: playwright
spec:
cluster: "@{cluster}"
labels:
env: "@{env}"
namespace: <namespace where run tests>
jobTimeout: 30m
image: mcr.microsoft.com/playwright:v1.45.1-jammy
scaling:
manual:
desiredPods: 1
Create Job Specification
spec:
namePrefix: playwright-e2e
runnerGroup: playwright
script: |
#!/bin/bash
set -e
# Clone the git repo
echo "Cloning repo"
git clone --single-branch -b "@{branch}" \
https://github.com/<org>/<repo>.git
# Run all playwright tests
cd <repo>
export CI=true
npm ci
set +e
npm run e2e:playwright # Change with your corresponding npm command or npx playwright test
E2E_EXIT_CODE=$?
set -e
# Compress the playwright-report directory so that it can be uploaded as a single artifact.
tar czf playwright-report.tar.gz playwright-report
exit $E2E_EXIT_CODE
routingContext:
sandbox: "@{sandbox}"
uploadArtifact:
- path: <repo>/playwright-report.tar.gz
There a few things to note in that code snippet
1. Exit code handling
set +e
npm run e2e:playwright # Change with your corresponding npm command or npx playwright test
E2E_EXIT_CODE=$?
set -e
... more script
exit $E2E_EXIT_CODE
If you want to make sure the job doesn't terminate when the tests fail, we are saving the exit code and then returning it at the very end.
2. Report
As of now, directory upload is not supported. So we are compressing the playwright-report directory so that all the artifacts are available as a single file.
Set Up Routing Context
There are some use cases where we need to run tests against specific Sandboxes, so we need to rely on some routing context. We could use the preview url, but there are some situations where it would be better to use simply the routing key. For the Playwright integration, we have two options:
Using Playwright config
We can use the Playwright config, and set the extraHTTPHeaders in the browsers or test settings.
For example:
extraHTTPHeaders: {
baggage: `sd-routing-key=${process.env.SIGNADOT_ROUTING_KEY}`
}
The resulting config will be something similar to:
import { defineConfig, devices } from "@playwright/test";
const BASE_URL = 'https://yourwebsite.com';
export default defineConfig({
testDir: "./playwright-tests",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 0 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [["html", { open: "never" }]],
use: {
baseURL: BASE_URL,
trace: "on",
video: "on",
extraHTTPHeaders: {
baggage: `sd-routing-key=${process.env.SIGNADOT_ROUTING_KEY}`,
},
},
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
baseURL: BASE_URL,
},
},
],
});
Using Playwright route
In others cases we may need to apply the Routing Key to specific routes, we can do this by using page.route. Which allows to mutate the request before is executed.
For example
await page.route(
(url: URL) => {
// Only add the routing key if the url contains mydomain.com
return url.href.includes("mydomain.com");
},
async (route, request) => {
const headers = await request.allHeaders();
// You can also use previous headers.baggage if need to
await route.continue({
headers: {
...headers,
baggage: `sd-routing-key=${routingKey}`,
},
});
}
);