@sun-asterisk/sungen 2.6.11 → 2.6.14
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/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +215 -65
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
- package/dist/dashboard/snapshot-builder.js +173 -32
- package/dist/dashboard/snapshot-builder.js.map +1 -1
- package/dist/dashboard/templates/index.html +84 -84
- package/dist/dashboard/types.d.ts +35 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.d.ts +24 -3
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +28 -7
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/json-exporter.d.ts +15 -0
- package/dist/exporters/json-exporter.d.ts.map +1 -1
- package/dist/exporters/json-exporter.js +7 -2
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts +7 -0
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +20 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/selector-key-resolver.d.ts +55 -0
- package/dist/exporters/selector-key-resolver.d.ts.map +1 -0
- package/dist/exporters/selector-key-resolver.js +208 -0
- package/dist/exporters/selector-key-resolver.js.map +1 -0
- package/dist/exporters/test-data-resolver.d.ts +15 -2
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +61 -8
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/exporters/types.d.ts +1 -0
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.d.ts +28 -3
- package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.js +34 -6
- package/dist/exporters/xlsx-exporter.js.map +1 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +13 -0
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +9 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +18 -2
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
- package/dist/orchestrator/ai-rules-updater.js +4 -0
- package/dist/orchestrator/ai-rules-updater.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +1 -2
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +48 -14
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-dashboard.md +4 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +22 -11
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-locale.md +71 -0
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +23 -8
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +45 -6
- package/dist/orchestrator/templates/ai-instructions/claude-config.md +6 -1
- package/dist/orchestrator/templates/ai-instructions/claude-skill-locale.md +316 -0
- package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +1 -0
- package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +38 -0
- package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +2 -0
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +50 -13
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-dashboard.md +4 -1
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +20 -9
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-locale.md +70 -0
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +23 -8
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +44 -6
- package/dist/orchestrator/templates/ai-instructions/copilot-config.md +6 -1
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-locale.md +291 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +1 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +38 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +2 -0
- package/dist/orchestrator/templates/playwright.config.ts +25 -8
- package/dist/orchestrator/templates/specs-base.ts +9 -0
- package/dist/orchestrator/templates/specs-locale-fixture.ts +105 -0
- package/package.json +1 -1
- package/src/cli/commands/delivery.ts +256 -65
- package/src/cli/index.ts +1 -1
- package/src/dashboard/snapshot-builder.ts +207 -32
- package/src/dashboard/templates/index.html +84 -84
- package/src/dashboard/types.ts +40 -3
- package/src/exporters/csv-exporter.ts +36 -7
- package/src/exporters/json-exporter.ts +22 -2
- package/src/exporters/playwright-report-parser.ts +20 -0
- package/src/exporters/selector-key-resolver.ts +190 -0
- package/src/exporters/test-data-resolver.ts +65 -7
- package/src/exporters/types.ts +1 -0
- package/src/exporters/xlsx-exporter.ts +61 -7
- package/src/generators/test-generator/code-generator.ts +14 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +19 -2
- package/src/orchestrator/ai-rules-updater.ts +4 -0
- package/src/orchestrator/project-initializer.ts +1 -2
- package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +48 -14
- package/src/orchestrator/templates/ai-instructions/claude-cmd-dashboard.md +4 -1
- package/src/orchestrator/templates/ai-instructions/claude-cmd-delivery.md +22 -11
- package/src/orchestrator/templates/ai-instructions/claude-cmd-locale.md +71 -0
- package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +23 -8
- package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +45 -6
- package/src/orchestrator/templates/ai-instructions/claude-config.md +6 -1
- package/src/orchestrator/templates/ai-instructions/claude-skill-locale.md +316 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +1 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +38 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +2 -0
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +50 -13
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-dashboard.md +4 -1
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-delivery.md +20 -9
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-locale.md +70 -0
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +23 -8
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +44 -6
- package/src/orchestrator/templates/ai-instructions/copilot-config.md +6 -1
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-locale.md +291 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +1 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +38 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +2 -0
- package/src/orchestrator/templates/playwright.config.ts +25 -8
- package/src/orchestrator/templates/specs-base.ts +9 -0
- package/src/orchestrator/templates/specs-locale-fixture.ts +105 -0
- package/dist/orchestrator/templates/playwright.config.d.ts +0 -10
- package/dist/orchestrator/templates/playwright.config.d.ts.map +0 -1
- package/dist/orchestrator/templates/playwright.config.js +0 -104
- package/dist/orchestrator/templates/playwright.config.js.map +0 -1
- package/dist/orchestrator/templates/specs-base.d.ts +0 -14
- package/dist/orchestrator/templates/specs-base.d.ts.map +0 -1
- package/dist/orchestrator/templates/specs-base.js +0 -77
- package/dist/orchestrator/templates/specs-base.js.map +0 -1
- package/dist/orchestrator/templates/specs-test-data.d.ts +0 -16
- package/dist/orchestrator/templates/specs-test-data.d.ts.map +0 -1
- package/dist/orchestrator/templates/specs-test-data.js +0 -151
- package/dist/orchestrator/templates/specs-test-data.js.map +0 -1
|
@@ -20,13 +20,28 @@ You are a **Senior QA Reviewer**. You evaluate Gherkin test cases using the `sun
|
|
|
20
20
|
|
|
21
21
|
## Steps
|
|
22
22
|
|
|
23
|
-
1.
|
|
24
|
-
2.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
1. **Enumerate feature files** — glob `<base>/<name>/features/*.feature`. A screen may have one main file (`<name>.feature`) plus sub-features (`<name>-<sub>.feature` like `awards-modal.feature`); a flow has a single `<name>.feature`. If zero `.feature` files found → `/sungen-create-test` first.
|
|
24
|
+
2. **Review every feature file** — for each `<basename>.feature` discovered in step 1:
|
|
25
|
+
- Read `<basename>.feature` and the matching `test-data/<basename>.yaml`.
|
|
26
|
+
- Apply the `sungen-tc-review` skill — score 3 dimensions: Syntax (30pts), Coverage (40pts), Viewpoint (30pts). **For flows**, also apply the "Flow Review Additions" section. Use `sungen-viewpoint` for pattern checklists.
|
|
27
|
+
- Apply the **Unverified Selectors check** — if `<base>/<name>/selectors/<basename>.yaml` exists, count lines matching `@needs-live-verify`. Include in the per-file report as a non-scoring metric. Does NOT affect the 60% threshold.
|
|
28
|
+
3. **Aggregated output** — present scores in a per-feature table, then a screen-level rollup:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Feature Syntax Coverage Viewpoint Total Verdict
|
|
32
|
+
──────────────────────────────────────────────────────────────────
|
|
33
|
+
home.feature 28/30 36/40 27/30 91% PASS
|
|
34
|
+
home-modal.feature 26/30 24/40 22/30 72% PASS
|
|
35
|
+
──────────────────────────────────────────────────────────────────
|
|
36
|
+
Screen rollup (mean) 27/30 30/40 24.5/30 81.5% PASS
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- **>= 60% per file**: PASS that file.
|
|
40
|
+
- **< 60% per file**: FAIL that file with recommendations.
|
|
41
|
+
- Show the full per-file report (recommendations, top issues) **only for files that fail**, or when the user asks for the deep report.
|
|
42
|
+
4. If any file is FAIL and user confirms → update that file's test cases following `sungen-gherkin-syntax` and `sungen-tc-generation` skills, then re-review **only the failing files** (skip already-passing ones to save time).
|
|
43
|
+
5. After all files PASS (or user decides to proceed), offer next steps:
|
|
44
|
+
|
|
45
|
+
- **`/sungen-run-test ${input:name}`** — Generate selectors, compile, and run tests for **every feature** in this screen (Recommended)
|
|
31
46
|
- **`/sungen-create-test ${input:name}`** — Add more test cases before running
|
|
32
47
|
- **Done for now** — I'll come back later
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sungen-run-test
|
|
3
3
|
description: 'Generate selectors + auth state via Playwright MCP, compile, and run Playwright tests — auto-fixes selectors on failure'
|
|
4
|
-
argument-hint:
|
|
4
|
+
argument-hint: "[name] [--env <locale>]"
|
|
5
5
|
tools: [read, execute, edit, vscode/askQuestions, playwright/*]
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -11,7 +11,24 @@ You are a **Senior Developer**. Use `sungen-selector-fix`, `sungen-selector-keys
|
|
|
11
11
|
|
|
12
12
|
## Parameters
|
|
13
13
|
|
|
14
|
-
Parse
|
|
14
|
+
Parse from `$ARGUMENTS`:
|
|
15
|
+
- **name** — screen or flow name. If missing, ask the user.
|
|
16
|
+
- **`--env <locale>`** — optional. Sets `SUNGEN_ENV=<locale>` for the test run so the runtime test-data resolver merges `<name>.<locale>.yaml` over the base, and `playwright.config.ts` writes results to `<name>-test-result.<locale>.json`. Accept `--locale <locale>` as an alias.
|
|
17
|
+
|
|
18
|
+
If `--env` is passed but no value follows, ask the user which locale to use.
|
|
19
|
+
|
|
20
|
+
**`--env <locale>` pre-flight**: when `--env` is passed AND the matching overlay file doesn't exist yet (`test-data/<feature>.<locale>.yaml` missing), tests will silently fall back to base locale — the run will execute but won't actually exercise the locale. Before Phase 0.5, check:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
ls qa/<screens|flows>/<name>/test-data/*.<locale>.yaml 2>/dev/null | wc -l
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Count 0 → offer the user:
|
|
27
|
+
- **Run `/sungen-locale <name> <locale>` first** (Recommended) — bootstrap the overlay
|
|
28
|
+
- **Continue anyway** — tests will likely fail on a real locale page
|
|
29
|
+
- **Cancel**
|
|
30
|
+
|
|
31
|
+
Skip when `--env` matches the base locale.
|
|
15
32
|
|
|
16
33
|
**Auto-detect context**: check if `qa/flows/<name>/` exists → flow mode (base path: `qa/flows/<name>/`). Else check `qa/screens/<name>/` → screen mode (base path: `qa/screens/<name>/`).
|
|
17
34
|
|
|
@@ -52,7 +69,11 @@ Parse **name** from `$ARGUMENTS`. If missing, ask the user.
|
|
|
52
69
|
name: "Submit"
|
|
53
70
|
```
|
|
54
71
|
3. **Phase 0.5 — Auth Persistence**: if the feature has `@auth:<role>` tags and `specs/.auth/<role>.json` is missing/expired, run Phase 0.5 from `sungen-selector-fix` — user logs in manually in MCP browser → `browser_storage_state` → `specs/.auth/<role>.json`. Offer `sungen makeauth <role>` as CLI fallback only if `browser_storage_state` isn't available in this MCP version.
|
|
55
|
-
4. Compile
|
|
72
|
+
4. Compile via local-first dispatcher so the sungen monorepo's unpublished selector-resolver features (i18n `{{var}}` interpolation, namespaced selector lookup) are picked up:
|
|
73
|
+
- **Screen**: `[ -x ./bin/sungen.js ] && ./bin/sungen.js generate --screen <name> || npx sungen generate --screen <name>`
|
|
74
|
+
- **Flow**: `[ -x ./bin/sungen.js ] && ./bin/sungen.js generate --flow <name> || npx sungen generate --flow <name>`
|
|
75
|
+
|
|
76
|
+
Default: runtime data loading from YAML. Use `--inline-data` only if user requests compile-time hardcoded values.
|
|
56
77
|
|
|
57
78
|
## Run & Fix (phased — per `sungen-selector-fix` skill)
|
|
58
79
|
|
|
@@ -63,13 +84,30 @@ Parse **name** from `$ARGUMENTS`. If missing, ask the user.
|
|
|
63
84
|
|
|
64
85
|
## Playwright command guidelines
|
|
65
86
|
|
|
66
|
-
**
|
|
87
|
+
**Multi-feature screens** — `sungen generate --screen <name>` produces one `<basename>.spec.ts` per `.feature` file (e.g. `home.spec.ts` + `home-modal.spec.ts`). You must **invoke playwright once per spec file** so each gets its own JSON result that `sungen delivery` can pick up. Do NOT run a single command with the directory as the test argument — that bundles everything into one results file that delivery can't disambiguate.
|
|
88
|
+
|
|
89
|
+
**Per-spec JSON results** — each invocation writes its JSON report to a path matching the spec basename. When `--env <locale>` was parsed from `$ARGUMENTS`, prepend `SUNGEN_ENV=<locale>` — `playwright.config.ts` auto-inserts `.<locale>` before `.json` in the output path:
|
|
67
90
|
|
|
68
91
|
```bash
|
|
69
|
-
# ✅ Screen
|
|
92
|
+
# ✅ Screen with 1 feature
|
|
70
93
|
PLAYWRIGHT_JSON_OUTPUT_NAME=specs/generated/<name>/<name>-test-result.json \
|
|
71
94
|
npx playwright test specs/generated/<name>/<name>.spec.ts
|
|
72
95
|
|
|
96
|
+
# ✅ Screen with multiple features — loop in shell:
|
|
97
|
+
for spec in specs/generated/<name>/*.spec.ts; do
|
|
98
|
+
base=$(basename "$spec" .spec.ts)
|
|
99
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME="specs/generated/<name>/${base}-test-result.json" \
|
|
100
|
+
npx playwright test "$spec"
|
|
101
|
+
done
|
|
102
|
+
|
|
103
|
+
# ✅ Locale 'vi' — same loop, just prepend SUNGEN_ENV=vi
|
|
104
|
+
for spec in specs/generated/<name>/*.spec.ts; do
|
|
105
|
+
base=$(basename "$spec" .spec.ts)
|
|
106
|
+
SUNGEN_ENV=vi \
|
|
107
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME="specs/generated/<name>/${base}-test-result.json" \
|
|
108
|
+
npx playwright test "$spec"
|
|
109
|
+
done
|
|
110
|
+
|
|
73
111
|
# ✅ Flow
|
|
74
112
|
PLAYWRIGHT_JSON_OUTPUT_NAME=specs/generated/flows/<name>/<name>-test-result.json \
|
|
75
113
|
npx playwright test specs/generated/flows/<name>/<name>.spec.ts
|
|
@@ -88,7 +126,7 @@ npx playwright test specs/generated/<name>/<name>.spec.ts
|
|
|
88
126
|
|
|
89
127
|
If you want to filter scenarios, use `-g "<pattern>"` instead of a reporter override.
|
|
90
128
|
|
|
91
|
-
`sungen delivery` reads the per-
|
|
129
|
+
`sungen delivery` reads per-feature `<basename>-test-result[.env].json` files (one per feature in the screen) and writes one CSV/XLSX per feature (e.g. `home-testcases.csv` + `home-modal-testcases.csv`). When `--env <locale>` was used here, run delivery with the same locale (`/sungen-delivery <name> --env <locale>`) so it picks the matching `*-test-result.<locale>.json` files and produces `*-testcases.<locale>.csv` / `.xlsx`.
|
|
92
130
|
|
|
93
131
|
## Next steps
|
|
94
132
|
|
|
@@ -20,8 +20,9 @@ You generate 3 files for sungen — a Gherkin compiler that produces Playwright
|
|
|
20
20
|
| `sungen-capture-local` | Load existing UI assets (screenshots, mockups, Figma exports) from `requirements/ui/` |
|
|
21
21
|
| `sungen-capture-live` | Capture a live running page via Playwright MCP (snapshot + screenshot) |
|
|
22
22
|
| `sungen-figma-source` | Figma URL → spec_figma.md + ui/*.png + provisional selectors |
|
|
23
|
+
| `sungen-locale` | Bootstrap i18n — audit selectors, detect locale switch mechanism, generate test-data overlay |
|
|
23
24
|
|
|
24
|
-
## Workflow (
|
|
25
|
+
## Workflow (7 AI commands)
|
|
25
26
|
|
|
26
27
|
| Command | What it does |
|
|
27
28
|
|---|---|
|
|
@@ -31,9 +32,11 @@ You generate 3 files for sungen — a Gherkin compiler that produces Playwright
|
|
|
31
32
|
| `/sungen-review <name>` | Score syntax, coverage, viewpoint quality (auto-detects screen or flow) |
|
|
32
33
|
| `/sungen-run-test <name>` | Generate `selectors.yaml`, compile, run, auto-fix (auto-detects screen or flow) |
|
|
33
34
|
| `/sungen-delivery [name...]` | Export test cases → CSV for QA delivery (all screens if no arg) |
|
|
35
|
+
| `/sungen-locale <name> <locale>` | Bootstrap i18n for a screen — audit selectors, detect locale switch, generate overlay (run before `/sungen-run-test --env <locale>`) |
|
|
34
36
|
|
|
35
37
|
**Screen path:** add-screen → create-test → review → run-test → delivery.
|
|
36
38
|
**Flow path:** add-flow → create-test → review → run-test → delivery.
|
|
39
|
+
**i18n path:** (after run-test passes for base locale) → locale → run-test --env <locale> → delivery --env <locale>.
|
|
37
40
|
|
|
38
41
|
`create-test`, `review`, and `run-test` auto-detect context: if `qa/flows/<name>/` exists → flow mode, else `qa/screens/<name>/` → screen mode.
|
|
39
42
|
|
|
@@ -82,6 +85,8 @@ qa/deliverables/<name>-testcases.xlsx # Styled workbook for client hand-off
|
|
|
82
85
|
|
|
83
86
|
**Environment overrides**: `SUNGEN_ENV=staging npx playwright test` merges `<screen>.staging.yaml` on top of `<screen>.yaml`. Create `<screen>.<env>.yaml` for environment-specific values (different credentials, URLs, test users).
|
|
84
87
|
|
|
88
|
+
**i18n support**: for multilingual sites, use `{{variable}}` in selector `name`/`value` fields to reference locale-dependent text from test-data. Create locale overlay files (e.g., `<screen>.vi.yaml`, `<screen>.staging-ja.yaml`) and run with `SUNGEN_ENV=vi`. One feature file + one selector file works across all locales. See `sungen-selector-keys` skill for details.
|
|
89
|
+
|
|
85
90
|
## CLI Commands
|
|
86
91
|
|
|
87
92
|
```bash
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sungen-locale
|
|
3
|
+
description: 'Bootstrap i18n for a screen/flow — audit hardcoded selector text, detect locale-switch mechanism via live Playwright, generate test-data overlay file. Auto-loaded by /sungen:locale command.'
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
Take a screen/flow whose `selectors/*.yaml` and `.feature` files were authored against the default locale (usually Vietnamese) and prepare it to run against a second locale. Output:
|
|
10
|
+
|
|
11
|
+
1. `selectors/<feature>.yaml` — hardcoded `name`/`value` replaced with `{{var}}`
|
|
12
|
+
2. `test-data/<feature>.yaml` — base locale, complete with all new keys
|
|
13
|
+
3. `test-data/<feature>.<locale>.yaml` — overlay with only the keys that change
|
|
14
|
+
4. (Optional) `selectors/<feature>.yaml` Pages block updated when locale uses URL prefix or query param
|
|
15
|
+
|
|
16
|
+
After this skill finishes, `sungen run-test <name> --env <locale>` Just Works.
|
|
17
|
+
|
|
18
|
+
## Run mode — Live (preferred) vs Offline (fallback)
|
|
19
|
+
|
|
20
|
+
Pick mode **once at start**, based on whether MCP Playwright can reach the page.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Try: browser_navigate(baseURL)
|
|
24
|
+
→ succeeds + page renders content → LIVE MODE (all 6 phases)
|
|
25
|
+
→ fails (auth blocked, network down, app broken) → OFFLINE MODE
|
|
26
|
+
(audit + scaffold template + ask user to fill, skip detection phases)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Live mode is the value-add** — it auto-detects locale switch mechanism and auto-fills translations. Offline mode just makes the file structure right; user fills in text manually.
|
|
30
|
+
|
|
31
|
+
Announce which mode is being used before Phase 1.
|
|
32
|
+
|
|
33
|
+
## Phase 1 — Audit selectors (always, no MCP)
|
|
34
|
+
|
|
35
|
+
For each `.feature` file under the screen, read the matching `selectors/<feature>.yaml`. List every entry whose `name` or `value` field contains literal text WITHOUT `{{…}}` AND is not a CSS/href selector.
|
|
36
|
+
|
|
37
|
+
Classify each candidate:
|
|
38
|
+
- **`name` field of `role`-type selector** → very likely locale-dependent
|
|
39
|
+
- **`value` field of `text`-type selector** → very likely locale-dependent
|
|
40
|
+
- **`value` of `locator`-type selector** that contains `:has-text("…")` → check if text is in target language
|
|
41
|
+
- **`value` of `page`-type selector** → URL — handled in Phase 3
|
|
42
|
+
- **CSS / href / attribute selectors** (e.g. `a[href="/awards"]`) → skip, locale-invariant
|
|
43
|
+
|
|
44
|
+
Print the candidate list as a table:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
selector key | field | hardcoded value | classification
|
|
48
|
+
-------------------+-------+---------------------------+------------------
|
|
49
|
+
nav about | name | Giới thiệu SAA 2025 | locale-dependent
|
|
50
|
+
nav awards | name | Thông tin giải thưởng | locale-dependent
|
|
51
|
+
event date | name | 26/12/2025 | maybe (date format)
|
|
52
|
+
nav kudos | name | Sun* Kudos | brand — skip
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If zero candidates and zero `{{var}}` already in place → screen has no localizable text. Tell user, stop.
|
|
56
|
+
|
|
57
|
+
## Phase 2 — Capture base locale (LIVE only)
|
|
58
|
+
|
|
59
|
+
1. Read `playwright.config.ts` for `baseURL`. Read `Path:` from `.feature` for entry path.
|
|
60
|
+
2. If screen has `@auth:<role>` tags, load `specs/.auth/<role>.json` via `browser_set_storage_state` first.
|
|
61
|
+
3. `browser_navigate(baseURL + entryPath)` then `browser_wait_for` for something stable.
|
|
62
|
+
4. Capture:
|
|
63
|
+
- `browser_snapshot()` — DOM accessibility tree
|
|
64
|
+
- `browser_evaluate(() => location.href)` — full URL
|
|
65
|
+
- `browser_evaluate(() => ({ localStorage: {...localStorage}, cookies: document.cookie }))` — storage state hash
|
|
66
|
+
5. For each Phase-1 candidate: verify the hardcoded text actually appears on the page. Drop ones that don't (stale selectors / false positives).
|
|
67
|
+
|
|
68
|
+
Save state in memory as `baseLocale = { url, snapshot, storage }`.
|
|
69
|
+
|
|
70
|
+
If page redirects to `/login` (auth blocker) → stop. Print: *"Auth blocked — cannot capture live page. Re-run with `--offline` flag, or unblock auth first."*
|
|
71
|
+
|
|
72
|
+
## Phase 3 — Switch locale (LIVE only) — detect mechanism + storage delta
|
|
73
|
+
|
|
74
|
+
Goal: identify (a) HOW to switch the app to the target locale, and (b) WHAT app-side storage state ends up holding the locale preference so a fresh BrowserContext can be primed identically without driving the UI.
|
|
75
|
+
|
|
76
|
+
Before triggering the switch, capture full storage baseline:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const before = await browser_evaluate(() => ({
|
|
80
|
+
sessionStorage: { ...sessionStorage },
|
|
81
|
+
localStorage: { ...localStorage },
|
|
82
|
+
cookies: document.cookie,
|
|
83
|
+
url: location.href,
|
|
84
|
+
}));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then try mechanisms in order. First one that produces visibly different text wins. For EACH attempt, capture `after` state and diff against `before`.
|
|
88
|
+
|
|
89
|
+
**3a. URL prefix**
|
|
90
|
+
- `browser_navigate(baseURL + '/' + locale + entryPath)`
|
|
91
|
+
- Wait, snapshot
|
|
92
|
+
- Compare a known Phase-1 candidate's text vs baseLocale
|
|
93
|
+
- If text differs and page didn't 404 → **URL prefix mechanism**. Save `localePrefix = '/' + locale`.
|
|
94
|
+
|
|
95
|
+
**3b. Query param** (only if 3a failed)
|
|
96
|
+
- `browser_navigate(baseURL + entryPath + '?lang=' + locale)` (also try `?locale=`, `?lng=`, `?l=`, `?language=`)
|
|
97
|
+
- Same diff check
|
|
98
|
+
- If text differs → **Query param mechanism**. Save the variant that worked.
|
|
99
|
+
|
|
100
|
+
**3c. Language switcher UI** (only if 3a + 3b failed)
|
|
101
|
+
- Look in base-locale snapshot for buttons matching: `'Select language'`, `'Language'`, `'言語'`, `'Ngôn ngữ'`, role=combobox
|
|
102
|
+
- If found, ask user before clicking
|
|
103
|
+
- `browser_click` the switcher, then the locale option
|
|
104
|
+
- Verify text changed
|
|
105
|
+
- If yes → **UI switcher mechanism**.
|
|
106
|
+
|
|
107
|
+
**3d. None detected** — ask user how to proceed manually.
|
|
108
|
+
|
|
109
|
+
### Phase 3.5 — Storage diff (always run after Phase 3 succeeds)
|
|
110
|
+
|
|
111
|
+
After locale text confirmed switched, capture `after` state and diff per area:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
const after = await browser_evaluate(() => ({
|
|
115
|
+
sessionStorage: { ...sessionStorage },
|
|
116
|
+
localStorage: { ...localStorage },
|
|
117
|
+
cookies: document.cookie,
|
|
118
|
+
}));
|
|
119
|
+
const sessionDiff = diffEntries(before.sessionStorage, after.sessionStorage);
|
|
120
|
+
const localDiff = diffEntries(before.localStorage, after.localStorage);
|
|
121
|
+
const cookieDiff = diffCookies(before.cookies, after.cookies);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Filter noise** — only keep entries where:
|
|
125
|
+
- Key name contains `lang|locale|language|i18n|intl` (case-insensitive), OR
|
|
126
|
+
- Value matches `^[a-z]{2}(-[A-Z]{2})?$` or equals the target locale code
|
|
127
|
+
|
|
128
|
+
Drop noise: auth tokens (`sb-*`, `*-token`, `*-jwt`), analytics (`_ga*`, `_gid`, `_fbp`), app state (`csrf*`, `last-*`).
|
|
129
|
+
|
|
130
|
+
**Auto-confidence per entry:**
|
|
131
|
+
- High: key name contains locale-related word AND value is a locale code → KEEP, no prompt
|
|
132
|
+
- Medium: only one signal matches → ask user
|
|
133
|
+
- Low: neither matches but key changed → ask user, default skip
|
|
134
|
+
|
|
135
|
+
### Phase 3.6 — Verification
|
|
136
|
+
|
|
137
|
+
For each high/medium-confidence storage entry, verify by setting it manually + reloading:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
await browser_evaluate(`() => sessionStorage.setItem('saa-language-preference', 'en')`);
|
|
141
|
+
await browser_navigate(baseURL); // reload triggers app to read storage on boot
|
|
142
|
+
await browser_snapshot();
|
|
143
|
+
// confirm a known target-locale string appears
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Caveat: hard reload kills any in-memory JWT (auth blocker amplifies failure surface). Skip verification if the screen has `@auth:*` tags and JWT persistence is known broken in the app.
|
|
147
|
+
|
|
148
|
+
If verification fails → drop confidence one tier, ask user.
|
|
149
|
+
|
|
150
|
+
Save mechanism + verified storage delta to memory for Phase 6.
|
|
151
|
+
|
|
152
|
+
## Phase 4 — Diff base ↔ target (LIVE only)
|
|
153
|
+
|
|
154
|
+
For each candidate from Phase 1 that survived Phase 2:
|
|
155
|
+
- Find the SAME element in target-locale snapshot (match by `role`+position, by `aria-label`, by neighbor structure)
|
|
156
|
+
- Extract its text → `targetText`
|
|
157
|
+
- Pair: `(selectorKey, hardcoded baseText, observed targetText)`
|
|
158
|
+
|
|
159
|
+
If matching fails for a candidate → mark "needs manual" — flag for user input rather than skip silently.
|
|
160
|
+
|
|
161
|
+
Result: list of triples `{ selectorKey, baseText, targetText, confidence }`.
|
|
162
|
+
|
|
163
|
+
## Phase 5 — Confirm + edit (always)
|
|
164
|
+
|
|
165
|
+
Present the proposal table:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
selector key | base text | target text | proposed var | apply?
|
|
169
|
+
-------------------+--------------------------+----------------------+------------------+-------
|
|
170
|
+
nav about | Giới thiệu SAA 2025 | About SAA 2025 | nav_about | [✓]
|
|
171
|
+
nav awards | Thông tin giải thưởng | Awards Info | nav_awards | [✓]
|
|
172
|
+
nav kudos | Sun* Kudos | Sun* Kudos | — | [skip — same]
|
|
173
|
+
event date | 26/12/2025 | 26/12/2025 | — | [skip — same]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Var names: snake_case the selector key. Avoid collisions with existing test-data keys.
|
|
177
|
+
|
|
178
|
+
Auto-skip rows where `baseText === targetText` (brand names, locale-invariant numbers).
|
|
179
|
+
|
|
180
|
+
Ask user: *"Review the table. Confirm to apply / edit individual rows / re-run capture / cancel."*
|
|
181
|
+
|
|
182
|
+
If user wants to edit a row → fall through to a per-row prompt for `var name` or `targetText` correction.
|
|
183
|
+
|
|
184
|
+
OFFLINE mode: same table but `target text` column blank — user fills via subsequent prompts or by editing the overlay file after the skill finishes.
|
|
185
|
+
|
|
186
|
+
## Phase 6 — Apply changes (always, after confirmation)
|
|
187
|
+
|
|
188
|
+
For each confirmed row:
|
|
189
|
+
|
|
190
|
+
**6a. Update `selectors/<feature>.yaml`**
|
|
191
|
+
|
|
192
|
+
Replace `name: '<baseText>'` with `name: '{{<varName>}}'`. Preserve quoting style.
|
|
193
|
+
|
|
194
|
+
**6b. Update `test-data/<feature>.yaml`** (base locale, complete dictionary)
|
|
195
|
+
|
|
196
|
+
Append new keys at the end, grouped under a `# === i18n: <screen> ===` comment:
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
# === i18n: home ===
|
|
200
|
+
nav_about: 'Giới thiệu SAA 2025'
|
|
201
|
+
nav_awards: 'Thông tin giải thưởng'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**6c. Create `test-data/<feature>.<locale>.yaml`** (overlay, only diffs)
|
|
205
|
+
|
|
206
|
+
```yaml
|
|
207
|
+
# home — <locale> overlay. Only keys that change vs base.
|
|
208
|
+
# Run with: SUNGEN_ENV=<locale> npx playwright test ...
|
|
209
|
+
|
|
210
|
+
nav_about: 'About SAA 2025'
|
|
211
|
+
nav_awards: 'Awards Info'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**6d. (URL/query mechanism only) Update Pages selectors**
|
|
215
|
+
|
|
216
|
+
URL prefix:
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
home:
|
|
220
|
+
type: 'page'
|
|
221
|
+
value: '{{base_path}}/'
|
|
222
|
+
awards:
|
|
223
|
+
type: 'page'
|
|
224
|
+
value: '{{base_path}}/awards'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Add to test-data:
|
|
228
|
+
```yaml
|
|
229
|
+
# base
|
|
230
|
+
base_path: ''
|
|
231
|
+
|
|
232
|
+
# overlay
|
|
233
|
+
base_path: '/en'
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Query param mechanism: append `query_suffix` similarly.
|
|
237
|
+
|
|
238
|
+
UI switcher: do NOT modify Pages. Write storage delta into `specs/generated/locale-config.json` (sibling of generated `base.ts` + `locale-fixture.ts`) (6f).
|
|
239
|
+
|
|
240
|
+
**6f. Storage injection config — `specs/generated/locale-config.json` (sibling of generated `base.ts` + `locale-fixture.ts`)**
|
|
241
|
+
|
|
242
|
+
Always write `specs/generated/locale-config.json` (sibling of generated `base.ts` + `locale-fixture.ts`) with the verified storage delta from Phase 3.5/3.6. Consumed by `specs/locale-fixture.ts` (auto-generated alongside `specs/base.ts`), which wraps Playwright's context and calls `addInitScript` + `addCookies` BEFORE the first navigation.
|
|
243
|
+
|
|
244
|
+
Schema:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"$schema": "sungen-locale-config-v1",
|
|
249
|
+
"sessionStorage": {
|
|
250
|
+
"saa-language-preference": "${SUNGEN_ENV}"
|
|
251
|
+
},
|
|
252
|
+
"localStorage": {},
|
|
253
|
+
"cookies": [],
|
|
254
|
+
"notes": "Detected by /sungen:locale on YYYY-MM-DD. ..."
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Use `"${SUNGEN_ENV}"` (or `"{{SUNGEN_ENV}}"`) as placeholder for runtime substitution. Use hardcoded literals when the stored value is fixed regardless of locale. Drop auth tokens / session IDs even if the Phase 3.5 diff captured them.
|
|
259
|
+
|
|
260
|
+
Multi-locale projects use the same file — placeholder gets substituted at runtime per locale.
|
|
261
|
+
|
|
262
|
+
**6e. Compile**
|
|
263
|
+
|
|
264
|
+
Run `sungen generate --screen <name>` (or `--flow`) and report any compile errors. Selectors changed → compile MUST succeed before run-test.
|
|
265
|
+
|
|
266
|
+
## Phase 7 — Hand off
|
|
267
|
+
|
|
268
|
+
Print summary:
|
|
269
|
+
- N selectors converted to `{{var}}`
|
|
270
|
+
- M base keys added to `test-data/<feature>.yaml`
|
|
271
|
+
- K overlay keys written to `test-data/<feature>.<locale>.yaml`
|
|
272
|
+
- Pages selectors updated: yes/no
|
|
273
|
+
- Locale-switching mechanism: URL prefix `/en` / query `?lang=en` / UI switcher / manual
|
|
274
|
+
|
|
275
|
+
Suggest:
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
/sungen:run-test <name> --env <locale>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Multi-feature screens
|
|
282
|
+
|
|
283
|
+
If the screen has multiple `.feature` files (e.g. `home.feature` + `home-modal.feature`), repeat Phase 1 → Phase 6 for each feature file with its own selectors + test-data pair. Phase 2 + 3 run **once per screen** — mechanism is the same. Phase 4 runs per feature because UI scope differs.
|
|
284
|
+
|
|
285
|
+
## What NOT to do
|
|
286
|
+
|
|
287
|
+
- Do not edit `.feature` files. The i18n shape is already correct there (`{{var}}` was the convention from the start). Only selectors + test-data need surgery.
|
|
288
|
+
- Do not write a separate selectors file per locale (`home.en.yaml`). One selectors file with `{{var}}` works across all locales.
|
|
289
|
+
- Do not delete keys from the base `test-data/<feature>.yaml`. Always append.
|
|
290
|
+
- Do not run tests in this skill. Hand off to `/sungen:run-test`.
|
|
291
|
+
- Do not commit. Hand off to user.
|
|
@@ -61,6 +61,7 @@ When running Phase 0 for a **flow** (`qa/flows/<name>/`), check existing screen
|
|
|
61
61
|
- Selector priority: follow the table in **Diagnosis & Fix § Step 3** (`testid` > `role`+name > `placeholder` > `label` > `locator` > `text`).
|
|
62
62
|
- Copy names **character-for-character** from the snapshot. Never infer from the Gherkin label.
|
|
63
63
|
- If an element is auto-inferable per `sungen-selector-keys` § Auto-Infer, **omit it** from YAML — keep the file minimal.
|
|
64
|
+
- **i18n sites**: if the site supports multiple languages, use `{{variable}}` in `name`/`value` fields instead of hardcoded text. Add corresponding `lbl_*` keys to `test-data.yaml` + locale overlay files (see `sungen-selector-keys` § i18n).
|
|
64
65
|
7. **Substring ambiguity check**: for each `role` + `name` selector, check if any other element in the snapshot has a name that **contains** this name as a substring (e.g., `"Đăng ký"` vs `"Đăng ký bằng Google"`). If yes → add `exact: true` to prevent strict mode violation at runtime.
|
|
65
66
|
8. **Merge, don't overwrite**: preserve the page selector and any user-authored entries in `selectors.yaml`. Only add missing keys.
|
|
66
67
|
9. **Show summary + confirm**: list the keys that will be added, ask the user to approve, then write the file.
|
|
@@ -115,6 +115,44 @@ gửi lời cảm ơn--3:
|
|
|
115
115
|
name: 'Gửi lời cảm ơn'
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
## i18n: Template Variables in Selectors
|
|
119
|
+
|
|
120
|
+
For multilingual sites without `data-testid`, use `{{variable}}` in `name` or `value` fields to reference locale-dependent text from `test-data.yaml`.
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
# selectors — one file for all locales
|
|
124
|
+
submit:
|
|
125
|
+
type: role
|
|
126
|
+
value: button
|
|
127
|
+
name: "{{lbl_submit}}"
|
|
128
|
+
|
|
129
|
+
search:
|
|
130
|
+
type: placeholder
|
|
131
|
+
value: "{{lbl_search}}"
|
|
132
|
+
|
|
133
|
+
logo:
|
|
134
|
+
type: testid
|
|
135
|
+
value: app-logo # testid is locale-independent — no variable needed
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
# test-data/login.yaml (base — English)
|
|
140
|
+
lbl_submit: "Sign in"
|
|
141
|
+
lbl_search: "Search..."
|
|
142
|
+
|
|
143
|
+
# test-data/login.vi.yaml (Vietnamese)
|
|
144
|
+
lbl_submit: "Đăng nhập"
|
|
145
|
+
lbl_search: "Tìm kiếm..."
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Run: `SUNGEN_ENV=vi npx playwright test`
|
|
149
|
+
|
|
150
|
+
**Rules:**
|
|
151
|
+
1. Prefix i18n keys with `lbl_`, `msg_`, `txt_` to separate from test data
|
|
152
|
+
2. Prefer `data-testid` — only use `{{variable}}` when no stable selector exists
|
|
153
|
+
3. Feature file stays identical across locales
|
|
154
|
+
4. Requires runtime data mode (default, not `--inline-data`)
|
|
155
|
+
|
|
118
156
|
## Lookup Priority
|
|
119
157
|
|
|
120
158
|
Resolver searches in this order:
|
|
@@ -352,6 +352,8 @@ Feature: <Screen> Screen
|
|
|
352
352
|
|
|
353
353
|
**Environment-specific data**: create `<screen>.<env>.yaml` alongside the base file with only the keys that change. Users run `SUNGEN_ENV=staging npx playwright test` to merge overrides.
|
|
354
354
|
|
|
355
|
+
**i18n / multilingual**: use the same `SUNGEN_ENV` overlay for locale variants — e.g., `login.vi.yaml`, `login.staging-ja.yaml`. Include `lbl_*` / `msg_*` keys for selector `{{variable}}` references (see `sungen-selector-keys` § i18n). One feature file + one selector file works across all locales.
|
|
356
|
+
|
|
355
357
|
## Flow Test Generation
|
|
356
358
|
|
|
357
359
|
When generating tests for a **flow** (`qa/flows/<name>/`), adapt the strategy:
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import { defineConfig, devices } from '@playwright/test';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the JSON reporter output path.
|
|
5
|
+
*
|
|
6
|
+
* Precedence:
|
|
7
|
+
* 1. `PLAYWRIGHT_JSON_OUTPUT_NAME` if set — used as-is, but a `.<env>`
|
|
8
|
+
* segment is inserted before the extension when `SUNGEN_ENV` is also set
|
|
9
|
+
* so per-locale runs don't overwrite each other.
|
|
10
|
+
* 2. `SUNGEN_ENV` only → `test-results/results.<env>.json`.
|
|
11
|
+
* 3. Otherwise → `test-results/results.json`.
|
|
12
|
+
*/
|
|
13
|
+
function resolveJsonOutputFile(): string {
|
|
14
|
+
const explicit = process.env.PLAYWRIGHT_JSON_OUTPUT_NAME;
|
|
15
|
+
const env = process.env.SUNGEN_ENV;
|
|
16
|
+
if (explicit) {
|
|
17
|
+
if (!env) return explicit;
|
|
18
|
+
return explicit.endsWith('.json')
|
|
19
|
+
? `${explicit.slice(0, -'.json'.length)}.${env}.json`
|
|
20
|
+
: `${explicit}.${env}`;
|
|
21
|
+
}
|
|
22
|
+
return env ? `test-results/results.${env}.json` : 'test-results/results.json';
|
|
23
|
+
}
|
|
24
|
+
|
|
3
25
|
/**
|
|
4
26
|
* Read environment variables from file.
|
|
5
27
|
* https://github.com/motdotla/dotenv
|
|
@@ -28,16 +50,11 @@ export default defineConfig({
|
|
|
28
50
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
29
51
|
/* JSON reporter is required by `sungen delivery` to populate test result columns in the exported CSV. */
|
|
30
52
|
/* Output file path is controlled by PLAYWRIGHT_JSON_OUTPUT_NAME env var for per-screen isolation. */
|
|
53
|
+
/* When SUNGEN_ENV is set, the env name is inserted before `.json` so locale */
|
|
54
|
+
/* runs don't overwrite each other (e.g. `<name>-test-result.vi.json`). */
|
|
31
55
|
reporter: [
|
|
32
56
|
['html'],
|
|
33
|
-
[
|
|
34
|
-
'json',
|
|
35
|
-
{
|
|
36
|
-
outputFile:
|
|
37
|
-
process.env.PLAYWRIGHT_JSON_OUTPUT_NAME ||
|
|
38
|
-
'test-results/results.json',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
57
|
+
['json', { outputFile: resolveJsonOutputFile() }],
|
|
41
58
|
],
|
|
42
59
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
43
60
|
use: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { test as base, expect, type Page } from '@playwright/test';
|
|
2
|
+
import { applyLocaleInjection } from './locale-fixture';
|
|
2
3
|
|
|
3
4
|
type CleanupConfig = {
|
|
4
5
|
overlay?: boolean;
|
|
@@ -66,6 +67,14 @@ const test = base.extend<{
|
|
|
66
67
|
}>({
|
|
67
68
|
screenshotOnFailure: [false, { option: true }],
|
|
68
69
|
|
|
70
|
+
// Wrap the default `context` fixture so locale state (sessionStorage,
|
|
71
|
+
// localStorage, cookies) is injected before the first page navigation.
|
|
72
|
+
// No-op when SUNGEN_ENV is unset or specs/locale-config.json is missing.
|
|
73
|
+
context: async ({ context }, use) => {
|
|
74
|
+
await applyLocaleInjection(context);
|
|
75
|
+
await use(context);
|
|
76
|
+
},
|
|
77
|
+
|
|
69
78
|
page: async ({ context }, use) => {
|
|
70
79
|
const page = await context.newPage();
|
|
71
80
|
await use(page);
|