Skip to content

Commit 7a4eb9a

Browse files
author
DavidQ
committed
Correct Playwright toolState scope to exclude palette manager while preserving global palette validation - PR_26124_016-fix-playwright-toolstate-scope
1 parent 7e202f4 commit 7a4eb9a

6 files changed

Lines changed: 140 additions & 39 deletions
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# PR_26124_016-fix-playwright-toolstate-scope
2+
3+
## Scope
4+
- Playwright validation/tests and audit/report integration only.
5+
- No runtime code changes.
6+
- No schema changes.
7+
8+
## Changes
9+
- Updated `tests/playwright/tool-validation/workspace-v2.tool-validation.spec.js`:
10+
- Removed `palette-manager-v2` from toolState-capable tool selector map.
11+
- Added explicit assertion that toolState-capable scope excludes `palette-manager-v2`.
12+
- Kept full audited tool list visibility assertion.
13+
- Switched workspace import helper to hidden file input `setInputFiles` for deterministic import flow.
14+
- Updated `tests/playwright/workspace-v2.validation.spec.js`:
15+
- Added producer assertions:
16+
- `palette-manager-v2` is not present in Producer/Tool options.
17+
- default selected tool is not `palette-manager-v2`.
18+
- `Load Tool State` works for `asset-manager-v2`.
19+
- `Create & Open Tool State` works for `asset-manager-v2`.
20+
- Switched import helper to hidden file input `setInputFiles`.
21+
- Stabilized tool-switch test by reading manifest from textarea after fixture load.
22+
- Updated `scripts/update-tool-completion-audit-from-playwright.mjs`:
23+
- Distinguishes `palette-manager-v2` as global workspace palette state coverage via `tools.palette-browser.swatches`.
24+
- Treats `palette-manager-v2` as excluded from toolState-capable mapping.
25+
- Added `Scope` column in `docs/dev/reports/tool_validation_results.md`.
26+
27+
## Validation
28+
- `node --check tests/playwright/tool-validation/workspace-v2.tool-validation.spec.js` -> pass
29+
- `node --check tests/playwright/workspace-v2.validation.spec.js` -> pass
30+
- `node --check scripts/update-tool-completion-audit-from-playwright.mjs` -> pass
31+
- `npm run test:workspace-v2` -> pass (`19 passed`, `0 failed`)
32+
33+
## Notes
34+
- Full samples smoke test was skipped because this PR changes only Playwright scope/assertions and report mapping logic, not shared sample/runtime framework behavior.

docs/dev/reports/tool_completion_audit.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
- `vector-map-editor-v2`
1212

1313
## Evidence Used
14-
- `npm run test:workspace-v2` -> PASS (`17 passed`, `0 failed`).
14+
- `npm run test:workspace-v2` -> PASS (`19 passed`, `0 failed`).
1515
- `node tests/runtime/V2CrossToolFlow.test.mjs` -> PASS.
1616
- `node tests/runtime/V2ToolLaunch.test.mjs` -> FAIL (palette fixture contract drift in test logic).
1717
- `node tests/runtime/V2ToolActionFlow.test.mjs` -> FAIL (string-token matcher drift in test logic).
@@ -44,8 +44,8 @@
4444
- Required fix: none
4545

4646
### palette-manager-v2
47-
- **Status:** FAIL
48-
- Exact failure reason: No Playwright tool-level tests found for this tool.
47+
- **Status:** PASS
48+
- Exact failure reason: Validated as global workspace palette state via tools.palette-browser.swatches; excluded from toolState-capable tool validation.
4949

5050
- Valid JSON loads + expected UI: PASS by code contract (`payloadJson.paletteDocument`) and fixture shape alignment
5151
- Invalid JSON rejected + clear error: PASS
@@ -129,6 +129,30 @@
129129

130130

131131

132+
133+
134+
135+
136+
137+
138+
139+
140+
141+
142+
143+
144+
145+
146+
147+
148+
149+
150+
151+
152+
153+
154+
155+
132156

133157

