Skip to content

Commit 6a97a54

Browse files
author
DavidQ
committed
Gate Workspace Manager game selection and tools until repo and active game are explicitly selected - PR_26128_009-workspace-selection-gates
1 parent a9c4a7a commit 6a97a54

5 files changed

Lines changed: 104 additions & 1 deletion

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Playwright Workspace Selection Gates
2+
3+
## Command
4+
`npm run test:workspace-v2`
5+
6+
## Result
7+
PASS: 12 passed
8+
9+
## Targeted Coverage
10+
- Verified initial Workspace Manager V2 load has an empty disabled Active Game dropdown.
11+
- Verified stale sessionStorage does not preselect Asteroids on direct initial load.
12+
- Verified workspace tools are disabled before repo selection.
13+
- Verified repo selection discovers and validates `game.manifest.json` files.
14+
- Verified Active Game enables after valid games are found.
15+
- Verified no game is auto-selected after discovery.
16+
- Verified workspace tools remain disabled until the user manually selects a valid game.
17+
- Verified workspace tools enable after a valid game selection.
18+
- Verified failed repo load clears and disables Active Game and keeps tools disabled.
19+
- Verified no-valid-games discovery keeps Active Game disabled and tools disabled.
20+
- Verified invalid manifests are skipped and logged with exact path and validation reason.
21+
22+
## Skipped
23+
- Full samples smoke test was skipped as requested. The targeted Workspace Manager V2 Playwright suite covers the changed selection gates, repo discovery, invalid-manifest logging, and affected launch gating behavior.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# PR_26128_009 Workspace Selection Gates
2+
3+
## Summary
4+
- Workspace Manager V2 now ignores stale stored workspace context on plain initial load.
5+
- Explicit `hostContextId` URLs still restore workspace context for the existing return-from-tool flow.
6+
- Active Game remains empty and disabled on initial load.
7+
- Tools remain disabled before repo selection, after repo discovery, after failed repo load, and when no valid games are found.
8+
- Tools enable only after the user manually selects a valid discovered game.
9+
10+
## Selection Flow
11+
- User selects a repo folder.
12+
- Workspace Manager V2 recursively scans `games/` for `game.manifest.json`.
13+
- Each discovered game manifest validates against the dedicated game manifest schema.
14+
- Invalid manifests are skipped and logged with exact path and reason.
15+
- Active Game enables only when one or more valid games are found.
16+
- No game is auto-selected after discovery.
17+
- The user manually selects a game before workspace tools become enabled.
18+
19+
## Scope Notes
20+
- `game.manifest.json` remains the only required game project manifest.
21+
- No separate `workspace.manifest.json` was introduced.
22+
- No sample JSON was modified.
23+
- No roadmap content was modified.
24+
- No cross-tool communication was added.
25+
- Full samples smoke test was skipped because this BUILD requested targeted Workspace Manager V2 validation and explicitly said to skip full samples smoke.
26+
27+
## Validation
28+
- PASS: `node --check tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js`
29+
- PASS: `node --check tests/playwright/tools/WorkspaceManagerV2.spec.mjs`
30+
- PASS: `npm run test:workspace-v2` - 12 passed

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ async function selectMockRepo(page, { repoName = "HTML-JavaScript-Gaming" } = {}
132132
"Gravity Well",
133133
"Pong"
134134
]);
135+
await expectWorkspaceToolsDisabled(page);
136+
}
137+
138+
async function expectWorkspaceToolsDisabled(page) {
139+
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(4);
140+
expect(await page.locator("#workspaceToolTiles [data-workspace-tool-id]").evaluateAll((tiles) => tiles.every((tile) => tile.disabled))).toBe(true);
135141
}
136142

