@andwhy/e2e-pipeline 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -0
- package/dist/bin/init.d.ts +2 -0
- package/dist/bin/init.js +128 -0
- package/dist/utils/copy.d.ts +23 -0
- package/dist/utils/copy.js +249 -0
- package/dist/utils/format.d.ts +1 -0
- package/dist/utils/format.js +49 -0
- package/dist/utils/install.d.ts +2 -0
- package/dist/utils/install.js +54 -0
- package/dist/utils/prompt.d.ts +2 -0
- package/dist/utils/prompt.js +17 -0
- package/package.json +37 -0
- package/templates/claude/agents/playwright-test-generator.md +184 -0
- package/templates/claude/agents/playwright-test-healer.md +70 -0
- package/templates/claude/agents/playwright-test-planner.md +135 -0
- package/templates/claude/partials/_robustness-core.md +69 -0
- package/templates/claude/rules/playwright-workflow.md +203 -0
- package/templates/claude/skills/playwright-test-pipeline/SKILL.md +201 -0
- package/templates/github/scripts/playwright-pr-comment.mjs +95 -0
- package/templates/github/workflows/checkly-deploy.yml +64 -0
- package/templates/github/workflows/pr-playwright-tests.yml +154 -0
- package/templates/shared/checkly.config.template.mjs +58 -0
- package/templates/shared/checkly.config.template.ts +58 -0
- package/templates/shared/playwright.config.template.mjs +44 -0
- package/templates/shared/playwright.config.template.ts +44 -0
- package/templates/shared/playwright.mcp.config.template.mjs +12 -0
- package/templates/shared/playwright.mcp.config.template.ts +12 -0
- package/templates/shared/preview-consent-setup.template.js +32 -0
- package/templates/shared/preview-consent-setup.template.ts +33 -0
- package/templates/shared/seed.spec.js +5 -0
- package/templates/shared/seed.spec.ts +5 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
name: PR Playwright tests
|
|
2
|
+
|
|
3
|
+
# Runs the suite against the PR's own Vercel preview. `deployment_status`
|
|
4
|
+
# fires once the preview is live and carries its URL; the preview is built
|
|
5
|
+
# from the PR branch, so the PR's changes exist on the target.
|
|
6
|
+
# Needs repo secret VERCEL_AUTOMATION_BYPASS_SECRET when previews are
|
|
7
|
+
# protected; the scaffolded helper turns it into Vercel's bypass cookie.
|
|
8
|
+
on:
|
|
9
|
+
deployment_status
|
|
10
|
+
|
|
11
|
+
# Vercel's payload has no branch, only the SHA — the job below resolves it.
|
|
12
|
+
run-name: Playwright · ${{ github.event.deployment.environment }}
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
pull-requests: write
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
resolve-branch:
|
|
20
|
+
if: >-
|
|
21
|
+
github.event.deployment_status.state == 'success' &&
|
|
22
|
+
github.event.deployment.environment == 'Preview'
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 2
|
|
25
|
+
outputs:
|
|
26
|
+
branch: ${{ steps.pr.outputs.branch }}
|
|
27
|
+
label: ${{ steps.pr.outputs.label }}
|
|
28
|
+
number: ${{ steps.pr.outputs.number }}
|
|
29
|
+
steps:
|
|
30
|
+
- name: Resolve the PR branch for this commit
|
|
31
|
+
id: pr
|
|
32
|
+
env:
|
|
33
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
34
|
+
SHA: ${{ github.event.deployment.ref }}
|
|
35
|
+
REPO: ${{ github.repository }}
|
|
36
|
+
run: |
|
|
37
|
+
# No associated PR (plain branch push) falls back to the SHA.
|
|
38
|
+
pr=$(gh api "repos/$REPO/commits/$SHA/pulls" --jq \
|
|
39
|
+
'if length > 0 then "\(.[0].number)\t\(.[0].head.ref)\t\(.[0].title)" else "" end' \
|
|
40
|
+
2>/dev/null || true)
|
|
41
|
+
branch=$(printf '%s' "$pr" | cut -f2)
|
|
42
|
+
number=$(printf '%s' "$pr" | cut -f1)
|
|
43
|
+
title=$(printf '%s' "$pr" | cut -f3)
|
|
44
|
+
|
|
45
|
+
echo "branch=${branch:-$SHA}" >> "$GITHUB_OUTPUT"
|
|
46
|
+
echo "number=${number}" >> "$GITHUB_OUTPUT"
|
|
47
|
+
if [ -n "$number" ]; then
|
|
48
|
+
echo "label=#${number} ${title}" >> "$GITHUB_OUTPUT"
|
|
49
|
+
else
|
|
50
|
+
echo "label=${branch:-$SHA}" >> "$GITHUB_OUTPUT"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
playwright:
|
|
54
|
+
name: Playwright · ${{ needs.resolve-branch.outputs.label }}
|
|
55
|
+
needs: resolve-branch
|
|
56
|
+
# A re-push cancels the stale run instead of racing an outdated preview.
|
|
57
|
+
concurrency:
|
|
58
|
+
group: pr-playwright-${{ needs.resolve-branch.outputs.branch }}
|
|
59
|
+
cancel-in-progress: true
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
# Red informs, branch protection decides — the check is not required.
|
|
62
|
+
timeout-minutes: 10
|
|
63
|
+
|
|
64
|
+
steps:
|
|
65
|
+
- name: Check out the deployed ref
|
|
66
|
+
uses: actions/checkout@v5
|
|
67
|
+
with:
|
|
68
|
+
ref: ${{ github.event.deployment.ref }}
|
|
69
|
+
|
|
70
|
+
- name: Set up pnpm
|
|
71
|
+
uses: pnpm/action-setup@v4
|
|
72
|
+
|
|
73
|
+
- name: Set up Node
|
|
74
|
+
uses: actions/setup-node@v5
|
|
75
|
+
with:
|
|
76
|
+
node-version: 22
|
|
77
|
+
cache: pnpm
|
|
78
|
+
|
|
79
|
+
# --ignore-scripts: only the tests run here; project postinstall hooks
|
|
80
|
+
# are not needed and may want CMS tokens CI does not have.
|
|
81
|
+
- name: Install dependencies
|
|
82
|
+
run: pnpm install --frozen-lockfile --ignore-scripts
|
|
83
|
+
|
|
84
|
+
- name: Install Playwright browsers
|
|
85
|
+
run: pnpm playwright install --with-deps chromium
|
|
86
|
+
|
|
87
|
+
# Chrome only for speed; Firefox/Edge run on Checkly against production.
|
|
88
|
+
# --global-timeout instead of a step timeout so reports still flush.
|
|
89
|
+
- name: Run Playwright tests against the preview
|
|
90
|
+
id: tests
|
|
91
|
+
timeout-minutes: 9
|
|
92
|
+
env:
|
|
93
|
+
BASE_URL: ${{ github.event.deployment_status.target_url }}
|
|
94
|
+
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
|
|
95
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME: playwright-results.json
|
|
96
|
+
run: |
|
|
97
|
+
pnpm playwright test \
|
|
98
|
+
--project=Chrome \
|
|
99
|
+
--global-timeout 360000 \
|
|
100
|
+
--reporter=list,html,json
|
|
101
|
+
|
|
102
|
+
- name: Upload HTML report
|
|
103
|
+
if: always()
|
|
104
|
+
uses: actions/upload-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: playwright-report-${{ github.run_id }}
|
|
107
|
+
path: |
|
|
108
|
+
playwright-report/
|
|
109
|
+
playwright-results.json
|
|
110
|
+
if-no-files-found: warn
|
|
111
|
+
retention-days: 7
|
|
112
|
+
|
|
113
|
+
# Reporting only — must not turn the check red.
|
|
114
|
+
- name: Comment the result on the PR
|
|
115
|
+
if: always() && needs.resolve-branch.outputs.number != ''
|
|
116
|
+
continue-on-error: true
|
|
117
|
+
env:
|
|
118
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
119
|
+
REPO: ${{ github.repository }}
|
|
120
|
+
PR: ${{ needs.resolve-branch.outputs.number }}
|
|
121
|
+
PREVIEW_URL: ${{ github.event.deployment_status.target_url }}
|
|
122
|
+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
123
|
+
run: |
|
|
124
|
+
node .github/scripts/playwright-pr-comment.mjs \
|
|
125
|
+
playwright-results.json > comment.md
|
|
126
|
+
|
|
127
|
+
# Update the existing comment so re-pushes do not stack.
|
|
128
|
+
marker='<!-- playwright-preview-report -->'
|
|
129
|
+
id=$(gh api "repos/$REPO/issues/$PR/comments" --paginate \
|
|
130
|
+
--jq "map(select(.body | startswith(\"$marker\"))) | .[0].id // empty")
|
|
131
|
+
|
|
132
|
+
if [ -n "$id" ]; then
|
|
133
|
+
gh api -X PATCH "repos/$REPO/issues/comments/$id" -F body=@comment.md
|
|
134
|
+
else
|
|
135
|
+
gh api -X POST "repos/$REPO/issues/$PR/comments" -F body=@comment.md
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
- name: Write result to job summary
|
|
139
|
+
if: always()
|
|
140
|
+
env:
|
|
141
|
+
OUTCOME: ${{ steps.tests.outcome }}
|
|
142
|
+
PREVIEW_URL: ${{ github.event.deployment_status.target_url }}
|
|
143
|
+
run: |
|
|
144
|
+
{
|
|
145
|
+
echo "## Playwright (preview)"
|
|
146
|
+
echo ""
|
|
147
|
+
echo "- Target: $PREVIEW_URL"
|
|
148
|
+
echo "- Browser: Chrome only"
|
|
149
|
+
if [ "$OUTCOME" = "success" ]; then
|
|
150
|
+
echo "- Result: all tests passed"
|
|
151
|
+
else
|
|
152
|
+
echo "- Result: **failures present** — see the uploaded \`playwright-report\` artifact"
|
|
153
|
+
fi
|
|
154
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineConfig } from "checkly";
|
|
2
|
+
|
|
3
|
+
// -- Multi-domain example (uncomment and adapt) --
|
|
4
|
+
// const domains = [
|
|
5
|
+
// { name: "example.com", url: "https://example.com" },
|
|
6
|
+
// { name: "example.de", url: "https://example.de" },
|
|
7
|
+
// ]
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* See https://www.checklyhq.com/docs/cli/project-structure/
|
|
11
|
+
*/
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
projectName: "my-app",
|
|
14
|
+
/** A logical ID that needs to be unique across your Checkly account.
|
|
15
|
+
* See https://www.checklyhq.com/docs/cli/constructs/
|
|
16
|
+
*/
|
|
17
|
+
logicalId: "my-app",
|
|
18
|
+
repoUrl: "https://github.com/your-org/your-repo",
|
|
19
|
+
checks: {
|
|
20
|
+
frequency: 180,
|
|
21
|
+
locations: ["eu-central-1"],
|
|
22
|
+
runtimeId: "2025.04",
|
|
23
|
+
playwrightConfigPath: "./playwright.config.mjs",
|
|
24
|
+
playwrightChecks: [
|
|
25
|
+
{
|
|
26
|
+
logicalId: "my-app-check-suite",
|
|
27
|
+
// Change the name to match your brand or product.
|
|
28
|
+
name: "my-app",
|
|
29
|
+
// Checkly's runner gets a bundle of test files, not the repo, so a
|
|
30
|
+
// project postinstall (codegen etc.) fails there on missing files.
|
|
31
|
+
// pnpm 10 skips dependency build scripts by default, so this only
|
|
32
|
+
// disables the project's own hooks; browsers come from the runtime.
|
|
33
|
+
installCommand: "pnpm install --ignore-scripts",
|
|
34
|
+
// Deploy only the e2e suite as monitors. Without this the whole
|
|
35
|
+
// Playwright suite runs per domain, so unit tests and regression
|
|
36
|
+
// guards that never needed a deployment become recurring paid checks.
|
|
37
|
+
testCommand: "npx playwright test tests/e2e",
|
|
38
|
+
environmentVariables: [
|
|
39
|
+
// Set this to your production URL.
|
|
40
|
+
{ key: "BASE_URL", value: "http://localhost:3000" },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
// Add more suites for additional domains:
|
|
44
|
+
// {
|
|
45
|
+
// logicalId: "my-app-check-suite-de",
|
|
46
|
+
// name: "my-app (DE)",
|
|
47
|
+
// environmentVariables: [
|
|
48
|
+
// { key: "BASE_URL", value: "https://example.de" },
|
|
49
|
+
// ],
|
|
50
|
+
// },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
cli: {
|
|
54
|
+
runLocation: "eu-west-1",
|
|
55
|
+
reporters: ["list"],
|
|
56
|
+
retries: 1,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineConfig } from "checkly";
|
|
2
|
+
|
|
3
|
+
// -- Multi-domain example (uncomment and adapt) --
|
|
4
|
+
// const domains = [
|
|
5
|
+
// { name: "example.com", url: "https://example.com" },
|
|
6
|
+
// { name: "example.de", url: "https://example.de" },
|
|
7
|
+
// ]
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* See https://www.checklyhq.com/docs/cli/project-structure/
|
|
11
|
+
*/
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
projectName: "my-app",
|
|
14
|
+
/** A logical ID that needs to be unique across your Checkly account.
|
|
15
|
+
* See https://www.checklyhq.com/docs/cli/constructs/
|
|
16
|
+
*/
|
|
17
|
+
logicalId: "my-app",
|
|
18
|
+
repoUrl: "https://github.com/your-org/your-repo",
|
|
19
|
+
checks: {
|
|
20
|
+
frequency: 180,
|
|
21
|
+
locations: ["eu-central-1"],
|
|
22
|
+
runtimeId: "2025.04",
|
|
23
|
+
playwrightConfigPath: "./playwright.config.ts",
|
|
24
|
+
playwrightChecks: [
|
|
25
|
+
{
|
|
26
|
+
logicalId: "my-app-check-suite",
|
|
27
|
+
// Change the name to match your brand or product.
|
|
28
|
+
name: "my-app",
|
|
29
|
+
// Checkly's runner gets a bundle of test files, not the repo, so a
|
|
30
|
+
// project postinstall (codegen etc.) fails there on missing files.
|
|
31
|
+
// pnpm 10 skips dependency build scripts by default, so this only
|
|
32
|
+
// disables the project's own hooks; browsers come from the runtime.
|
|
33
|
+
installCommand: "pnpm install --ignore-scripts",
|
|
34
|
+
// Deploy only the e2e suite as monitors. Without this the whole
|
|
35
|
+
// Playwright suite runs per domain, so unit tests and regression
|
|
36
|
+
// guards that never needed a deployment become recurring paid checks.
|
|
37
|
+
testCommand: "npx playwright test tests/e2e",
|
|
38
|
+
environmentVariables: [
|
|
39
|
+
// Set this to your production URL.
|
|
40
|
+
{ key: "BASE_URL", value: "http://localhost:3000" },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
// Add more suites for additional domains:
|
|
44
|
+
// {
|
|
45
|
+
// logicalId: "my-app-check-suite-de",
|
|
46
|
+
// name: "my-app (DE)",
|
|
47
|
+
// environmentVariables: [
|
|
48
|
+
// { key: "BASE_URL", value: "https://example.de" },
|
|
49
|
+
// ],
|
|
50
|
+
// },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
cli: {
|
|
54
|
+
runLocation: "eu-west-1",
|
|
55
|
+
reporters: ["list"],
|
|
56
|
+
retries: 1,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
// e2e specs live here so other suites elsewhere under tests/ are not picked
|
|
5
|
+
// up. If the repo already has such a suite (unit, a11y), give it its own
|
|
6
|
+
// project below with its own testDir — do NOT widen this one to ./tests,
|
|
7
|
+
// which would run that suite in every browser project and mix the suites.
|
|
8
|
+
testDir: "./tests/e2e",
|
|
9
|
+
// Seeds are run directly by the Playwright MCP, not as tests of their own.
|
|
10
|
+
testIgnore: "**/seed.spec.*",
|
|
11
|
+
fullyParallel: true,
|
|
12
|
+
forbidOnly: !!process.env.CI,
|
|
13
|
+
retries: process.env.CI ? 2 : 0,
|
|
14
|
+
workers: process.env.CI ? 1 : undefined,
|
|
15
|
+
reporter: "html",
|
|
16
|
+
use: {
|
|
17
|
+
baseURL: process.env.BASE_URL ?? "http://localhost:3000",
|
|
18
|
+
trace: "on",
|
|
19
|
+
},
|
|
20
|
+
projects: [
|
|
21
|
+
{
|
|
22
|
+
name: "Chrome",
|
|
23
|
+
use: {
|
|
24
|
+
...devices["Desktop Chrome"],
|
|
25
|
+
userAgent: "Chrome_Checkly_0759687ceba6",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Firefox",
|
|
30
|
+
use: {
|
|
31
|
+
...devices["Desktop Firefox"],
|
|
32
|
+
userAgent: "Firefox_Checkly_0759687ceba6",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "Edge",
|
|
37
|
+
use: {
|
|
38
|
+
...devices["Desktop Edge"],
|
|
39
|
+
userAgent: "Edge_Checkly_0759687ceba6",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
timeout: 60_000,
|
|
44
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
// e2e specs live here so other suites elsewhere under tests/ are not picked
|
|
5
|
+
// up. If the repo already has such a suite (unit, a11y), give it its own
|
|
6
|
+
// project below with its own testDir — do NOT widen this one to ./tests,
|
|
7
|
+
// which would run that suite in every browser project and mix the suites.
|
|
8
|
+
testDir: "./tests/e2e",
|
|
9
|
+
// Seeds are run directly by the Playwright MCP, not as tests of their own.
|
|
10
|
+
testIgnore: "**/seed.spec.*",
|
|
11
|
+
fullyParallel: true,
|
|
12
|
+
forbidOnly: !!process.env.CI,
|
|
13
|
+
retries: process.env.CI ? 2 : 0,
|
|
14
|
+
workers: process.env.CI ? 1 : undefined,
|
|
15
|
+
reporter: "html",
|
|
16
|
+
use: {
|
|
17
|
+
baseURL: process.env.BASE_URL ?? "http://localhost:3000",
|
|
18
|
+
trace: "on",
|
|
19
|
+
},
|
|
20
|
+
projects: [
|
|
21
|
+
{
|
|
22
|
+
name: "Chrome",
|
|
23
|
+
use: {
|
|
24
|
+
...devices["Desktop Chrome"],
|
|
25
|
+
userAgent: "Chrome_Checkly_0759687ceba6",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Firefox",
|
|
30
|
+
use: {
|
|
31
|
+
...devices["Desktop Firefox"],
|
|
32
|
+
userAgent: "Firefox_Checkly_0759687ceba6",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "Edge",
|
|
37
|
+
use: {
|
|
38
|
+
...devices["Desktop Edge"],
|
|
39
|
+
userAgent: "Edge_Checkly_0759687ceba6",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
timeout: 60_000,
|
|
44
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "@playwright/test";
|
|
2
|
+
import config from "./playwright.config.mjs";
|
|
3
|
+
|
|
4
|
+
// Used only by the Playwright MCP server — .mcp.json points here, nothing else
|
|
5
|
+
// does. The main config ignores seed.spec.* so seeds never run as tests in
|
|
6
|
+
// local, CI, or Checkly runs; but the planner/generator setup_page tools
|
|
7
|
+
// execute seeds through the test runner, so the MCP's config must be able to
|
|
8
|
+
// discover them. Do not point CI or Checkly at this file.
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
...config,
|
|
11
|
+
testIgnore: [],
|
|
12
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "@playwright/test";
|
|
2
|
+
import config from "./playwright.config";
|
|
3
|
+
|
|
4
|
+
// Used only by the Playwright MCP server — .mcp.json points here, nothing else
|
|
5
|
+
// does. The main config ignores seed.spec.* so seeds never run as tests in
|
|
6
|
+
// local, CI, or Checkly runs; but the planner/generator setup_page tools
|
|
7
|
+
// execute seeds through the test runner, so the MCP's config must be able to
|
|
8
|
+
// discover them. Do not point CI or Checkly at this file.
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
...config,
|
|
11
|
+
testIgnore: [],
|
|
12
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
// Vercel deployment protection returns 401 for anonymous visitors, which is
|
|
3
|
+
// what Checkly's runners are. With the project's automation bypass secret in
|
|
4
|
+
// VERCEL_AUTOMATION_BYPASS_SECRET (Vercel project settings → Deployment
|
|
5
|
+
// Protection; keep the value in 1Password and pass it per run:
|
|
6
|
+
// pnpm checkly pw-test --env BASE_URL="<preview>" \
|
|
7
|
+
// --env VERCEL_AUTOMATION_BYPASS_SECRET="<secret>" -- tests/e2e/<feature>/
|
|
8
|
+
// ) the first navigation exchanges the secret for Vercel's bypass cookie and
|
|
9
|
+
// the rest of the test uses plain relative URLs. Without the secret this is a
|
|
10
|
+
// plain goto, so the same specs run unchanged against localhost and production.
|
|
11
|
+
// Never commit the secret into checkly.config — deployed monitors run against
|
|
12
|
+
// production and do not need it.
|
|
13
|
+
export const prepareVercelPreviewPage = async (page, baseURL) => {
|
|
14
|
+
const secret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
15
|
+
if (secret) {
|
|
16
|
+
await page.context().setExtraHTTPHeaders({
|
|
17
|
+
"x-vercel-protection-bypass": secret,
|
|
18
|
+
"x-vercel-set-bypass-cookie": "true",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
await page.goto(baseURL ?? "/");
|
|
22
|
+
if (secret) {
|
|
23
|
+
// The bypass cookie is set now. Stop sending the secret with every
|
|
24
|
+
// request — extraHTTPHeaders are context-wide and would carry it to
|
|
25
|
+
// third-party origins too.
|
|
26
|
+
await page.context().setExtraHTTPHeaders({});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Projects extend this file with their own consent helpers, e.g.
|
|
31
|
+
// gotoPathAndAcceptCookies(page, baseURL, path) for the local cookie banner —
|
|
32
|
+
// that part is CMP-specific and stays project-owned.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
// Vercel deployment protection returns 401 for anonymous visitors, which is
|
|
4
|
+
// what Checkly's runners are. With the project's automation bypass secret in
|
|
5
|
+
// VERCEL_AUTOMATION_BYPASS_SECRET (Vercel project settings → Deployment
|
|
6
|
+
// Protection; keep the value in 1Password and pass it per run:
|
|
7
|
+
// pnpm checkly pw-test --env BASE_URL="<preview>" \
|
|
8
|
+
// --env VERCEL_AUTOMATION_BYPASS_SECRET="<secret>" -- tests/e2e/<feature>/
|
|
9
|
+
// ) the first navigation exchanges the secret for Vercel's bypass cookie and
|
|
10
|
+
// the rest of the test uses plain relative URLs. Without the secret this is a
|
|
11
|
+
// plain goto, so the same specs run unchanged against localhost and production.
|
|
12
|
+
// Never commit the secret into checkly.config — deployed monitors run against
|
|
13
|
+
// production and do not need it.
|
|
14
|
+
export const prepareVercelPreviewPage = async (page: Page, baseURL?: string) => {
|
|
15
|
+
const secret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
16
|
+
if (secret) {
|
|
17
|
+
await page.context().setExtraHTTPHeaders({
|
|
18
|
+
"x-vercel-protection-bypass": secret,
|
|
19
|
+
"x-vercel-set-bypass-cookie": "true",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
await page.goto(baseURL ?? "/");
|
|
23
|
+
if (secret) {
|
|
24
|
+
// The bypass cookie is set now. Stop sending the secret with every
|
|
25
|
+
// request — extraHTTPHeaders are context-wide and would carry it to
|
|
26
|
+
// third-party origins too.
|
|
27
|
+
await page.context().setExtraHTTPHeaders({});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Projects extend this file with their own consent helpers, e.g.
|
|
32
|
+
// gotoPathAndAcceptCookies(page, baseURL, path) for the local cookie banner —
|
|
33
|
+
// that part is CMP-specific and stays project-owned.
|