Skip to content

Commit 5cdd959

Browse files
committed
PR_26174_ALFA_005-idea-project-validation-polish
1 parent 2b2e75d commit 5cdd959

8 files changed

Lines changed: 286 additions & 231 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Branch Validation: PASS
2+
3+
PASS - Current branch: pr/26174-ALFA-005-idea-project-validation-polish.
4+
PASS - Stack base: pr/26174-ALFA-004-game-hub-progress-count-model.
5+
PASS - Changes are scoped to missing targeted Idea Board tests and required reports.
6+
PASS - No merge to main performed.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Manual Validation Notes: PASS
2+
3+
PASS - Confirmed non-Ready Idea Board rows do not expose Create Project.
4+
PASS - Confirmed a Refining idea exposes Create Project only after status changes to Ready.
5+
PASS - Confirmed a converted Project idea has no Edit/Delete controls, no Add Note control, and no note edit/delete actions.
6+
PASS - Confirmed guest Create Project redirects to /account/sign-in.html and does not call createGame.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Requirement Checklist: PASS
2+
3+
PASS - Validates Ready-only Create Project behavior.
4+
PASS - Validates converted Project ideas stay locked/read-only.
5+
PASS - Validates guest Create Project redirects to account/sign-in.html.
6+
PASS - Added missing targeted tests only; no production code changed.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Validation Lane: PASS
2+
3+
Targeted Playwright impacted lane:
4+
PASS - npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board gates Create Project|Idea Board guest Create Project"
5+
6+
Notes:
7+
- Full workspace smoke was not run; targeted impacted Playwright validation was used per request.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# PR_26174_ALFA_005-idea-project-validation-polish
2+
3+
## Purpose
4+
5+
Polish Idea Board project-creation validation coverage.
6+
7+
## Summary
8+
9+
- Added a focused targeted Playwright test for Ready-only Create Project gating.
10+
- Validated converted Project ideas expose only project-safe actions and keep notes read-only.
11+
- Reused the existing targeted guest Create Project redirect test as part of this validation lane.
12+
13+
## Validation
14+
15+
PASS - `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board gates Create Project|Idea Board guest Create Project"`
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
src/dev-runtime/persistence/tool-repositories/game-journey-mock-repository.js
2-
tests/playwright/tools/GameJourneyTool.spec.mjs
1+
tests/playwright/tools/IdeaBoardTableNotes.spec.mjs
32
docs_build/dev/reports/codex_review.diff
43
docs_build/dev/reports/codex_changed_files.txt
5-
docs_build/dev/reports/PR_26174_ALFA_004-game-hub-progress-count-model.md
6-
docs_build/dev/reports/PR_26174_ALFA_004-game-hub-progress-count-model-branch-validation.txt
7-
docs_build/dev/reports/PR_26174_ALFA_004-game-hub-progress-count-model-requirement-checklist.txt
8-
docs_build/dev/reports/PR_26174_ALFA_004-game-hub-progress-count-model-validation-lane.txt
9-
docs_build/dev/reports/PR_26174_ALFA_004-game-hub-progress-count-model-manual-validation-notes.txt
4+
docs_build/dev/reports/PR_26174_ALFA_005-idea-project-validation-polish.md
5+
docs_build/dev/reports/PR_26174_ALFA_005-idea-project-validation-polish-branch-validation.txt
6+
docs_build/dev/reports/PR_26174_ALFA_005-idea-project-validation-polish-requirement-checklist.txt
7+
docs_build/dev/reports/PR_26174_ALFA_005-idea-project-validation-polish-validation-lane.txt
8+
docs_build/dev/reports/PR_26174_ALFA_005-idea-project-validation-polish-manual-validation-notes.txt

docs_build/dev/reports/codex_review.diff

Lines changed: 123 additions & 224 deletions
Large diffs are not rendered by default.

tests/playwright/tools/IdeaBoardTableNotes.spec.mjs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,123 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => {
429429
}
430430
});
431431