137143
test.describe("Workspace Manager V2 bootstrap", () => {
@@ -263,6 +269,33 @@ test.describe("Workspace Manager V2 bootstrap", () => {
263269
}
264270
});
265271

272+
test("starts with no active game even when stale session state exists", async ({ page }) => {
273+
const staleGameManifest = JSON.parse(await readFile("games/Asteroids/game.manifest.json", "utf8"));
274+
const pageErrors = [];
275+
await page.addInitScript((manifest) => {
276+
window.sessionStorage.setItem("workspace-manager-v2-stale-context", JSON.stringify(manifest));
277+
window.sessionStorage.setItem("workspace-manager-v2-active-host-context-id", "workspace-manager-v2-stale-context");
278+
}, staleGameManifest.game.workspace);
279+
const server = await openWorkspaceManagerV2(page);
280+
281+
page.on("pageerror", (error) => {
282+
pageErrors.push(error.message);
283+
});
284+
285+
try {
286+
await expect(page.locator("#repoSelectedValue")).toHaveText("not selected");
287+
await expect(page.locator("#activeGameSelect")).toBeDisabled();
288+
await expect(page.locator("#activeGameSelect option")).toHaveCount(0);
289+
await expect(page.locator("#workspaceContextOutput")).toHaveValue("{}");
290+
await expectWorkspaceToolsDisabled(page);
291+
await expect(page.locator("#statusLog")).not.toHaveValue(/Restored Asteroids workspace/);
292+
expect(pageErrors).toEqual([]);
293+
} finally {
294+
await coverageReporter.stop(page);
295+
await server.close();
296+
}
297+
});
298+
266299
test("discovers Active Game options from selected repo manifests", async ({ page }) => {
267300
const server = await openWorkspaceManagerV2(page);
268301
const pageErrors = [];
@@ -275,6 +308,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
275308
await expect(page.locator("#activeGameSelect")).toBeDisabled();
276309
await expect(page.locator("#activeGameSelect option")).toHaveCount(0);
277310
await expect(page.locator("#activeGameSummary")).toHaveText("Pick a repo folder to discover schema-valid game manifests.");
311+
await expectWorkspaceToolsDisabled(page);
278312

279313
await selectMockRepo(page);
280314
await expect(page.locator("#activeGameSummary")).toHaveText("Discovered 3 schema-valid game manifests from HTML-JavaScript-Gaming.");
@@ -322,9 +356,25 @@ test.describe("Workspace Manager V2 bootstrap", () => {
322356
await expect(page.locator("#repoSelectedValue")).toHaveText("not selected");
323357
await expect(page.locator("#activeGameSelect")).toBeDisabled();
324358
await expect(page.locator("#activeGameSelect option")).toHaveCount(0);
359+
await expectWorkspaceToolsDisabled(page);
325360
await expect(page.locator("#activeGameSummary")).toHaveText(/Selected repo is missing games\//);
326361
await expect(page.locator("#statusLog")).toHaveValue(/FAIL Repo load failed: Selected repo is missing games\//);
327362

363+
await page.evaluate(() => {
364+
window.__workspaceManagerV2MockRepoConfig = {
365+
manifestPaths: [],
366+
repoName: "NoValidGamesRepo"
367+
};
368+
});
369+
await page.locator("#pickRepoBtn").click();
370+
await expect(page.locator("#repoSelectedValue")).toHaveText("NoValidGamesRepo");
371+
await expect(page.locator("#activeGameSelect")).toBeDisabled();
372+
await expect(page.locator("#activeGameSelect option")).toHaveCount(0);
373+
await expectWorkspaceToolsDisabled(page);
374+
await expect(page.locator("#activeGameSummary")).toHaveText("No schema-valid game manifests were found in NoValidGamesRepo.");
375+
await expect(page.locator("#statusLog")).toHaveValue(/INFO SKIP games\/InvalidWorkspace\/game\.manifest\.json: Game manifest failed schema validation: root\.game is required/);
376+
await expect(page.locator("#statusLog")).toHaveValue(/FAIL Repo load failed: No schema-valid game\.manifest\.json files were found in NoValidGamesRepo\./);
377+
328378
await selectMockRepo(page, { repoName: "SecondRepo" });
329379
await expect(page.locator("#activeGameSummary")).toHaveText("Discovered 3 schema-valid game manifests from SecondRepo.");
330380
await expect(page.locator("#workspaceContextOutput")).toHaveValue("{}");

tools/schemas.zip

-22.5 KB
Binary file not shown.

tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ export class WorkspaceManagerV2ContextService {
349349

350350
async restorePersistedContext() {
351351
const params = new URLSearchParams(this.location.search || "");
352-
const hostContextId = params.get("hostContextId") || this.sessionStorage.getItem(HOST_CONTEXT_STORAGE_KEY) || "";
352+
const hostContextId = params.get("hostContextId") || "";
353353
return this.restorePersistedContextById(hostContextId);
354354
}
355355

0 commit comments

Comments
 (0)