Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.

Commit 28d55d9

Browse files
mvilanovaCopilot
andauthored
feat(playwright): optimizes playwright tests (#6153)
* feat(playwright): optimizes playwright tests * Update playwright.config.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Marc Vilanova <39573146+mvilanova@users.noreply.github.com> * Update playwright.config.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Marc Vilanova <39573146+mvilanova@users.noreply.github.com> * should-run-e2e flow * renames action * increases timeouts * fixes --------- Signed-off-by: Marc Vilanova <39573146+mvilanova@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 1a6e23a commit 28d55d9

4 files changed

Lines changed: 144 additions & 39 deletions

File tree

.github/workflows/enforce-labels.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ jobs:
99
steps:
1010
- uses: yogevbd/enforce-label-action@2.2.2
1111
with:
12-
REQUIRED_LABELS_ANY: "bug,dependencies,documentation,enhancement,feature,skip-changelog,techdebt,tests"
13-
REQUIRED_LABELS_ANY_DESCRIPTION: "Select at least one label from the following list: bug, dependencies, documentation, enhancement, feature, skip-changelog, techdebt, tests"
12+
REQUIRED_LABELS_ANY: "bug,dependencies,documentation,enhancement,feature,skip-changelog,skip-e2e,techdebt,tests"
13+
REQUIRED_LABELS_ANY_DESCRIPTION: "Select at least one label from the following list: bug, dependencies, documentation, enhancement, feature, skip-changelog, skip-e2e, techdebt, tests"
1414
BANNED_LABELS: "banned"

.github/workflows/playwright.yml

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,80 @@
1-
name: "playwright"
2-
on: # rebuild any PRs and main branch changes
1+
name: Playwright E2E Tests
2+
on:
33
pull_request:
4+
types: [opened, synchronize, reopened, ready_for_review]
45
push:
56
branches:
67
- main
78

89
env:
910
LOG_LEVEL: ERROR
10-
STATIC_DIR:
11+
STATIC_DIR: ""
1112
DATABASE_HOSTNAME: localhost
1213
DATABASE_CREDENTIALS: dispatch:dispatch
1314
DISPATCH_ENCRYPTION_KEY: NJHDWDJ3PbHT8h
1415
DISPATCH_JWT_SECRET: foo
1516

1617
jobs:
18+
# Job to determine if e2e tests should run
19+
should-run-e2e:
20+
runs-on: ubuntu-latest
21+
outputs:
22+
run-tests: ${{ steps.check.outputs.run-tests }}
23+
steps:
24+
- name: Check out Git repository
25+
uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Check if e2e tests should run
30+
id: check
31+
run: |
32+
# Skip if draft PR
33+
if [[ "${{ github.event.pull_request.draft }}" == "true" ]]; then
34+
echo "Skipping e2e tests: Draft PR"
35+
echo "run-tests=false" >> $GITHUB_OUTPUT
36+
exit 0
37+
fi
38+
39+
# Skip if only docs changed
40+
if git diff --name-only origin/${{ github.base_ref }}..HEAD | grep -v -E '^(docs/|.*\.md$|.*\.mdx$|LICENSE|.*\.txt$)' | wc -l | grep -q '^0$'; then
41+
echo "Skipping e2e tests: Documentation-only changes"
42+
echo "run-tests=false" >> $GITHUB_OUTPUT
43+
exit 0
44+
fi
45+
46+
# Skip if only backend tests changed
47+
if git diff --name-only origin/${{ github.base_ref }}..HEAD | grep -v -E '^(tests/(?!static/e2e)|.*test.*\.py$)' | wc -l | grep -q '^0$'; then
48+
echo "Skipping e2e tests: Test-only changes"
49+
echo "run-tests=false" >> $GITHUB_OUTPUT
50+
exit 0
51+
fi
52+
53+
# Skip if only backend-only changes (no frontend impact)
54+
if git diff --name-only origin/${{ github.base_ref }}..HEAD | grep -v -E '^(src/dispatch/(?!static)|tests/(?!static)|\.github/workflows/(?!playwright)|requirements.*\.txt|setup\.py|pyproject\.toml|\.python-version|Dockerfile|docker/)' | wc -l | grep -q '^0$'; then
55+
echo "Skipping e2e tests: Backend-only changes"
56+
echo "run-tests=false" >> $GITHUB_OUTPUT
57+
exit 0
58+
fi
59+
60+
# Skip if labeled with skip-e2e
61+
if echo '${{ toJson(github.event.pull_request.labels.*.name) }}' | grep -q 'skip-e2e'; then
62+
echo "Skipping e2e tests: skip-e2e label found"
63+
echo "run-tests=false" >> $GITHUB_OUTPUT
64+
exit 0
65+
fi
66+
67+
echo "Running e2e tests: Frontend or critical changes detected"
68+
echo "run-tests=true" >> $GITHUB_OUTPUT
69+
1770
end-to-end:
71+
needs: should-run-e2e
72+
if: needs.should-run-e2e.outputs.run-tests == 'true'
1873
runs-on: ubuntu-latest
74+
strategy:
75+
fail-fast: false
76+
matrix:
77+
shard: [1, 2, 3, 4]
1978
services:
2079
postgres:
2180
image: postgres
@@ -58,10 +117,29 @@ jobs:
58117
- name: Setup sample database
59118
run: dispatch database restore --dump-file data/dispatch-sample-data.dump --skip-check && dispatch database upgrade
60119
- name: Run tests
61-
run: npx playwright test --project=chromium
120+
run: npx playwright test --project=chromium --shard=${{ matrix.shard }}/4
62121
- uses: actions/upload-artifact@v4
63122
if: always()
64123
with:
65-
name: playwright-report
124+
name: playwright-report-shard-${{ matrix.shard }}
66125
path: playwright-report/
67126
retention-days: 30
127+
128+
# Summary job for required checks
129+
e2e-tests-complete:
130+
runs-on: ubuntu-latest
131+
needs: [should-run-e2e, end-to-end]
132+
if: always()
133+
steps:
134+
- name: Check e2e test results
135+
run: |
136+
if [[ "${{ needs.should-run-e2e.outputs.run-tests }}" == "false" ]]; then
137+
echo "✅ E2E tests skipped (not needed for this change)"
138+
exit 0
139+
elif [[ "${{ needs.end-to-end.result }}" == "success" ]]; then
140+
echo "✅ E2E tests passed"
141+
exit 0
142+
else
143+
echo "❌ E2E tests failed"
144+
exit 1
145+
fi

playwright.config.ts

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,52 +13,59 @@ const config: PlaywrightTestConfig = {
1313
/* Base URL to use in actions like `await page.goto('/')`. */
1414
baseURL: "http://localhost:8080/",
1515
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
16-
trace: "on",
17-
video: "on",
18-
screenshot: "on",
16+
trace: "retain-on-failure",
17+
video: "retain-on-failure",
18+
screenshot: "only-on-failure",
1919
},
2020
/* Maximum time one test can run for. */
21-
timeout: 200 * 1000,
21+
timeout: process.env.CI ? 200 * 1000 : 60 * 1000,
2222
expect: {
2323
/**
2424
* Maximum time expect() should wait for the condition to be met.
2525
* For example in `await expect(locator).toHaveText();`
2626
*/
27-
timeout: 20000,
27+
timeout: process.env.CI ? 20000 : 10000,
2828
},
2929
/* Run tests in files in parallel */
3030
fullyParallel: true,
3131
/* Fail the build on CI if you accidentally left test.only in the source code. */
3232
forbidOnly: !!process.env.CI,
3333
/* Retry on CI only */
3434
retries: process.env.CI ? 2 : 0,
35-
/* Opt out of parallel tests on CI. */
36-
workers: process.env.CI ? 1 : undefined,
35+
/* Optimize workers for CI - use more workers for faster execution */
36+
workers: process.env.CI ? 4 : undefined,
3737
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
38-
reporter: "html",
38+
reporter: process.env.CI ? [["html"], ["github"]] : "html",
3939
/* Configure projects for major browsers */
40-
projects: [
41-
{
42-
name: "chromium",
43-
use: {
44-
...devices["Desktop Chrome"],
45-
},
46-
},
47-
48-
{
49-
name: "firefox",
50-
use: {
51-
...devices["Desktop Firefox"],
52-
},
53-
},
54-
55-
{
56-
name: "webkit",
57-
use: {
58-
...devices["Desktop Safari"],
59-
},
60-
},
61-
],
40+
projects: process.env.CI
41+
? [
42+
{
43+
name: "chromium",
44+
use: {
45+
...devices["Desktop Chrome"],
46+
},
47+
},
48+
]
49+
: [
50+
{
51+
name: "chromium",
52+
use: {
53+
...devices["Desktop Chrome"],
54+
},
55+
},
56+
{
57+
name: "firefox",
58+
use: {
59+
...devices["Desktop Firefox"],
60+
},
61+
},
62+
{
63+
name: "webkit",
64+
use: {
65+
...devices["Desktop Safari"],
66+
},
67+
},
68+
],
6269
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
6370
// outputDir: 'test-results/',
6471

@@ -67,6 +74,8 @@ const config: PlaywrightTestConfig = {
6774
command: "dispatch server develop",
6875
url: "http://localhost:8080/",
6976
reuseExistingServer: !process.env.CI,
77+
/* Increase timeout to allow server to fully start and settle - especially important after removing the 2-minute wait from tests */
78+
timeout: 240 * 1000, // 4 minutes to ensure server is fully ready
7079
},
7180
}
7281

