@andwhy/e2e-pipeline 0.15.1 → 0.15.3
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/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/playwright-test-generator.md +3 -2
- package/plugin/agents/playwright-test-healer.md +3 -2
- package/plugin/skills/playwright-test-pipeline/SKILL.md +4 -3
- package/templates/claude/partials/_robustness-core.md +3 -2
- package/templates/github/scripts/playwright-pr-comment.mjs +35 -2
- package/templates/github/workflows/pr-playwright-tests.yml +4 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andwhy/e2e-pipeline",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "Scaffolds the full e2e testing pipeline: agent-assisted Playwright tests, CI runs against Vercel previews, and Checkly monitors that follow production deploys",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "e2e-pipeline",
|
|
3
3
|
"displayName": "&why e2e pipeline",
|
|
4
|
-
"version": "0.15.
|
|
4
|
+
"version": "0.15.3",
|
|
5
5
|
"description": "Agent-assisted Playwright e2e tests: planner, generator and healer agents plus the playwright-test-pipeline skill that drives Plan → Generate → Heal, Checkly preview validation and deployment.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "&why",
|
|
@@ -133,7 +133,8 @@ Follow these when writing tests to prevent flaky-test and cross-environment fail
|
|
|
133
133
|
exact-match lookup silently skips the entire suite on every PR run and in
|
|
134
134
|
`checkly pw-test` — green checks that tested nothing. The lookup must resolve preview
|
|
135
135
|
hosts to the config of the production domain the preview serves (ask the user which one
|
|
136
|
-
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime
|
|
136
|
+
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime, and CI may pass it
|
|
137
|
+
empty, so fall back with `||`, never `??`):
|
|
137
138
|
|
|
138
139
|
```ts
|
|
139
140
|
const getLocaleConfig = (baseURL: string) => {
|
|
@@ -142,7 +143,7 @@ Follow these when writing tests to prevent flaky-test and cross-environment fail
|
|
|
142
143
|
if (config) return config;
|
|
143
144
|
// Previews serve <primary domain>'s content; without this every preview run skips.
|
|
144
145
|
if (hostname.endsWith(".vercel.app"))
|
|
145
|
-
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST
|
|
146
|
+
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST || "<primary domain>"];
|
|
146
147
|
return undefined;
|
|
147
148
|
};
|
|
148
149
|
```
|
|
@@ -130,7 +130,8 @@ Robustness rules (apply these BEFORE increasing timeouts or adding retries):
|
|
|
130
130
|
exact-match lookup silently skips the entire suite on every PR run and in
|
|
131
131
|
`checkly pw-test` — green checks that tested nothing. The lookup must resolve preview
|
|
132
132
|
hosts to the config of the production domain the preview serves (ask the user which one
|
|
133
|
-
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime
|
|
133
|
+
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime, and CI may pass it
|
|
134
|
+
empty, so fall back with `||`, never `??`):
|
|
134
135
|
|
|
135
136
|
```ts
|
|
136
137
|
const getLocaleConfig = (baseURL: string) => {
|
|
@@ -139,7 +140,7 @@ Robustness rules (apply these BEFORE increasing timeouts or adding retries):
|
|
|
139
140
|
if (config) return config;
|
|
140
141
|
// Previews serve <primary domain>'s content; without this every preview run skips.
|
|
141
142
|
if (hostname.endsWith(".vercel.app"))
|
|
142
|
-
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST
|
|
143
|
+
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST || "<primary domain>"];
|
|
143
144
|
return undefined;
|
|
144
145
|
};
|
|
145
146
|
```
|
|
@@ -7,7 +7,7 @@ description: Guides the full workflow for creating and maintaining Playwright
|
|
|
7
7
|
tests, asks to "test" a page/feature/flow, or asks how the test pipeline
|
|
8
8
|
works.
|
|
9
9
|
metadata:
|
|
10
|
-
version: "0.15.
|
|
10
|
+
version: "0.15.3"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Playwright Test Pipeline
|
|
@@ -200,8 +200,9 @@ Include them verbatim in every Agent prompt to the generator or healer.
|
|
|
200
200
|
4. Never hardcode a single locale's URL pattern. Use a locale config map keyed
|
|
201
201
|
by bare hostname and resolve at runtime. Preview hosts (`*.vercel.app`) are
|
|
202
202
|
never in the map and must fall back to the primary production domain's
|
|
203
|
-
config (overridable via `PREVIEW_LOCALE_HOST
|
|
204
|
-
skips the whole suite on
|
|
203
|
+
config (overridable via `PREVIEW_LOCALE_HOST`, read with `||` so an empty
|
|
204
|
+
value falls back too) — an exact-match-only lookup skips the whole suite on
|
|
205
|
+
every PR run.
|
|
205
206
|
|
|
206
207
|
5. After all tests pass locally, verify with
|
|
207
208
|
`BASE_URL=<dev-url> pnpm playwright test` via the terminal tool. If failures
|
|
@@ -72,7 +72,8 @@
|
|
|
72
72
|
exact-match lookup silently skips the entire suite on every PR run and in
|
|
73
73
|
`checkly pw-test` — green checks that tested nothing. The lookup must resolve preview
|
|
74
74
|
hosts to the config of the production domain the preview serves (ask the user which one
|
|
75
|
-
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime
|
|
75
|
+
if it isn't obvious; `PREVIEW_LOCALE_HOST` overrides it at runtime, and CI may pass it
|
|
76
|
+
empty, so fall back with `||`, never `??`):
|
|
76
77
|
|
|
77
78
|
```ts
|
|
78
79
|
const getLocaleConfig = (baseURL: string) => {
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
if (config) return config;
|
|
82
83
|
// Previews serve <primary domain>'s content; without this every preview run skips.
|
|
83
84
|
if (hostname.endsWith(".vercel.app"))
|
|
84
|
-
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST
|
|
85
|
+
return LOCALE_CONFIG[process.env.PREVIEW_LOCALE_HOST || "<primary domain>"];
|
|
85
86
|
return undefined;
|
|
86
87
|
};
|
|
87
88
|
```
|
|
@@ -13,6 +13,24 @@ const clean = text =>
|
|
|
13
13
|
.replace(/\u001b\[[0-9;]*m/g, '')
|
|
14
14
|
.trim()
|
|
15
15
|
|
|
16
|
+
// Skip reasons with counts. A skipped test proves nothing, so a run that
|
|
17
|
+
// skips must say why instead of reading as a pass.
|
|
18
|
+
const skipReasons = (suite, acc = new Map()) => {
|
|
19
|
+
for (const spec of suite.specs ?? []) {
|
|
20
|
+
for (const test of spec.tests ?? []) {
|
|
21
|
+
const last = test.results?.[test.results.length - 1]
|
|
22
|
+
if (last?.status !== 'skipped') continue
|
|
23
|
+
const note = [...(test.annotations ?? []), ...(last.annotations ?? [])].find(
|
|
24
|
+
a => a.type === 'skip'
|
|
25
|
+
)
|
|
26
|
+
const reason = clean(note?.description) || 'no reason given'
|
|
27
|
+
acc.set(reason, (acc.get(reason) ?? 0) + 1)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const child of suite.suites ?? []) skipReasons(child, acc)
|
|
31
|
+
return acc
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
const collect = (suite, acc = []) => {
|
|
17
35
|
for (const spec of suite.specs ?? []) {
|
|
18
36
|
for (const test of spec.tests ?? []) {
|
|
@@ -41,8 +59,10 @@ const render = report => {
|
|
|
41
59
|
|
|
42
60
|
const lines = [MARKER, '## Playwright on the preview', '']
|
|
43
61
|
|
|
44
|
-
if (!failures.length && !truncated) {
|
|
45
|
-
lines.push(`All tests passed. ${expected} passed
|
|
62
|
+
if (!failures.length && !truncated && !skipped) {
|
|
63
|
+
lines.push(`All tests passed. ${expected} passed.`)
|
|
64
|
+
} else if (!failures.length && !truncated) {
|
|
65
|
+
lines.push(`No failures. ${expected} passed, **${skipped} skipped**.`)
|
|
46
66
|
} else {
|
|
47
67
|
lines.push(
|
|
48
68
|
`**${failures.length} failed**, ${expected} passed, ${skipped} skipped` +
|
|
@@ -58,6 +78,19 @@ const render = report => {
|
|
|
58
78
|
)
|
|
59
79
|
}
|
|
60
80
|
|
|
81
|
+
if (skipped) {
|
|
82
|
+
const reasons = new Map()
|
|
83
|
+
for (const s of report.suites ?? []) skipReasons(s, reasons)
|
|
84
|
+
lines.push(
|
|
85
|
+
'',
|
|
86
|
+
'> [!WARNING]',
|
|
87
|
+
`> ${skipped} skipped tests did not run on this preview. Check that they are meant to skip here:`
|
|
88
|
+
)
|
|
89
|
+
for (const [reason, count] of reasons) {
|
|
90
|
+
lines.push(`> - ${truncate(reason, 200)} (${count})`)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
61
94
|
for (const f of failures) {
|
|
62
95
|
lines.push('', `### \`${f.file}:${f.line}\` — ${f.title}`)
|
|
63
96
|
if (f.error) {
|
|
@@ -5,8 +5,9 @@ name: PR Playwright tests
|
|
|
5
5
|
# pipeline release updates it without a change here. This file owns the
|
|
6
6
|
# trigger and the permissions only.
|
|
7
7
|
# Needs repo secret VERCEL_AUTOMATION_BYPASS_SECRET when previews are
|
|
8
|
-
# protected. Optional repo variable
|
|
9
|
-
#
|
|
8
|
+
# protected. Optional repo variable PREVIEW_TESTS_AS: the production domain
|
|
9
|
+
# whose test settings previews use (e.g. shop.de), one value per repo.
|
|
10
|
+
# Unset, the specs use the primary domain.
|
|
10
11
|
on:
|
|
11
12
|
deployment_status
|
|
12
13
|
|
|
@@ -22,7 +23,7 @@ jobs:
|
|
|
22
23
|
playwright:
|
|
23
24
|
uses: why-agency/why-e2e-pipeline/.github/workflows/reusable-pr-playwright-tests.yml@main
|
|
24
25
|
with:
|
|
25
|
-
|
|
26
|
+
preview_tests_as: ${{ vars.PREVIEW_TESTS_AS }}
|
|
26
27
|
# Per-repo settings, defaults shown. Uncomment to change.
|
|
27
28
|
# node_version: "22" # match the repo's engines/.nvmrc
|
|
28
29
|
# pnpm_version: "" # set when package.json has no packageManager
|