Skip to content

Commit 2eed23d

Browse files
author
DavidQ
committed
Expand Playwright coverage to full Workspace V2 Asset Manager regression flow - PR_11_318D
1 parent 247bec7 commit 2eed23d

7 files changed

Lines changed: 310 additions & 12 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,10 @@ PR_11_318C
194194
```bash
195195
npx @openai/codex run --model gpt-5.3-codex --reasoning medium "Implement PR_11_318C: Redirect Playwright outputs to tests/results/** and avoid default output folders with config-only changes."
196196
```
197+
198+
---
199+
PR_11_318D
200+
201+
```bash
202+
npx @openai/codex run --model gpt-5.3-codex --reasoning medium "Implement PR_11_318D: Expand Workspace V2 Playwright UI coverage into full Asset Manager regression with launch/add/remove/validation/export/import round-trip assertions."
203+
```

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Redirect Playwright output artifacts and reports into tests/results and remove default output folder usage - PR 11.318C
1+
Expand Workspace V2 Playwright UI regression coverage for Asset Manager launch, validation, export, and round-trip import - PR 11.318D
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# PR_11_318D Report
2+
3+
## Purpose
4+
Expand Workspace V2 UI automation into a full regression scenario for Asset Manager V2 launch, validation, selection/details, export integrity, and import/export round-trip.
5+
6+
## Files Changed
7+
- `tests/ui/workspace-v2.asset-manager.spec.js`
8+
- `docs/pr/PR_11_318D_WORKSPACE_V2_FULL_UI_REGRESSION/PLAN_PR.md`
9+
- `docs/pr/PR_11_318D_WORKSPACE_V2_FULL_UI_REGRESSION/BUILD_PR.md`
10+
- `docs/dev/reports/PR_11_318D_report.md`
11+
- `docs/dev/codex_commands.md`
12+
- `docs/dev/commit_comment.txt`
13+
14+
## Coverage Added
15+
- Workspace V2 startup baseline:
16+
- Full Reset
17+
- workspace tools summary includes `palette-browser` and `workspace-v2`
18+
- Producer launch:
19+
- select `asset-manager-v2`
20+
- Load Fixture
21+
- Create Session + Launch
22+
- Asset Manager contract readout includes valid `payloadJson.assetCatalog`
23+
- `Player Ship` visible
24+
- Add valid asset + status:
25+
- add `asset-002` / `Enemy Ship`
26+
- success status visible
27+
- Duplicate rejection:
28+
- duplicate add blocked message visible
29+
- only one `Enemy Ship` row
30+
- Blank/whitespace rejection:
31+
- required field rejection message visible
32+
- no blank asset entries created
33+
- Selection/details panel:
34+
- selecting `Player Ship` shows expected id/label/kind/path values
35+
- Remove asset:
36+
- remove `asset-002`
37+
- `Enemy Ship` disappears
38+
- remove status visible
39+
- Export validation:
40+
- confirms manifest contract shape and field exclusions
41+
- confirms no serialized UI selection state
42+
- Import/export round-trip:
43+
- import from exported JSON via file chooser path
44+
- reopen Asset Manager V2
45+
- `Player Ship` visible
46+
- no invalid payload state
47+
48+
## Validation Commands
49+
- `node --check tests/ui/workspace-v2.asset-manager.spec.js` -> **PASS**
50+
- `npx playwright test tests/ui/workspace-v2.asset-manager.spec.js` -> **PASS**
51+
52+
## Full Samples Smoke Decision
53+
- **Skipped** full samples smoke.
54+
- Reason: this PR changes only a targeted Playwright UI test and does not modify runtime/sample framework logic.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# BUILD_PR_11_318D
2+
3+
## Implementation
4+
- Expanded `tests/ui/workspace-v2.asset-manager.spec.js` into a full regression flow:
5+
- Workspace V2 startup + Full Reset baseline checks
6+
- Producer launch into Asset Manager V2
7+
- Valid add (`asset-002`) and success status check
8+
- Duplicate add rejection and single-entry count check
9+
- Blank/whitespace rejection and message assertions
10+
- Asset selection/details panel assertions for `asset-001`
11+
- Remove `asset-002` and removal status check
12+
- Export validation through workspace textarea JSON:
13+
- `documentKind = workspace-manifest`
14+
- `tools.palette-browser` exists
15+
- `tools.workspace-v2` exists
16+
- `activeSession.toolId = asset-manager-v2`
17+
- `asset-001` present and `asset-002` absent
18+
- no `workspaceSession`
19+
- no `games`
20+
- no `tools.asset-manager-v2`
21+
- no UI selection state serialized
22+
- Import round-trip via `Import Workspace Session JSON` file chooser
23+
- Reopen Asset Manager V2 and confirm `Player Ship` loads with no invalid-state error
24+
25+
## Validation
26+
- `node --check tests/ui/workspace-v2.asset-manager.spec.js`
27+
- `npx playwright test tests/ui/workspace-v2.asset-manager.spec.js`
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# PLAN_PR_11_318D
2+
3+
## Purpose
4+
Expand Workspace V2 Playwright coverage into a full Asset Manager V2 regression scenario including launch, add/remove, validation errors, selection details, export integrity, and import round-trip.
5+
6+
## Scope
7+
- `tests/ui/workspace-v2.asset-manager.spec.js`
8+
- `docs/dev/reports/PR_11_318D_report.md`
9+
- `docs/dev/codex_commands.md`
10+
- `docs/dev/commit_comment.txt`
11+
12+
## Steps
13+
1. Extend the existing UI test to cover Workspace startup baseline state.
14+
2. Validate session-aware producer launch into Asset Manager V2.
15+
3. Cover valid add, duplicate rejection, and blank-field rejection.
16+
4. Validate selection/details panel behavior.
17+
5. Validate removal behavior and status messaging.
18+
6. Validate exported workspace manifest contract shape and content.
19+
7. Validate import round-trip and Asset Manager reopen behavior from imported manifest.
20+
8. Run targeted syntax check and targeted Playwright spec only.

