11import { expect , test } from "@playwright/test" ;
22import { readFile } from "node:fs/promises" ;
3+ import path from "node:path" ;
34import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs" ;
45import { workspaceV2CoverageReporter as coverageReporter } from "../../helpers/workspaceV2CoverageReporter.mjs" ;
56
@@ -234,6 +235,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
234235 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " g a m e R o o t " : " g a m e s \/ A s t e r o i d s \/ " / ) ;
235236 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s P a t h " : " g a m e s \/ A s t e r o i d s \/ a s s e t s " / ) ;
236237 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " r e p o R o o t " : " H T M L - J a v a S c r i p t - G a m i n g " / ) ;
238+ expect ( JSON . parse ( await page . locator ( "#workspaceContextOutput" ) . inputValue ( ) ) . repoPath ) . toBe ( server . repoRoot ) ;
237239 await expect ( page . locator ( "#workspaceContextOutput" ) ) . not . toHaveValue ( / " p r e v i e w I m a g e P a t h " / ) ;
238240 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s .i m a g e .b e z e l .b e z e l " / ) ;
239241 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s .i m a g e .p r e v i e w .p r e v i e w " / ) ;
@@ -311,6 +313,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
311313 expect ( savedManifest . documentKind ) . toBe ( "workspace-manifest" ) ;
312314 expect ( Object . keys ( savedManifest . tools ) . sort ( ) ) . toEqual ( [ "asset-manager-v2" , "palette-manager-v2" , "vector-map-editor" ] ) ;
313315 expect ( savedManifest . repoRoot ) . toBe ( "HTML-JavaScript-Gaming" ) ;
316+ expect ( savedManifest . repoPath ) . toBe ( server . repoRoot ) ;
314317 expect ( savedManifest . tools [ "palette-manager-v2" ] . swatches . length ) . toBeGreaterThan ( 0 ) ;
315318 expect ( Object . keys ( savedManifest . tools [ "asset-manager-v2" ] . assets ) ) . toHaveLength ( 14 ) ;
316319 expect ( savedManifest . tools [ "asset-manager-v2" ] . previewImagePath ) . toBeUndefined ( ) ;
@@ -387,6 +390,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
387390 expect ( storedContext . gameRoot ) . toBe ( "games/Asteroids/" ) ;
388391 expect ( storedContext . assetsPath ) . toBe ( "games/Asteroids/assets" ) ;
389392 expect ( storedContext . repoRoot ) . toBe ( "HTML-JavaScript-Gaming" ) ;
393+ expect ( storedContext . repoPath ) . toBe ( server . repoRoot ) ;
390394 expect ( storedContext . tools [ "palette-manager-v2" ] . swatches . length ) . toBeGreaterThan ( 0 ) ;
391395 expect ( Object . keys ( storedContext . tools [ "asset-manager-v2" ] . assets ) ) . toHaveLength ( 14 ) ;
392396 expect ( storedContext . tools [ "asset-manager-v2" ] . previewImagePath ) . toBeUndefined ( ) ;
@@ -521,8 +525,9 @@ test.describe("Workspace Manager V2 bootstrap", () => {
521525 await expect ( page . locator ( '[data-launch-mode-nav="workspace"]' ) ) . toBeVisible ( ) ;
522526 await expect ( page . locator ( '[data-launch-mode-nav="workspace"] button' ) ) . toHaveText ( [ "Generate Image" , "Return to Workspace" ] ) ;
523527 await expect ( page . locator ( "#executeBtn" ) ) . toBeVisible ( ) ;
524- await expect ( page . locator ( "#executeBtn" ) ) . toBeDisabled ( ) ;
525- await expect ( page . locator ( "#repoSelectedValue" ) ) . toHaveText ( "HTML-JavaScript-Gaming" ) ;
528+ await expect ( page . locator ( "#executeBtn" ) ) . toBeEnabled ( ) ;
529+ await expect ( page . locator ( "#repoSelectedValue" ) ) . toHaveText ( server . repoRoot ) ;
530+ await expect ( page . locator ( "#pickRepoBtn" ) ) . toBeHidden ( ) ;
526531 await expect ( page . locator ( "#workspaceContextValue" ) ) . toHaveCount ( 0 ) ;
527532 await expect ( page . locator ( "#repoDestinationContent" ) ) . not . toContainText ( "Workspace launch" ) ;
528533 await expect ( page . locator ( "#targetTypeGames" ) ) . toBeChecked ( ) ;
@@ -534,10 +539,13 @@ test.describe("Workspace Manager V2 bootstrap", () => {
534539 await expect ( page . locator ( "#previewTargetValue" ) ) . toHaveText ( "games/Asteroids/assets/images/preview.svg" ) ;
535540 await expect ( page . locator ( "#lastGeneratedImagePreview" ) ) . toBeVisible ( ) ;
536541 await expect ( page . locator ( "#lastGeneratedImageMeta" ) ) . toHaveText ( "Preview target: games/Asteroids/assets/images/preview.png" ) ;
542+ const absoluteAsteroidsPreviewPath = path . join ( server . repoRoot , "games" , "Asteroids" , "assets" , "images" , "preview.svg" ) ;
537543 await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Workspace launch context hydrated for Asteroids." ) ;
538544 await expect ( page . locator ( "#log" ) ) . toContainText ( "Workspace repoRoot display label available: HTML-JavaScript-Gaming." ) ;
539- await expect ( page . locator ( "#log" ) ) . toContainText ( "WARN Absolute repoRoot missing for workspace launch; manifest repoRoot is display-only: HTML-JavaScript-Gaming." ) ;
540- await expect ( page . locator ( "#log" ) ) . toContainText ( "Direct preview write unavailable until a real writable repo root is selected." ) ;
545+ await expect ( page . locator ( "#log" ) ) . toContainText ( `Workspace repoPath available: ${ server . repoRoot } .` ) ;
546+ await expect ( page . locator ( "#log" ) ) . toContainText ( `Resolved repoPath: ${ server . repoRoot } ` ) ;
547+ await expect ( page . locator ( "#log" ) ) . toContainText ( `Resolved absolute preview output path: ${ absoluteAsteroidsPreviewPath } ` ) ;
548+ await expect ( page . locator ( "#log" ) ) . not . toContainText ( "Direct preview write unavailable" ) ;
541549 await expect ( page . locator ( "#log" ) ) . not . toContainText ( "Unable to resolve absolute repoRoot" ) ;
542550 await expect ( page . locator ( "#log" ) ) . not . toContainText ( "/__workspace-manager-v2/repo-root" ) ;
543551 await expect ( page . locator ( "#log" ) ) . toContainText ( "Asset folder: assets\\images" ) ;
@@ -552,9 +560,21 @@ test.describe("Workspace Manager V2 bootstrap", () => {
552560 const previewStatusHeaderOrder = await page . locator ( ".preview-generator-v2__status-accordion-header" ) . evaluate ( ( header ) => Array . from ( header . querySelectorAll ( ":scope > span, :scope > div > span, :scope > div > button" ) , ( element ) => element . textContent . trim ( ) ) ) ;
553561 expect ( previewStatusHeaderOrder ) . toEqual ( [ "Status" , "+" , "Clear" ] ) ;
554562 await page . locator ( "#baseUrl" ) . fill ( server . baseUrl ) ;
555- await expect ( page . locator ( "#executeBtn" ) ) . toBeDisabled ( ) ;
556- expect ( server . previewWrites . size ) . toBe ( 0 ) ;
557- expect ( server . previewAbsoluteWrites . size ) . toBe ( 0 ) ;
563+ await expect ( page . locator ( "#executeBtn" ) ) . toBeEnabled ( ) ;
564+ let previewDownloadOpened = false ;
565+ page . on ( "download" , ( ) => {
566+ previewDownloadOpened = true ;
567+ } ) ;
568+ await page . locator ( "#executeBtn" ) . click ( ) ;
569+ await expect ( page . locator ( "#log" ) ) . toContainText ( "Workspace launch direct preview write target: games/Asteroids/assets/images/preview.svg." , { timeout : 20000 } ) ;
570+ await expect ( page . locator ( "#log" ) ) . toContainText ( `Workspace launch absolute preview output path: ${ absoluteAsteroidsPreviewPath } .` , { timeout : 20000 } ) ;
571+ await expect ( page . locator ( "#log" ) ) . toContainText ( "Direct preview write target: games/Asteroids/assets/images/preview.svg" , { timeout : 20000 } ) ;
572+ await expect ( page . locator ( "#log" ) ) . toContainText ( `Direct preview absolute path: ${ absoluteAsteroidsPreviewPath } ` , { timeout : 20000 } ) ;
573+ await expect ( page . locator ( "#log" ) ) . toContainText ( `OK Direct preview write completed: ${ absoluteAsteroidsPreviewPath } ` , { timeout : 20000 } ) ;
574+ await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Asteroids" , { timeout : 20000 } ) ;
575+ expect ( previewDownloadOpened ) . toBe ( false ) ;
576+ expect ( server . previewWrites . get ( "games/Asteroids/assets/images/preview.svg" ) ) . toContain ( "<svg" ) ;
577+ expect ( server . previewAbsoluteWrites . get ( absoluteAsteroidsPreviewPath ) ) . toContain ( "<svg" ) ;
558578 await page . locator ( "#returnToWorkspaceButton" ) . click ( ) ;
559579 await expect ( page ) . toHaveURL ( / w o r k s p a c e - m a n a g e r - v 2 \/ i n d e x \. h t m l \? h o s t C o n t e x t I d = w o r k s p a c e - m a n a g e r - v 2 - / ) ;
560580 expect ( pageErrors ) . toEqual ( [ ] ) ;
@@ -607,6 +627,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
607627 const hostContextId = "workspace-manager-v2-display-root-context" ;
608628 const displayRootManifest = JSON . parse ( await readFile ( "games/Asteroids/game.manifest.json" , "utf8" ) ) ;
609629 displayRootManifest . repoRoot = "HTML-JavaScript-Gaming" ;
630+ delete displayRootManifest . repoPath ;
610631
611632 page . on ( "pageerror" , ( error ) => {
612633 pageErrors . push ( error . message ) ;
@@ -620,12 +641,14 @@ test.describe("Workspace Manager V2 bootstrap", () => {
620641
621642 try {
622643 await expect ( page . locator ( "#repoSelectedValue" ) ) . toHaveText ( "HTML-JavaScript-Gaming" ) ;
644+ await expect ( page . locator ( "#pickRepoBtn" ) ) . toBeHidden ( ) ;
623645 await expect ( page . locator ( "#executeBtn" ) ) . toBeDisabled ( ) ;
624646 await expect ( page . locator ( "#previewTargetValue" ) ) . toHaveText ( "games/Asteroids/assets/images/preview.svg" ) ;
625647 await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Workspace launch context hydrated for Asteroids." ) ;
626648 await expect ( page . locator ( "#log" ) ) . toContainText ( "Workspace repoRoot display label available: HTML-JavaScript-Gaming." ) ;
627- await expect ( page . locator ( "#log" ) ) . toContainText ( "WARN Absolute repoRoot missing for workspace launch; manifest repoRoot is display-only: HTML-JavaScript-Gaming." ) ;
628- await expect ( page . locator ( "#log" ) ) . toContainText ( "Direct preview write unavailable until a real writable repo root is selected." ) ;
649+ await expect ( page . locator ( "#log" ) ) . toContainText ( "Workspace repoPath missing." ) ;
650+ await expect ( page . locator ( "#log" ) ) . toContainText ( "WARN Manifest repoPath is missing or invalid for workspace launch; repoRoot is display-only: HTML-JavaScript-Gaming." ) ;
651+ await expect ( page . locator ( "#log" ) ) . toContainText ( "Direct preview write unavailable until manifest repoPath is an absolute filesystem path." ) ;
629652 await expect ( page . locator ( "#log" ) ) . not . toContainText ( "/__workspace-manager-v2/repo-root" ) ;
630653 await expect ( page . locator ( "#log" ) ) . not . toContainText ( "FAIL Workspace launch context hydration" ) ;
631654 expect ( server . previewWrites . size ) . toBe ( 0 ) ;
@@ -664,13 +687,15 @@ test.describe("Workspace Manager V2 bootstrap", () => {
664687
665688 await page . locator ( "#activeGameSelect" ) . selectOption ( "GravityWell" ) ;
666689 await expect ( page . locator ( "#activeGameSummary" ) ) . toContainText ( "games/GravityWell/" ) ;
690+ await expect ( page . locator ( "#activeGameSummary" ) ) . toContainText ( "Select Repo" ) ;
667691 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " g a m e R o o t " : " g a m e s \/ G r a v i t y W e l l \/ " / ) ;
668692 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s P a t h " : " g a m e s \/ G r a v i t y W e l l \/ a s s e t s " / ) ;
669693 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s .i m a g e .p r e v i e w .p r e v i e w " / ) ;
670694 await expect ( page . locator ( "#workspaceContextOutput" ) ) . not . toHaveValue ( / " a s s e t s .i m a g e .b a c k g r o u n d .p r e v i e w " / ) ;
671695 await expect ( page . locator ( "#workspaceContextOutput" ) ) . not . toHaveValue ( / " a s s e t - b r o w s e r " | " p a l e t t e - b r o w s e r " | " v e c t o r - m a p - e d i t o r " / ) ;
672696 await expect ( page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) ) . toContainText ( "1 managed assets" ) ;
673697 await expect ( page . locator ( '[data-workspace-tool-id="palette-manager-v2"]' ) ) . toContainText ( "10 palette swatches" ) ;
698+ await expect ( page . locator ( '[data-workspace-tool-id="preview-generator-v2"]' ) ) . toContainText ( "Select Repo" ) ;
674699 const gravityManifest = JSON . parse ( await page . locator ( "#workspaceContextOutput" ) . inputValue ( ) ) ;
675700 expect ( Object . keys ( gravityManifest . tools ) . sort ( ) ) . toEqual ( [ "asset-manager-v2" , "palette-manager-v2" ] ) ;
676701 expect ( gravityManifest . tools [ "asset-manager-v2" ] . assets [ "assets.image.preview.preview" ] ) . toEqual ( {
@@ -684,13 +709,15 @@ test.describe("Workspace Manager V2 bootstrap", () => {
684709
685710 await page . locator ( "#activeGameSelect" ) . selectOption ( "Pong" ) ;
686711 await expect ( page . locator ( "#activeGameSummary" ) ) . toContainText ( "games/Pong/" ) ;
712+ await expect ( page . locator ( "#activeGameSummary" ) ) . toContainText ( "Select Repo" ) ;
687713 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " g a m e R o o t " : " g a m e s \/ P o n g \/ " / ) ;
688714 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s P a t h " : " g a m e s \/ P o n g \/ a s s e t s " / ) ;
689715 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s .i m a g e .p r e v i e w .p r e v i e w " / ) ;
690716 await expect ( page . locator ( "#workspaceContextOutput" ) ) . not . toHaveValue ( / " a s s e t s .i m a g e .b a c k g r o u n d .p r e v i e w " / ) ;
691717 await expect ( page . locator ( "#workspaceContextOutput" ) ) . not . toHaveValue ( / " a s s e t - b r o w s e r " | " p a l e t t e - b r o w s e r " | " v e c t o r - m a p - e d i t o r " / ) ;
692718 await expect ( page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) ) . toContainText ( "1 managed assets" ) ;
693719 await expect ( page . locator ( '[data-workspace-tool-id="palette-manager-v2"]' ) ) . toContainText ( "8 palette swatches" ) ;
720+ await expect ( page . locator ( '[data-workspace-tool-id="preview-generator-v2"]' ) ) . toContainText ( "Select Repo" ) ;
694721 const pongManifest = JSON . parse ( await page . locator ( "#workspaceContextOutput" ) . inputValue ( ) ) ;
695722 expect ( Object . keys ( pongManifest . tools ) . sort ( ) ) . toEqual ( [ "asset-manager-v2" , "palette-manager-v2" ] ) ;
696723 expect ( pongManifest . tools [ "asset-manager-v2" ] . assets [ "assets.image.preview.preview" ] ) . toEqual ( {
@@ -792,7 +819,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
792819 await expect ( page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) ) . toContainText ( "0 managed assets" ) ;
793820 await expect ( page . locator ( '[data-workspace-tool-id="workspace-manager-v2"]' ) ) . toHaveCount ( 0 ) ;
794821 await expect ( page . locator ( '[data-workspace-tool-id="palette-manager-v2"]' ) ) . toContainText ( "3 palette swatches" ) ;
795- await expect ( page . locator ( '[data-workspace-tool-id="preview-generator-v2"]' ) ) . toContainText ( "Schema-valid manifest " ) ;
822+ await expect ( page . locator ( '[data-workspace-tool-id="preview-generator-v2"]' ) ) . toContainText ( "Select Repo " ) ;
796823 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " i d " : " w o r k s p a c e - m a n a g e r - v 2 - U A T - t e m p l a t e " / ) ;
797824 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " g a m e R o o t " : " g a m e s \/ _ t e m p l a t e \/ " / ) ;
798825 await expect ( page . locator ( "#workspaceContextOutput" ) ) . toHaveValue ( / " a s s e t s P a t h " : " g a m e s \/ _ t e m p l a t e \/ a s s e t s " / ) ;
0 commit comments