tests/static/e2e/pages/auth-page.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,27 @@ export class AuthPage {
5151
])
5252
}
5353

54+
/**
55+
* Wait for the application to be fully ready by checking that all necessary elements are loaded
56+
* and the page is stable. This replaces the previous 2-minute static wait.
57+
*/
58+
async waitForAppReady() {
59+
// Wait for the page to be loaded and interactive
60+
await this.page.waitForLoadState("networkidle")
61+
62+
// Additional wait to ensure any background initialization is complete
63+
// This is much shorter than the previous 2-minute wait but ensures stability
64+
await this.page.waitForTimeout(5000)
65+
66+
// Verify the basic UI elements are working by ensuring we can navigate to login
67+
await this.page.goto(this.loginRoute, { waitUntil: "networkidle" })
68+
await expect(this.loginHeader).toBeVisible()
69+
}
70+
5471
async registerNewUser(email: string, password: string) {
55-
// wait for 2 minutes to let server settle
56-
await new Promise(resolve => setTimeout(resolve, 120000));
72+
// Ensure the application is ready before attempting registration
73+
await this.waitForAppReady()
74+
5775
await this.gotoRegisterWithLink()
5876
await this.emailLabel.first().click()
5977
await this.emailLabel.fill(email)

0 commit comments

Comments
 (0)