432+
test("Idea Board gates Create Project to Ready ideas and locks converted projects", async ({ page }) => {
433+
const server = await startRepoServer({
434+
gameJourneyCompletionMetricsLegacyDbPath: null,
435+
gameJourneyCompletionMetricsPostgresClient: createGameJourneyCompletionMetricsPostgresClientStub(),
436+
});
437+
const previousApiUrl = process.env.GAMEFOUNDRY_API_URL;
438+
const previousSiteUrl = process.env.GAMEFOUNDRY_SITE_URL;
439+
const previousSupabaseEnv = {
440+
GAMEFOUNDRY_DATABASE_URL: process.env.GAMEFOUNDRY_DATABASE_URL,
441+
GAMEFOUNDRY_SUPABASE_ANON_KEY: process.env.GAMEFOUNDRY_SUPABASE_ANON_KEY,
442+
GAMEFOUNDRY_SUPABASE_SERVICE_ROLE_KEY: process.env.GAMEFOUNDRY_SUPABASE_SERVICE_ROLE_KEY,
443+
GAMEFOUNDRY_SUPABASE_URL: process.env.GAMEFOUNDRY_SUPABASE_URL,
444+
};
445+
process.env.GAMEFOUNDRY_API_URL = `${server.baseUrl}/api`;
446+
process.env.GAMEFOUNDRY_SITE_URL = server.baseUrl;
447+
process.env.GAMEFOUNDRY_DATABASE_URL = "postgres://idea-board:test@127.0.0.1:5432/idea_board";
448+
process.env.GAMEFOUNDRY_SUPABASE_ANON_KEY = "idea-board-anon-key";
449+
process.env.GAMEFOUNDRY_SUPABASE_SERVICE_ROLE_KEY = "idea-board-service-role-key";
450+
process.env.GAMEFOUNDRY_SUPABASE_URL = `${server.baseUrl}/fake-supabase`;
451+
const createGameRequests = [];
452+
const failedRequests = [];
453+
const pageErrors = [];
454+
const consoleErrors = [];
455+
456+
page.on("request", (request) => {
457+
const requestUrl = request.url();
458+
if (requestUrl.includes("/api/toolbox/game-hub/repositories/") && requestUrl.includes("/methods/createGame")) {
459+
createGameRequests.push(request.postDataJSON());
460+
}
461+
});
462+
page.on("response", (response) => {
463+
if (response.status() >= 400) failedRequests.push(`${response.status()} ${response.url()}`);
464+
});
465+
page.on("pageerror", (error) => {
466+
const text = error.stack || error.message;
467+
if (!isBrowserExtensionNoise(text)) pageErrors.push(error.message);
468+
});
469+
page.on("console", (message) => {
470+
if (message.type() === "error" && !isBrowserExtensionNoise(message.text())) consoleErrors.push(message.text());
471+
});
472+
473+
try {
474+
await page.route("**/api/platform-settings/banner", async (route) => {
475+
await route.fulfill({
476+
contentType: "application/json",
477+
body: JSON.stringify({
478+
data: { banner: { active: false, message: "", tone: "info" } },
479+
ok: true,
480+
}),
481+
});
482+
});
483+
await page.route("**/api/toolbox/registry/snapshot", async (route) => {
484+
await route.fulfill({
485+
contentType: "application/json",
486+
body: JSON.stringify({
487+
data: {
488+
activeTools: [],
489+
readinessByStatus: {},
490+
tools: [],
491+
toolboxContract: {},
492+
},
493+
ok: true,
494+
}),
495+
});
496+
});
497+
await page.request.post(`${server.baseUrl}/api/session/user`, {
498+
data: { userKey: MOCK_DB_KEYS.users.user1 },
499+
});
500+
501+
await page.goto(`${server.baseUrl}/toolbox/idea-board/index.html`, { waitUntil: "networkidle" });
502+
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] [data-idea-board-idea-action='create-project']")).toHaveCount(0);
503+
await expect(page.locator("[data-idea-board-idea-row='sky-orchard'] [data-idea-board-idea-action='create-project']")).toHaveCount(0);
504+
await expect(page.locator("[data-idea-board-idea-row='clockwork-courier'] [data-idea-board-idea-action='create-project']")).toHaveCount(0);
505+
506+
await page.locator("[data-idea-board-add-idea]").click();
507+
await page.locator("[data-idea-board-idea-input]").fill("Validation Reef");
508+
await page.locator("[data-idea-board-pitch-input]").fill("Verify project gating and read-only conversion.");
509+
await page.locator("[data-idea-board-idea-status-input]").selectOption("Refining");
510+
await page.locator("[data-idea-board-idea-action='save']").click();
511+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] td").nth(1)).toHaveText("Refining");
512+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action='create-project']")).toHaveCount(0);
513+
expect(createGameRequests).toEqual([]);
514+
515+
await page.locator("[data-idea-board-idea-cell='validation-reef']").click();
516+
await page.locator("[data-idea-board-add-note='validation-reef']").click();
517+
await page.locator("[data-idea-board-note-input]").fill("This note should become read-only project context.");
518+
await page.locator("[data-idea-board-note-action='save']").click();
519+
await expect(page.locator("[data-idea-board-notes-count='validation-reef']")).toHaveText("1 Note");
520+
521+
await page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action='edit']").click();
522+
await page.locator("[data-idea-board-idea-status-input]").selectOption("Ready");
523+
await page.locator("[data-idea-board-idea-action='save']").click();
524+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] td").nth(1)).toHaveText("Ready");
525+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action]")).toHaveText(["Edit", "Create Project", "Delete"]);
526+
527+
await page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action='create-project']").click();
528+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] td").nth(1)).toHaveText("Project");
529+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action]")).toHaveText(["Open in Game Hub", "Archive"]);
530+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action='edit']")).toHaveCount(0);
531+
await expect(page.locator("[data-idea-board-idea-row='validation-reef'] [data-idea-board-idea-action='delete']")).toHaveCount(0);
532+
await expect(page.locator("[data-idea-board-add-note='validation-reef']")).toHaveCount(0);
533+
await expect(page.locator("[data-idea-board-notes-table='validation-reef'] [data-idea-board-note-action]")).toHaveCount(0);
534+
await expect(page.locator("[data-idea-board-note-input-row]")).toHaveCount(0);
535+
expect(createGameRequests).toHaveLength(1);
536+
expect(Object.keys(createGameRequests[0].args[0]).sort()).toEqual(["name", "purpose", "sourceIdea", "status"]);
537+
538+
expect(failedRequests).toEqual([]);
539+
expect(pageErrors).toEqual([]);
540+
expect(consoleErrors).toEqual([]);
541+
} finally {
542+
restoreEnvValue("GAMEFOUNDRY_API_URL", previousApiUrl);
543+
restoreEnvValue("GAMEFOUNDRY_SITE_URL", previousSiteUrl);
544+
Object.entries(previousSupabaseEnv).forEach(([key, value]) => restoreEnvValue(key, value));
545+
await server.close();
546+
}
547+
});
548+
432549
test("Idea Board guest Create Project redirects to sign in without creating a project", async ({ page }) => {
433550
const server = await startRepoServer();
434551
const previousApiUrl = process.env.GAMEFOUNDRY_API_URL;

0 commit comments

Comments
 (0)