134158

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# Tool Validation Results
22

33
Derived from `tests/results/playwright-results.json` generated by `npm run test:workspace-v2`.
4+
`palette-manager-v2` is tracked as global workspace palette state (`tools.palette-browser.swatches`) and excluded from toolState-capable validation scope.
45

5-
| Tool | Status | Failing Reason |
6-
| --- | --- | --- |
7-
| `workspace-v2` | PASS | n/a |
8-
| `asset-manager-v2` | PASS | n/a |
9-
| `palette-manager-v2` | FAIL | No Playwright tool-level tests found for this tool. |
10-
| `svg-asset-studio-v2` | PASS | n/a |
11-
| `tilemap-studio-v2` | PASS | n/a |
12-
| `vector-map-editor-v2` | PASS | n/a |
6+
| Tool | Scope | Status | Failing Reason |
7+
| --- | --- | --- | --- |
8+
| `workspace-v2` | ToolState-capable Tool | PASS | n/a |
9+
| `asset-manager-v2` | ToolState-capable Tool | PASS | n/a |
10+
| `palette-manager-v2` | Global Workspace Palette State | PASS | n/a |
11+
| `svg-asset-studio-v2` | ToolState-capable Tool | PASS | n/a |
12+
| `tilemap-studio-v2` | ToolState-capable Tool | PASS | n/a |
13+
| `vector-map-editor-v2` | ToolState-capable Tool | PASS | n/a |
1314

scripts/update-tool-completion-audit-from-playwright.mjs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,34 @@ function collectAllPlaywrightTests(playwrightJson) {
7979
return tests;
8080
}
8181

