diff --git a/assets/toolbox/idea-board/js/index.js b/assets/toolbox/idea-board/js/index.js index 47a5ed91e..25607bc8d 100644 --- a/assets/toolbox/idea-board/js/index.js +++ b/assets/toolbox/idea-board/js/index.js @@ -129,6 +129,10 @@ function previousStatusForRestore(record) { : "Refining"; } +function isEditableStatus(status) { + return editableStatusOptions.includes(status); +} + function rememberPreviousStatus(record) { if (record.status !== "Archived") { record.previousStatus = record.status; @@ -436,7 +440,7 @@ function saveIdeaRow(root, row) { const idea = row.querySelector("[data-idea-board-idea-input]")?.value.trim(); const pitch = row.querySelector("[data-idea-board-pitch-input]")?.value.trim(); const status = row.querySelector("[data-idea-board-idea-status-input]")?.value; - if (!idea || !pitch || !status) { + if (!idea || !pitch || !isEditableStatus(status)) { updateStatus(root, "Enter an idea, pitch, and status before saving."); return; } diff --git a/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md b/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md new file mode 100644 index 000000000..dc24d4ee4 --- /dev/null +++ b/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md @@ -0,0 +1,60 @@ +# PR_26175_ALFA_018 - Alfa Idea Board Polish Consolidation + +## Executive Summary + +PASS - Consolidated the remaining current-main-safe Alfa Batch D Idea Board status dropdown guard. + +Current `main` already contained the #114, #115, and #116 structural work: the status filter is in the left accordion, the Idea Board parent table no longer has the Updated column, idea labels wrap, editable status dropdowns list only `New`, `Exploring`, `Refining`, and `Ready`, and status filters list `New`, `Exploring`, `Refining`, `Ready`, `Project`, and `Archived`. + +This PR adds a runtime save guard so stale or injected editable dropdown values cannot persist non-editable statuses such as `Project` or `Archived`. + +## Runtime Files Changed + +| File | Change | +| --- | --- | +| `assets/toolbox/idea-board/js/index.js` | Adds an editable-status validation helper and rejects add/edit saves when the submitted status is not one of the editable statuses. | +| `tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | Adds focused coverage that injects a stale `Project` option into the editable row and verifies it cannot create an Idea Board row. | + +## Source PR Coverage + +| Source PR | Batch D Area | Current-Main Resolution | +| --- | --- | --- | +| #114 | Idea Board cleanup | Already present on current main; Game Hub changes were not touched. | +| #115 | Status filter table polish | Already present on current main; no Updated column, wrapped idea labels, themed status filters. | +| #116 | Editable status dropdown fix | Present and hardened by this PR with save-path validation. | + +## Requirement Checklist + +| Requirement | Status | Notes | +| --- | --- | --- | +| Start from `main` | PASS | `main` was checked, pulled, clean, and synced before branch creation. | +| Hard stop if branch/worktree/sync invalid | PASS | Branch `main`, clean worktree, local/origin sync `0 0` confirmed after pull. | +| Read all Project Instructions | PASS | All files under `docs_build/dev/ProjectInstructions/` were read before edits. | +| Implement current-main-safe Batch D runtime changes | PASS | Added runtime validation for editable-only Idea Board statuses. | +| Editable statuses limited to New/Exploring/Refining/Ready | PASS | UI already did this; save path now enforces it. | +| Filter statuses include Project and Archived | PASS | Existing filter behavior preserved. | +| Preserve Game Hub changes | PASS | No Game Hub files changed. | +| Do not change status bar work | PASS | Status bar diff check was empty. | +| Do not install Chromium | PASS | Chromium was not installed. | +| Required reports and ZIP | PASS | Reports generated and delta ZIP created under `tmp/`. | + +## Validation Lane + +| Command | Status | Result | +| --- | --- | --- | +| `node --check assets/toolbox/idea-board/js/index.js` | PASS | JavaScript syntax valid. | +| `node --check tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | PASS | Test file syntax valid. | +| `git diff --check -- assets/toolbox/idea-board/js/index.js tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | PASS | Exit code 0; Git emitted a non-blocking CRLF warning for the test file. | +| `git diff -- toolbox/game-hub/game-hub.js toolbox/game-hub/index.html assets/theme-v2/css/status.css assets/theme-v2/js/toolbox-status-bar.js tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` | PASS | Empty diff; Game Hub and status bar work untouched. | +| `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs --workers=1 --reporter=line --timeout=30000` | BLOCKED | Browser executable missing at `C:\Users\davidq\AppData\Local\ms-playwright\chromium-1217\chrome-win64\chrome.exe`; Chromium was not installed per instruction. | + +## Manual Validation Notes + +- Compared GitHub PR #114, #115, and #116 metadata and patches against current main. +- Confirmed the historical `toolbox/idea-board/index.js` path has moved on current main to `assets/toolbox/idea-board/js/index.js`. +- Confirmed current main already preserves the Batch D status filter/table/dropdown shape. +- Confirmed this PR does not modify `toolbox/game-hub/*`, `assets/theme-v2/css/status.css`, `assets/theme-v2/js/toolbox-status-bar.js`, or status bar Playwright coverage. + +## Branch Validation + +PASS - Work began from clean, synced `main`; implementation was made on `PR_26175_ALFA_018-alfa-idea-board-polish-consolidation`. diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index 39527f045..96fb4553c 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,5 +1,5 @@ -docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md +assets/toolbox/idea-board/js/index.js +docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md docs_build/dev/reports/codex_changed_files.txt docs_build/dev/reports/codex_review.diff -tests/playwright/tools/GameHubMockRepository.spec.mjs -toolbox/game-hub/game-hub.js +tests/playwright/tools/IdeaBoardTableNotes.spec.mjs diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index cf2b27172..873cd747c 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,180 +1,130 @@ -diff --git a/docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md b/docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md +diff --git a/assets/toolbox/idea-board/js/index.js b/assets/toolbox/idea-board/js/index.js +index 47a5ed91e..25607bc8d 100644 +--- a/assets/toolbox/idea-board/js/index.js ++++ b/assets/toolbox/idea-board/js/index.js +@@ -129,6 +129,10 @@ function previousStatusForRestore(record) { + : "Refining"; + } + ++function isEditableStatus(status) { ++ return editableStatusOptions.includes(status); ++} ++ + function rememberPreviousStatus(record) { + if (record.status !== "Archived") { + record.previousStatus = record.status; +@@ -436,7 +440,7 @@ function saveIdeaRow(root, row) { + const idea = row.querySelector("[data-idea-board-idea-input]")?.value.trim(); + const pitch = row.querySelector("[data-idea-board-pitch-input]")?.value.trim(); + const status = row.querySelector("[data-idea-board-idea-status-input]")?.value; +- if (!idea || !pitch || !status) { ++ if (!idea || !pitch || !isEditableStatus(status)) { + updateStatus(root, "Enter an idea, pitch, and status before saving."); + return; + } +diff --git a/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md b/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md new file mode 100644 -index 000000000..7b8961565 +index 000000000..dc24d4ee4 --- /dev/null -+++ b/docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md -@@ -0,0 +1,67 @@ -+# PR_26175_ALFA_017 - Alfa Game Hub Interactions Consolidation ++++ b/docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md +@@ -0,0 +1,60 @@ ++# PR_26175_ALFA_018 - Alfa Idea Board Polish Consolidation + +## Executive Summary + -+PASS - Consolidated the current-main-safe Batch C Game Hub interaction behavior from GitHub PRs #107 through #113. ++PASS - Consolidated the remaining current-main-safe Alfa Batch D Idea Board status dropdown guard. ++ ++Current `main` already contained the #114, #115, and #116 structural work: the status filter is in the left accordion, the Idea Board parent table no longer has the Updated column, idea labels wrap, editable status dropdowns list only `New`, `Exploring`, `Refining`, and `Ready`, and status filters list `New`, `Exploring`, `Refining`, `Ready`, `Project`, and `Archived`. + -+This PR carries forward the remaining runtime-safe Game Hub child-row behavior: every expanded game parent row now exposes the same two child rows, Source Idea first and Readiness Output second, even when the game does not yet have source idea details. Existing current-main behavior for selected-game button state, guest save redirects, table-row add/edit flows, and removed standalone panels was preserved. ++This PR adds a runtime save guard so stale or injected editable dropdown values cannot persist non-editable statuses such as `Project` or `Archived`. + +## Runtime Files Changed + +| File | Change | +| --- | --- | -+| `toolbox/game-hub/game-hub.js` | Always renders Source Idea and Readiness Output child rows for expanded game rows; aligns `aria-controls` with both child row IDs. | -+| `tests/playwright/tools/GameHubMockRepository.spec.mjs` | Updates focused Game Hub expectations for ordinary games to require the stable two-child-row structure and Source Idea fallback content. | ++| `assets/toolbox/idea-board/js/index.js` | Adds an editable-status validation helper and rejects add/edit saves when the submitted status is not one of the editable statuses. | ++| `tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | Adds focused coverage that injects a stale `Project` option into the editable row and verifies it cannot create an Idea Board row. | + +## Source PR Coverage + -+| Source PR | Batch C Area | Current-Main Resolution | ++| Source PR | Batch D Area | Current-Main Resolution | +| --- | --- | --- | -+| #107 | Game row child rows | Carried forward the stable Source Idea + Readiness Output child-row contract. | -+| #108 | Parent table centered in main panel / columns | Already present on current main without reintroducing obsolete Owner/Role/Next Tool columns. | -+| #109 | Actions/setup cleanup | Already present; Open Game Journey and Game Setup controls remain absent. | -+| #110 | Row add/edit selected state | Already present; add/edit rows remain table-native. | -+| #111 | Guest save redirect | Already present; save actions continue redirecting guests to `account/sign-in.html`. | -+| #112 | Selected-game button state | Already present; row/cell selected markers remain absent. | -+| #113 | Selected button and Game Crew label cleanup | Selected button styling already present; Game Crew label is no longer relevant on current main. | ++| #114 | Idea Board cleanup | Already present on current main; Game Hub changes were not touched. | ++| #115 | Status filter table polish | Already present on current main; no Updated column, wrapped idea labels, themed status filters. | ++| #116 | Editable status dropdown fix | Present and hardened by this PR with save-path validation. | + +## Requirement Checklist + +| Requirement | Status | Notes | +| --- | --- | --- | -+| Start from `main` | PASS | Initial gate passed before branch creation. | -+| Hard stop if branch/worktree/sync invalid | PASS | `main`, clean worktree, local/origin sync `0 0` confirmed before branch creation. | -+| Read all Project Instructions | PASS | Active Project Instructions and history snapshots were reviewed before edits. | -+| Implement current-main-safe Batch C runtime changes | PASS | Implemented the remaining stable Source Idea + Readiness Output child-row behavior. | -+| Do not create report-only PR | PASS | Runtime and Playwright test files changed. | ++| Start from `main` | PASS | `main` was checked, pulled, clean, and synced before branch creation. | ++| Hard stop if branch/worktree/sync invalid | PASS | Branch `main`, clean worktree, local/origin sync `0 0` confirmed after pull. | ++| Read all Project Instructions | PASS | All files under `docs_build/dev/ProjectInstructions/` were read before edits. | ++| Implement current-main-safe Batch D runtime changes | PASS | Added runtime validation for editable-only Idea Board statuses. | ++| Editable statuses limited to New/Exploring/Refining/Ready | PASS | UI already did this; save path now enforces it. | ++| Filter statuses include Project and Archived | PASS | Existing filter behavior preserved. | ++| Preserve Game Hub changes | PASS | No Game Hub files changed. | +| Do not change status bar work | PASS | Status bar diff check was empty. | -+| Do not reintroduce removed standalone panels | PASS | No panel markup was restored. | -+| Do not use browser-owned product data as source of truth | PASS | Change uses existing repository/API-driven Game Hub state only. | +| Do not install Chromium | PASS | Chromium was not installed. | -+| Required reports created | PASS | `codex_review.diff`, `codex_changed_files.txt`, and this report are included. | -+| Repo-structured ZIP under `tmp/` | PASS | ZIP created after report generation. | ++| Required reports and ZIP | PASS | Reports generated and delta ZIP created under `tmp/`. | + +## Validation Lane + +| Command | Status | Result | +| --- | --- | --- | -+| `node --check toolbox/game-hub/game-hub.js` | PASS | JavaScript syntax valid. | -+| `node --check tests/playwright/tools/GameHubMockRepository.spec.mjs` | PASS | Test file syntax valid. | -+| `node --check tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | PASS | Targeted adjacent test syntax valid. | -+| `node --check tests/playwright/tools/GameJourneyTool.spec.mjs` | PASS | Targeted adjacent test syntax valid. | -+| `git diff --check -- toolbox/game-hub/game-hub.js tests/playwright/tools/GameHubMockRepository.spec.mjs` | PASS | Exit code 0; Git emitted a non-blocking CRLF working-copy warning for the test file. | -+| `git diff -- assets/theme-v2/css/status.css assets/theme-v2/js/toolbox-status-bar.js tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` | PASS | Empty diff; status bar work untouched. | -+| `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs tests/playwright/tools/GameJourneyTool.spec.mjs tests/playwright/tools/GameHubMockRepository.spec.mjs` | BLOCKED | Timed out with no diagnostics before the narrower browser check. | -+| `npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs -g "Game Hub creates, opens, and deletes mock games|Game Hub validates game parent rows and child tables|Game Hub readiness child rows update from mock game state" --workers=1 --reporter=line --timeout=30000` | BLOCKED | Browser executable missing at `C:\Users\davidq\AppData\Local\ms-playwright\chromium-1217\chrome-win64\chrome.exe`. Chromium was not installed per instruction. | ++| `node --check assets/toolbox/idea-board/js/index.js` | PASS | JavaScript syntax valid. | ++| `node --check tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | PASS | Test file syntax valid. | ++| `git diff --check -- assets/toolbox/idea-board/js/index.js tests/playwright/tools/IdeaBoardTableNotes.spec.mjs` | PASS | Exit code 0; Git emitted a non-blocking CRLF warning for the test file. | ++| `git diff -- toolbox/game-hub/game-hub.js toolbox/game-hub/index.html assets/theme-v2/css/status.css assets/theme-v2/js/toolbox-status-bar.js tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` | PASS | Empty diff; Game Hub and status bar work untouched. | ++| `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs --workers=1 --reporter=line --timeout=30000` | BLOCKED | Browser executable missing at `C:\Users\davidq\AppData\Local\ms-playwright\chromium-1217\chrome-win64\chrome.exe`; Chromium was not installed per instruction. | + +## Manual Validation Notes + -+- Reviewed source PR metadata and file patches for #107, #108, #109, #110, #111, #112, and #113. -+- Compared the final Batch C branch state against current main and preserved current-main additions, including selected-game change notifications and required Add Game validation. -+- Confirmed the implementation does not modify `toolbox-status-bar.js`, `status.css`, or `ToolboxSelectedGameStatusBar.spec.mjs`. -+- Confirmed no runtime JSON contract changes and no browser-owned product data source was introduced. -+- Browser validation remains blocked until the local Playwright Chromium executable is available. ++- Compared GitHub PR #114, #115, and #116 metadata and patches against current main. ++- Confirmed the historical `toolbox/idea-board/index.js` path has moved on current main to `assets/toolbox/idea-board/js/index.js`. ++- Confirmed current main already preserves the Batch D status filter/table/dropdown shape. ++- Confirmed this PR does not modify `toolbox/game-hub/*`, `assets/theme-v2/css/status.css`, `assets/theme-v2/js/toolbox-status-bar.js`, or status bar Playwright coverage. + +## Branch Validation + -+PASS - Work began from clean, synced `main`; implementation was made on `PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation`. ++PASS - Work began from clean, synced `main`; implementation was made on `PR_26175_ALFA_018-alfa-idea-board-polish-consolidation`. diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt -index 1e9d23fae..39527f045 100644 +index 39527f045..96fb4553c 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt -@@ -1,6 +1,5 @@ --docs_build/dev/reports/PR_26175_ALFA_016-alfa-parent-child-table-consolidation.md -+docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md +@@ -1,5 +1,5 @@ +-docs_build/dev/reports/PR_26175_ALFA_017-alfa-game-hub-interactions-consolidation.md ++assets/toolbox/idea-board/js/index.js ++docs_build/dev/reports/PR_26175_ALFA_018-alfa-idea-board-polish-consolidation.md docs_build/dev/reports/codex_changed_files.txt docs_build/dev/reports/codex_review.diff - tests/playwright/tools/GameHubMockRepository.spec.mjs --tests/playwright/tools/IdeaBoardTableNotes.spec.mjs - toolbox/game-hub/game-hub.js -diff --git a/tests/playwright/tools/GameHubMockRepository.spec.mjs b/tests/playwright/tools/GameHubMockRepository.spec.mjs -index 2baf13cd0..20bb99adb 100644 ---- a/tests/playwright/tools/GameHubMockRepository.spec.mjs -+++ b/tests/playwright/tools/GameHubMockRepository.spec.mjs -@@ -355,18 +355,17 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-expanded", "true"); - const demoChildRows = page.locator("[data-game-expanded-row='demo-game']"); - await expect(demoChildRows).toHaveCount(2); -- await expect(demoChildRows.nth(0)).toHaveAttribute("data-game-child-row", "summary"); -+ await expect(demoChildRows.nth(0)).toHaveAttribute("data-game-child-row", "source-idea"); - await expect(demoChildRows.nth(1)).toHaveAttribute("data-game-child-row", "readiness-output"); -+ await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='summary']")).toHaveCount(0); - await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table]")).toHaveCount(2); -- const summaryTable = demoChildRows.nth(0).locator("[data-game-child-table='summary']"); -- await expect(summaryTable.locator("caption")).toHaveText("Game Summary"); -- await expect(summaryTable.locator("thead th")).toHaveText(["Field", "Value"]); -- await expect(summaryTable.locator("tbody tr")).toHaveText([ -- "ProjectDemo Game", -- "PurposeGame", -- "StatusUnder Construction", -+ const demoSourceIdeaTable = demoChildRows.nth(0).locator("[data-game-child-table='source-idea']"); -+ await expect(demoSourceIdeaTable.locator("caption")).toHaveText("Source Idea"); -+ await expect(demoSourceIdeaTable.locator("tbody tr")).toHaveText([ -+ "IdeaNo source idea yet", -+ "PitchCreate a project from Idea Board to see source details.", -+ "Note 1No source notes.", - ]); -- await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='source-idea']")).toHaveCount(0); - const readinessOutputTable = demoChildRows.nth(1).locator("[data-game-child-table='readiness-output']"); - await expect(readinessOutputTable.locator("caption")).toHaveText("Readiness Output"); - await expect(readinessOutputTable.locator("thead th")).toHaveText(["Output", "Status"]); -@@ -449,9 +448,10 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).not.toHaveAttribute("aria-current", "true"); - await expect(page.locator("[data-game-toggle][aria-current='true']")).toHaveCount(1); - await expect(page.locator("[data-game-toggle][data-game-active='true']")).toHaveCount(1); -- await expect(page.locator("[data-game-expanded-row='launch-test-game-1']")).toHaveCount(2); -- await expect(page.locator("[data-game-expanded-row='launch-test-game-1']").nth(0)).toHaveAttribute("data-game-child-row", "summary"); -- await expect(page.locator("[data-game-expanded-row='launch-test-game-1']").nth(1)).toHaveAttribute("data-game-child-row", "readiness-output"); -+ const launchChildRows = page.locator("[data-game-expanded-row='launch-test-game-1']"); -+ await expect(launchChildRows).toHaveCount(2); -+ await expect(launchChildRows.nth(0)).toHaveAttribute("data-game-child-row", "source-idea"); -+ await expect(launchChildRows.nth(1)).toHaveAttribute("data-game-child-row", "readiness-output"); - await expect(page.locator("[data-game-expanded-row='archive-game-2']")).toHaveCount(0); - await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveClass("btn btn--compact primary"); - await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/); -diff --git a/toolbox/game-hub/game-hub.js b/toolbox/game-hub/game-hub.js -index 2b9f8c031..2d761a0e6 100644 ---- a/toolbox/game-hub/game-hub.js -+++ b/toolbox/game-hub/game-hub.js -@@ -287,12 +287,7 @@ function createGameToggleButton(game, expanded, active) { - button.setAttribute("aria-current", "true"); - } - button.setAttribute("aria-expanded", String(expanded)); -- const controlledRows = [`game-child-summary-${game.id}`]; -- if (hasSourceIdeaDetails(game)) { -- controlledRows.push(`game-child-source-idea-${game.id}`); -- } -- controlledRows.push(`game-child-readiness-output-${game.id}`); -- button.setAttribute("aria-controls", controlledRows.join(" ")); -+ button.setAttribute("aria-controls", `game-child-source-idea-${game.id} game-child-readiness-output-${game.id}`); - button.textContent = game.name; - return button; - } -@@ -421,28 +416,18 @@ function renderReadinessOutputChildTable(parent, game, progress, active) { - } - - function renderExpandedGameRow(tbody, game, progress, active) { -- const childRows = [ -+ [ - { -- id: `game-child-summary-${game.id}`, -- render: (parent) => renderGameSummaryChildTable(parent, game), -- type: "summary", -- }, -- ]; -- if (hasSourceIdeaDetails(game)) { -- childRows.push({ - id: `game-child-source-idea-${game.id}`, - render: (parent) => renderSourceIdeaChildTable(parent, game), - type: "source-idea", -- }); -- } -- childRows.push( -+ }, - { - id: `game-child-readiness-output-${game.id}`, - render: (parent) => renderReadinessOutputChildTable(parent, game, progress, active), - type: "readiness-output", - }, -- ); -- childRows.forEach(({ id, render, type }) => { -+ ].forEach(({ id, render, type }) => { - const row = document.createElement("tr"); - row.dataset.gameExpandedRow = game.id; - row.dataset.gameChildRow = type; +-tests/playwright/tools/GameHubMockRepository.spec.mjs +-toolbox/game-hub/game-hub.js ++tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +index 01a730513..08f8fdc0e 100644 +--- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs ++++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +@@ -329,6 +329,22 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + await expect(ideaInputRow.locator("[data-idea-board-idea-status-input]")).toHaveCount(1); + await expect(ideaInputRow.locator("[data-idea-board-idea-status-input] option")).toHaveText(EDITABLE_STATUS_OPTIONS); + await expect(ideaInputRow.locator("td").nth(2)).toHaveText("0 Notes"); ++ await ideaInputRow.locator("[data-idea-board-idea-status-input]").evaluate((select) => { ++ const option = document.createElement("option"); ++ option.value = "Project"; ++ option.textContent = "Project"; ++ select.append(option); ++ select.value = "Project"; ++ }); ++ await page.locator("[data-idea-board-idea-input]").fill("Project Trap"); ++ await page.locator("[data-idea-board-pitch-input]").fill("Project status cannot be saved from the editable row."); ++ await page.locator("[data-idea-board-idea-action='save']").click(); ++ await expect(page.locator("[data-idea-board-status]")).toHaveText("Enter an idea, pitch, and status before saving."); ++ await expect(page.locator("[data-idea-board-idea-row='project-trap']")).toHaveCount(0); ++ await ideaInputRow.locator("[data-idea-board-idea-status-input]").evaluate((select) => { ++ select.querySelector("option[value='Project']")?.remove(); ++ select.value = "Refining"; ++ }); + await page.locator("[data-idea-board-idea-input]").fill("Lantern Reef"); + await page.locator("[data-idea-board-pitch-input]").fill("Guide light through a reef that rearranges at dusk."); + await page.locator("[data-idea-board-idea-status-input]").selectOption("Refining"); diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs index 01a730513..08f8fdc0e 100644 --- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs @@ -329,6 +329,22 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { await expect(ideaInputRow.locator("[data-idea-board-idea-status-input]")).toHaveCount(1); await expect(ideaInputRow.locator("[data-idea-board-idea-status-input] option")).toHaveText(EDITABLE_STATUS_OPTIONS); await expect(ideaInputRow.locator("td").nth(2)).toHaveText("0 Notes"); + await ideaInputRow.locator("[data-idea-board-idea-status-input]").evaluate((select) => { + const option = document.createElement("option"); + option.value = "Project"; + option.textContent = "Project"; + select.append(option); + select.value = "Project"; + }); + await page.locator("[data-idea-board-idea-input]").fill("Project Trap"); + await page.locator("[data-idea-board-pitch-input]").fill("Project status cannot be saved from the editable row."); + await page.locator("[data-idea-board-idea-action='save']").click(); + await expect(page.locator("[data-idea-board-status]")).toHaveText("Enter an idea, pitch, and status before saving."); + await expect(page.locator("[data-idea-board-idea-row='project-trap']")).toHaveCount(0); + await ideaInputRow.locator("[data-idea-board-idea-status-input]").evaluate((select) => { + select.querySelector("option[value='Project']")?.remove(); + select.value = "Refining"; + }); await page.locator("[data-idea-board-idea-input]").fill("Lantern Reef"); await page.locator("[data-idea-board-pitch-input]").fill("Guide light through a reef that rearranges at dusk."); await page.locator("[data-idea-board-idea-status-input]").selectOption("Refining");