tests/playwright_installation.txt

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
Here are **clean, copy/paste instructions** to install Playwright on another machine/page.
2+
3+
---
4+
5+
## 🧪 Install Playwright (VS Code / Windows / Node)
6+
7+
### 1. Open project folder
8+
9+
```powershell
10+
cd C:\path\to\HTML-JavaScript-Gaming
11+
```
12+
13+
---
14+
15+
### 2. Initialize Node (if not already)
16+
17+
```powershell
18+
npm init -y
19+
```
20+
21+
---
22+
23+
### 3. Install Playwright test runner
24+
25+
```powershell
26+
npm install -D @playwright/test
27+
```
28+
29+
---
30+
31+
### 4. Install browsers
32+
33+
```powershell
34+
npx playwright install
35+
```
36+
37+
---
38+
39+
### 5. Verify install
40+
41+
```powershell
42+
npx playwright --version
43+
```
44+
45+
---
46+
47+
## ▶️ Run your test
48+
49+
```powershell
50+
npx playwright test tests/ui/workspace-v2.asset-manager.spec.js
51+
```
52+
53+
---
54+
55+
## 👀 Run with visible browser
56+
57+
```powershell
58+
npx playwright test --headed
59+
```
60+
61+
---
62+
63+
## 🐢 Slow motion (via config)
64+
65+
Create file at repo root:
66+
67+
```text
68+
playwright.config.cjs
69+
```
70+
71+
```javascript
72+
module.exports = {
73+
use: {
74+
headless: false,
75+
launchOptions: {
76+
slowMo: 500
77+
},
78+
trace: 'on'
79+
}
80+
};
81+
```
82+
83+
Then run:
84+
85+
```powershell
86+
npx playwright test
87+
```
88+
89+
---
90+
91+
## 🔍 View test replay
92+
93+
```powershell
94+
npx playwright show-trace
95+
```
96+
97+
---
98+
99+
## 📁 Required structure
100+
101+
```text
102+
HTML-JavaScript-Gaming/
103+
├── tests/
104+
│ └── ui/
105+
│ └── workspace-v2.asset-manager.spec.js <<<< test code goes here
106+
├── playwright.config.cjs
107+
├── package.json
108+
```
109+
110+
---
111+
112+
## 🚫 Important
113+
114+
```text
115+
✔ Keep node_modules at root
116+
✔ Do NOT move node_modules to tmp
117+
✔ tests/results is safe for outputs
118+
```
119+
120+
---
121+
122+
## 👍 That’s it
123+
124+
Once installed, the user can:
125+
126+
* run tests
127+
* see browser automation
128+
* replay test steps
129+
* validate Workspace V2 + tools automatically
130+
131+
---
132+
133+
If you want next:
134+
👉 I can generate a **README.md install section** you can drop into your repo 👍