82+
function isGlobalPaletteStateTool(toolId) {
83+
return toolId === "palette-manager-v2";
84+
}
85+
8286
function getToolStatusFromTests(toolId, tests) {
87+
if (isGlobalPaletteStateTool(toolId)) {
88+
const paletteContractTests = tests.filter((test) => test.fullTitle.includes("palette contract: palette-browser exists, swatches empty, one palette entry"));
89+
if (paletteContractTests.length === 0) {
90+
return {
91+
status: "FAIL",
92+
reason: "Global palette contract test was not found."
93+
};
94+
}
95+
const failedPaletteContractTest = paletteContractTests.find((test) => test.status !== "passed");
96+
if (failedPaletteContractTest) {
97+
const failureMessage = failedPaletteContractTest.error
98+
? failedPaletteContractTest.error.replace(/\s+/g, " ").trim()
99+
: "Global palette contract test failed.";
100+
return {
101+
status: "FAIL",
102+
reason: `${failedPaletteContractTest.fullTitle}${failureMessage ? ` -> ${failureMessage}` : ""}`
103+
};
104+
}
105+
return {
106+
status: "PASS",
107+
reason: "Validated as global workspace palette state via tools.palette-browser.swatches; excluded from toolState-capable tool validation."
108+
};
109+
}
83110
const matchingTests = tests.filter((test) => test.fullTitle.includes(`@${toolId}`) || test.title.includes(`@${toolId}`));
84111
if (matchingTests.length === 0) {
85112
return {
@@ -130,13 +157,15 @@ function buildValidationReport(toolIds, toolStatuses) {
130157
lines.push("# Tool Validation Results");
131158
lines.push("");
132159
lines.push("Derived from `tests/results/playwright-results.json` generated by `npm run test:workspace-v2`.");
160+
lines.push("`palette-manager-v2` is tracked as global workspace palette state (`tools.palette-browser.swatches`) and excluded from toolState-capable validation scope.");
133161
lines.push("");
134-
lines.push("| Tool | Status | Failing Reason |");
135-
lines.push("| --- | --- | --- |");
162+
lines.push("| Tool | Scope | Status | Failing Reason |");
163+
lines.push("| --- | --- | --- | --- |");
136164
for (const toolId of toolIds) {
137165
const entry = toolStatuses[toolId];
138166
const reasonText = entry.status === "FAIL" ? entry.reason : "n/a";
139-
lines.push(`| \`${toolId}\` | ${entry.status} | ${reasonText.replace(/\|/g, "\\|")} |`);
167+
const scope = isGlobalPaletteStateTool(toolId) ? "Global Workspace Palette State" : "ToolState-capable Tool";
168+
lines.push(`| \`${toolId}\` | ${scope} | ${entry.status} | ${reasonText.replace(/\|/g, "\\|")} |`);
140169
}
141170
lines.push("");
142171
return `${lines.join("\n")}\n`;

tests/playwright/tool-validation/workspace-v2.tool-validation.spec.js

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import fs from "node:fs";
33
import path from "node:path";
44
import { fileURLToPath } from "node:url";
55
import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs";
6-
import { ctrlTapClick } from "../../helpers/playwrightCtrlTapClick.mjs";
76

87
const __filename = fileURLToPath(import.meta.url);
98
const __dirname = path.dirname(__filename);
@@ -69,10 +68,7 @@ function buildWorkspaceManifest(toolStateContext, hostContextId) {
6968
}
7069

7170
async function importWorkspaceManifest(page, manifest) {
72-
const chooserPromise = page.waitForEvent("filechooser");
73-
await ctrlTapClick(page, page.getByRole("button", { name: "Import Workspace Tool State JSON" }));
74-
const chooser = await chooserPromise;
75-
await chooser.setFiles({
71+
await page.locator("#workspaceV2ImportFile").setInputFiles({
7672
name: "workspace-v2-tool-validation-import.json",
7773
mimeType: "application/json",
7874
buffer: Buffer.from(JSON.stringify(manifest, null, 2), "utf8")
@@ -95,13 +91,6 @@ const toolSelectors = {
9591
validToken: "payloadJson.assetCatalog valid",
9692
invalidToken: "payloadJson.assetCatalog invalid"
9793
},
98-
"palette-manager-v2": {
99-
valid: "#paletteManagerValidState",
100-
invalid: "#paletteManagerInvalidState",
101-
readout: "#paletteManagerContractReadout",
102-
validToken: "payloadJson.paletteDocument valid",
103-
invalidToken: "payloadJson.paletteDocument invalid"
104-
},
10594
"svg-asset-studio-v2": {
10695
valid: "#svgV2ValidState",
10796
invalid: "#svgV2InvalidState",
@@ -140,6 +129,10 @@ test("@workspace-v2 tool validation list includes all audited tools", async () =
140129
]);
141130
});
142131

132+
test("@workspace-v2 toolState-capable validation scope excludes palette-manager-v2", async () => {
133+
expect(workspaceToolStateCapableToolIds).not.toContain("palette-manager-v2");
134+
});
135+
143136
test("@workspace-v2 valid workspace manifest payloadJson imports", async ({ page }) => {
144137
const server = await startRepoServer();
145138
try {

tests/playwright/workspace-v2.validation.spec.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@ import { startRepoServer } from "../helpers/playwrightRepoServer.mjs";
33
import { ctrlTapClick } from "../helpers/playwrightCtrlTapClick.mjs";
44

55
async function importManifestFromObject(page, manifest) {
6-
const chooserPromise = page.waitForEvent("filechooser");
7-
await ctrlTapClick(page, page.getByRole("button", { name: "Import Workspace Tool State JSON" }));
8-
const chooser = await chooserPromise;
96
const jsonText = JSON.stringify(manifest, null, 2);
10-
await chooser.setFiles({
7+
await page.locator("#workspaceV2ImportFile").setInputFiles({
118
name: "workspace-v2-import.json",
129
mimeType: "application/json",
1310
buffer: Buffer.from(jsonText, "utf8")
@@ -16,12 +13,35 @@ async function importManifestFromObject(page, manifest) {
1613
}
1714

1815
async function exportManifestFromTextarea(page) {
19-
await ctrlTapClick(page, page.getByRole("button", { name: "Export Workspace Tool State JSON" }));
16+
await page.getByRole("button", { name: "Export Workspace Tool State JSON" }).click();
2017
const exportedText = await page.locator("#workspaceV2ImportJson").inputValue();
2118
return JSON.parse(exportedText);
2219
}
2320

2421
test.describe("Workspace V2 validation coverage", () => {
22+
test("producer tool selection excludes palette-manager-v2 and asset-manager load/create actions work", async ({ page }) => {
23+
const server = await startRepoServer();
24+
try {
25+
await page.goto(`${server.baseUrl}/tools/workspace-v2/index.html`);
26+
await ctrlTapClick(page, page.getByRole("button", { name: "Full Reset" }));
27+
28+
await expect(page.locator("#workspaceV2ToolSelect option[value='palette-manager-v2']")).toHaveCount(0);
29+
await expect(page.locator("#workspaceV2ToolSelect")).not.toHaveValue("palette-manager-v2");
30+
31+
await page.locator("#workspaceV2ToolSelect").selectOption("asset-manager-v2");
32+
await page.locator("#workspaceV2LoadFixtureButton").click();
33+
await expect(page.locator("#workspaceV2Status")).toContainText("Fixture loaded for asset-manager-v2.");
34+
35+
await ctrlTapClick(page, page.getByRole("button", { name: "Create & Open Tool State" }));
36+
await expect(page).toHaveURL(/\/tools\/asset-manager-v2\/index\.html/);
37+
38+
await ctrlTapClick(page, page.getByRole("button", { name: /Back to Workspace V2/ }));
39+
await expect(page).toHaveURL(/\/tools\/workspace-v2\/index\.html/);
40+
} finally {
41+
await server.close();
42+
}
43+
});
44+
2545
test("workspace lifecycle reset -> valid import -> export -> import success", async ({ page }) => {
2646
const server = await startRepoServer();
2747
try {
@@ -152,16 +172,16 @@ test.describe("Workspace V2 validation coverage", () => {
152172
await ctrlTapClick(page, page.getByRole("button", { name: "Full Reset" }));
153173

154174
await page.locator("#workspaceV2ToolSelect").selectOption("tilemap-studio-v2");
155-
await ctrlTapClick(page, page.getByRole("button", { name: "Load Tool State" }));
156-
let exportedManifest = await exportManifestFromTextarea(page);
157-
expect(exportedManifest.tools?.["workspace-v2"]?.activeToolId).toBe("tilemap-studio-v2");
158-
expect(exportedManifest.tools?.["workspace-v2"]?.activeToolState?.toolId).toBe("tilemap-studio-v2");
175+
await page.locator("#workspaceV2LoadFixtureButton").click();
176+
let manifest = JSON.parse(await page.locator("#workspaceV2ImportJson").inputValue());
177+
expect(manifest.tools?.["workspace-v2"]?.activeToolId).toBe("tilemap-studio-v2");
178+
expect(manifest.tools?.["workspace-v2"]?.activeToolState?.toolId).toBe("tilemap-studio-v2");
159179

160180
await page.locator("#workspaceV2ToolSelect").selectOption("vector-map-editor-v2");
161-
await ctrlTapClick(page, page.getByRole("button", { name: "Load Tool State" }));
162-
exportedManifest = await exportManifestFromTextarea(page);
163-
expect(exportedManifest.tools?.["workspace-v2"]?.activeToolId).toBe("vector-map-editor-v2");
164-
expect(exportedManifest.tools?.["workspace-v2"]?.activeToolState?.toolId).toBe("vector-map-editor-v2");
181+
await page.locator("#workspaceV2LoadFixtureButton").click();
182+
manifest = JSON.parse(await page.locator("#workspaceV2ImportJson").inputValue());
183+
expect(manifest.tools?.["workspace-v2"]?.activeToolId).toBe("vector-map-editor-v2");
184+
expect(manifest.tools?.["workspace-v2"]?.activeToolState?.toolId).toBe("vector-map-editor-v2");
165185
} finally {
166186
await server.close();
167187
}

0 commit comments

Comments
 (0)