tests/ui/workspace-v2.asset-manager.spec.js

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,45 +68,101 @@ async function startRepoServer() {
6868
test("workspace v2 launches asset manager and add/remove is reflected in export", async ({ page }) => {
6969
const server = await startRepoServer();
7070
try {
71+
// 1) Workspace V2 startup baseline
7172
await page.goto(`${server.baseUrl}/tools/workspace-v2/index.html`);
72-
7373
await page.getByRole("button", { name: "Full Reset" }).click();
74+
await expect(page.locator("#workspaceV2WorkspaceToolsSummary")).toContainText("palette-browser");
75+
await expect(page.locator("#workspaceV2WorkspaceToolsSummary")).toContainText("workspace-v2");
76+
77+
// 2) Producer launch to Asset Manager V2
7478
await page.locator("#workspaceV2ToolSelect").selectOption("asset-manager-v2");
7579
await page.getByRole("button", { name: "Load Fixture" }).click();
7680
await page.getByRole("button", { name: "Create Session + Launch" }).click();
77-
7881
await expect(page).toHaveURL(/\/tools\/asset-manager-v2\/index\.html/);
7982
await expect(page).toHaveTitle("Asset Manager V2");
83+
await expect(page.locator("#assetBrowserV2ContractReadout")).toContainText("payloadJson.assetCatalog valid");
8084
await expect(page.getByRole("button", { name: /Player Ship/ })).toBeVisible();
8185

86+
// 3) Add valid asset
8287
await page.locator("#assetManagerV2AddId").fill("asset-002");
8388
await page.locator("#assetManagerV2AddLabel").fill("Enemy Ship");
8489
await page.locator("#assetManagerV2AddKind").fill("svg");
8590
await page.locator("#assetManagerV2AddPath").fill("assets/vectors/enemy-ship.svg");
8691
await page.getByRole("button", { name: "Add Asset" }).click();
87-
8892
await expect(page.getByRole("button", { name: /Enemy Ship/ })).toBeVisible();
93+
await expect(page.locator("#assetManagerV2ActionStatus")).toHaveText("Asset 'asset-002' added.");
94+
95+
// 4) Reject duplicate id
96+
await page.locator("#assetManagerV2AddId").fill("asset-002");
97+
await page.locator("#assetManagerV2AddLabel").fill("Enemy Ship Duplicate");
98+
await page.locator("#assetManagerV2AddKind").fill("svg");
99+
await page.locator("#assetManagerV2AddPath").fill("assets/vectors/enemy-ship-duplicate.svg");
100+
await page.getByRole("button", { name: "Add Asset" }).click();
101+
await expect(page.locator("#assetManagerV2ActionStatus")).toHaveText("Add blocked. Asset id 'asset-002' already exists.");
102+
await expect(page.locator("#assetBrowserV2List").getByRole("button", { name: /Enemy Ship/ })).toHaveCount(1);
103+
104+
// 5) Reject blank fields
105+
await page.locator("#assetManagerV2AddId").fill(" ");
106+
await page.locator("#assetManagerV2AddLabel").fill(" ");
107+
await page.locator("#assetManagerV2AddKind").fill(" ");
108+
await page.locator("#assetManagerV2AddPath").fill(" ");
109+
await page.getByRole("button", { name: "Add Asset" }).click();
110+
await expect(page.locator("#assetManagerV2ActionStatus")).toContainText("Missing required field(s):");
111+
await expect(page.locator("#assetManagerV2ActionStatus")).toContainText("id");
112+
await expect(page.locator("#assetManagerV2ActionStatus")).toContainText("label");
113+
await expect(page.locator("#assetManagerV2ActionStatus")).toContainText("kind");
114+
await expect(page.locator("#assetManagerV2ActionStatus")).toContainText("path");
115+
await expect(page.locator("#assetBrowserV2List").getByRole("button", { name: /Enemy Ship/ })).toHaveCount(1);
116+
117+
// 6) Select asset/details
118+
await page.locator("#assetBrowserV2List").getByRole("button", { name: /Player Ship/ }).click();
119+
await expect(page.locator("#assetBrowserV2DetailId")).toHaveText("asset-001");
120+
await expect(page.locator("#assetBrowserV2DetailLabel")).toHaveText("Player Ship");
121+
await expect(page.locator("#assetBrowserV2DetailKind")).toHaveText("svg");
122+
await expect(page.locator("#assetBrowserV2DetailPath")).toHaveText("assets/vectors/player-ship.svg");
123+
124+
// 7) Remove asset
89125
await page.getByRole("button", { name: "Remove asset-002" }).click();
90126
await expect(page.getByRole("button", { name: /Enemy Ship/ })).toHaveCount(0);
127+
await expect(page.locator("#assetManagerV2ActionStatus")).toHaveText("Asset 'asset-002' removed.");
91128

129+
// 8) Export validation
92130
await page.getByRole("button", { name: /Back to Workspace V2/ }).click();
93131
await expect(page).toHaveURL(/\/tools\/workspace-v2\/index\.html/);
94-
95-
const downloadPromise = page.waitForEvent("download");
96132
await page.getByRole("button", { name: "Export Workspace Session JSON" }).click();
97-
const download = await downloadPromise;
98-
const downloadPath = await download.path();
99-
if (!downloadPath) {
100-
throw new Error("Workspace export did not produce a downloadable file.");
101-
}
102-
const exportedJsonText = await fs.readFile(downloadPath, "utf8");
133+
const exportedJsonText = await page.locator("#workspaceV2ImportJson").inputValue();
103134
const exported = JSON.parse(exportedJsonText);
104135
const entries = exported?.tools?.["workspace-v2"]?.activeSession?.payloadJson?.assetCatalog?.entries;
105136
if (!Array.isArray(entries)) {
106137
throw new Error("Exported manifest is missing tools.workspace-v2.activeSession.payloadJson.assetCatalog.entries.");
107138
}
139+
expect(exported.documentKind).toBe("workspace-manifest");
140+
expect(exported.tools?.["palette-browser"]).toBeTruthy();
141+
expect(exported.tools?.["workspace-v2"]).toBeTruthy();
142+
expect(exported.tools?.["workspace-v2"]?.activeSession?.toolId).toBe("asset-manager-v2");
108143
expect(entries.some((entry) => entry?.id === "asset-001")).toBe(true);
109144
expect(entries.some((entry) => entry?.id === "asset-002")).toBe(false);
145+
expect(Object.prototype.hasOwnProperty.call(exported, "workspaceSession")).toBe(false);
146+
expect(Object.prototype.hasOwnProperty.call(exported, "games")).toBe(false);
147+
expect(Object.prototype.hasOwnProperty.call(exported.tools || {}, "asset-manager-v2")).toBe(false);
148+
const exportedString = JSON.stringify(exported);
149+
expect(exportedString.includes("selectedAssetId")).toBe(false);
150+
expect(exportedString.includes("assetBrowserV2Detail")).toBe(false);
151+
152+
// 9) Import/export round trip
153+
const importFileChooserPromise = page.waitForEvent("filechooser");
154+
await page.getByRole("button", { name: "Import Workspace Session JSON" }).click();
155+
const importFileChooser = await importFileChooserPromise;
156+
await importFileChooser.setFiles({
157+
name: "workspace-v2-roundtrip.json",
158+
mimeType: "application/json",
159+
buffer: Buffer.from(exportedJsonText, "utf8")
160+
});
161+
await expect(page.locator("#workspaceV2ImportExportStatus")).toHaveText("Workspace session imported.");
162+
await page.getByRole("button", { name: /Open Asset Manager V2/ }).click();
163+
await expect(page).toHaveURL(/\/tools\/asset-manager-v2\/index\.html/);
164+
await expect(page.getByRole("button", { name: /Player Ship/ })).toBeVisible();
165+
await expect(page.locator("#assetBrowserV2InvalidState")).toBeHidden();
110166
} finally {
111167
await server.close();
112168
}

0 commit comments

Comments
 (0)