@@ -1899,10 +1899,36 @@ test.describe("Workspace Manager V2 bootstrap", () => {
18991899 await expect ( page . locator ( "#log" ) ) . not . toContainText ( "FAIL Workspace background hydration" ) ;
19001900 await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Workspace manifest preview source is valid at games/Asteroids/assets/images/preview.png." ) ;
19011901 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 ( ) ) ) ;
1902- expect ( previewStatusHeaderOrder ) . toEqual ( [ "Status" , "+" , "Clear" ] ) ;
1902+ expect ( previewStatusHeaderOrder ) . toEqual ( [ "Status" , "+" , "Copy" , "Clear" ] ) ;
1903+ await expect ( page . locator ( ".preview-generator-v2__status-header-actions #copyLogBtn" ) ) . toBeVisible ( ) ;
1904+ await expect ( page . locator ( ".preview-generator-v2__status-header-actions #clearLogBtn" ) ) . toBeVisible ( ) ;
1905+ await page . evaluate ( ( ) => {
1906+ Object . defineProperty ( navigator , "clipboard" , {
1907+ configurable : true ,
1908+ value : {
1909+ writeText : async ( text ) => {
1910+ window . __previewGeneratorV2CopiedLog = text ;
1911+ }
1912+ }
1913+ } ) ;
1914+ } ) ;
1915+ const previewLogBeforeCopy = await page . locator ( "#log" ) . textContent ( ) ;
1916+ await page . locator ( "#copyLogBtn" ) . click ( ) ;
1917+ expect ( await page . evaluate ( ( ) => window . __previewGeneratorV2CopiedLog ) ) . toBe ( previewLogBeforeCopy ) ;
1918+ await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Copied Preview Generator V2 status log to clipboard" ) ;
1919+ await page . evaluate ( ( ) => {
1920+ Object . defineProperty ( navigator , "clipboard" , {
1921+ configurable : true ,
1922+ value : undefined
1923+ } ) ;
1924+ } ) ;
1925+ await page . locator ( "#copyLogBtn" ) . click ( ) ;
1926+ await expect ( page . locator ( "#log" ) ) . toContainText ( "FAIL Copy status log failed: Clipboard API is unavailable." ) ;
19031927 await page . locator ( "#executeBtn" ) . click ( ) ;
19041928 await expect ( page . locator ( "#log" ) ) . toContainText ( "Starting execution..." , { timeout : 20000 } ) ;
19051929 await expect ( page . locator ( "#log" ) ) . toContainText ( `Repo root: ${ displayRepoRootPath ( server ) } ` , { timeout : 20000 } ) ;
1930+ await expect ( page . locator ( "#log" ) ) . toContainText ( `CHK ${ displayAbsoluteOutputPath ( server , "games/Asteroids/assets/images/preview.svg" ) } ` , { timeout : 20000 } ) ;
1931+ await expect ( page . locator ( "#log" ) ) . toContainText ( `MISSING ${ displayAbsoluteOutputPath ( server , "games/Asteroids/assets/images/preview.svg" ) } ` , { timeout : 20000 } ) ;
19061932 await expect ( page . locator ( "#log" ) ) . toContainText ( "RUN Asteroids" , { timeout : 20000 } ) ;
19071933 await expect ( page . locator ( "#log" ) ) . toContainText ( "OUT games\\Asteroids\\assets\\images\\preview.svg" , { timeout : 20000 } ) ;
19081934 await expect ( page . locator ( "#log" ) ) . toContainText ( "OK WRITE Asteroids" , { timeout : 20000 } ) ;
@@ -1930,6 +1956,72 @@ test.describe("Workspace Manager V2 bootstrap", () => {
19301956 }
19311957 } ) ;
19321958
1959+ test ( "keeps Preview Generator V2 repo writer after Asset Manager V2 deletes the preview asset entry" , async ( { page } ) => {
1960+ const server = await openWorkspaceManagerV2 ( page ) ;
1961+ const pageErrors = [ ] ;
1962+
1963+ page . on ( "pageerror" , ( error ) => {
1964+ pageErrors . push ( error . message ) ;
1965+ } ) ;
1966+
1967+ try {
1968+ await selectMockRepo ( page ) ;
1969+ await page . locator ( "#activeGameSelect" ) . selectOption ( "Asteroids" ) ;
1970+ await expectWorkspaceReturnRehydrated ( page ) ;
1971+ await page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) . click ( ) ;
1972+ await expect ( page ) . toHaveURL ( / a s s e t - m a n a g e r - v 2 \/ i n d e x \. h t m l .* l a u n c h = w o r k s p a c e / ) ;
1973+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / W o r k s p a c e M a n a g e r V 2 l o a d e d 1 4 v a l i d a t e d a s s e t s f r o m t o o l s \. a s s e t - m a n a g e r - v 2 \. a s s e t s / ) ;
1974+ await page . locator ( '[data-delete-asset-id="assets.image.preview.preview"]' ) . click ( ) ;
1975+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K D e l e t e d 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 \. / ) ;
1976+ const editedAssetSession = await page . evaluate ( ( ) => JSON . parse ( sessionStorage . getItem ( "workspace.tools.asset-manager-v2" ) ) ) ;
1977+ expect ( editedAssetSession . data . assets [ "assets.image.preview.preview" ] ) . toBeUndefined ( ) ;
1978+ expect ( Object . keys ( editedAssetSession . data . assets ) ) . toHaveLength ( 13 ) ;
1979+ expect ( editedAssetSession . dirty ) . toMatchObject ( {
1980+ isDirty : true ,
1981+ reason : "asset-updated"
1982+ } ) ;
1983+ await page . evaluate ( ( ) => {
1984+ sessionStorage . setItem ( "workspace.repo.writes" , JSON . stringify ( [ {
1985+ contents : "<svg>stale cached prior preview</svg>" ,
1986+ path : "HTML-JavaScript-Gaming/games/Asteroids/assets/images/preview.svg"
1987+ } ] ) ) ;
1988+ } ) ;
1989+ await page . locator ( "#returnToWorkspaceButton" ) . click ( ) ;
1990+ 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 - / ) ;
1991+ await expectWorkspaceReturnRehydrated ( page ) ;
1992+ await expect ( page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) ) . toContainText ( "13 managed assets" ) ;
1993+ await expect ( page . locator ( '[data-workspace-tool-id="asset-manager-v2"]' ) ) . toHaveAttribute ( "data-workspace-tool-dirty" , "true" ) ;
1994+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / I N F O R e f r e s h e d a s s e t - m a n a g e r - v 2 f r o m w o r k s p a c e \. t o o l s \. a s s e t - m a n a g e r - v 2 \. d a t a : 1 3 m a n a g e d a s s e t s ; D i r t y : t r u e \. / ) ;
1995+ await page . locator ( '[data-workspace-tool-id="preview-generator-v2"]' ) . click ( ) ;
1996+ await expect ( page ) . toHaveURL ( / p r e v i e w - g e n e r a t o r - v 2 \/ i n d e x \. h t m l .* l a u n c h = w o r k s p a c e / ) ;
1997+ await expect ( page . locator ( "#repoSelectedValue" ) ) . toHaveText ( "HTML-JavaScript-Gaming" ) ;
1998+ await expect ( page . locator ( "#executeBtn" ) ) . toBeEnabled ( ) ;
1999+ await expect ( page . locator ( "#previewTargetValue" ) ) . toHaveText ( "games/Asteroids/assets/images/preview.svg" ) ;
2000+ await expect ( page . locator ( "#log" ) ) . toContainText ( "WARN Workspace manifest preview asset is missing from Asset Manager V2 data; generated preview output will target games/Asteroids/assets/images/preview.svg." ) ;
2001+ await expect ( page . locator ( "#log" ) ) . toContainText ( "OK Workspace repo session reference loaded from workspace.repo.reference for HTML-JavaScript-Gaming." ) ;
2002+ await expect ( page . locator ( "#log" ) ) . not . toContainText ( "Repo selected: not selected" ) ;
2003+ await page . locator ( "#executeBtn" ) . click ( ) ;
2004+ const log = page . locator ( "#log" ) ;
2005+ await expect ( log ) . toContainText ( `CHK ${ displayAbsoluteOutputPath ( server , "games/Asteroids/assets/images/preview.svg" ) } ` , { timeout : 20000 } ) ;
2006+ await expect ( log ) . toContainText ( `MISSING ${ displayAbsoluteOutputPath ( server , "games/Asteroids/assets/images/preview.svg" ) } ` , { timeout : 20000 } ) ;
2007+ await expect ( log ) . toContainText ( "RUN Asteroids" , { timeout : 20000 } ) ;
2008+ await expect ( log ) . toContainText ( "OK WRITE Asteroids" , { timeout : 20000 } ) ;
2009+ await expect ( log ) . toContainText ( `Write verification passed: file exists at ${ displayAbsoluteOutputPath ( server , "games/Asteroids/assets/images/preview.svg" ) } .` , { timeout : 20000 } ) ;
2010+ await expect ( log ) . toContainText ( "Written: 1" , { timeout : 20000 } ) ;
2011+ await expect ( log ) . toContainText ( "Failed: 0" , { timeout : 20000 } ) ;
2012+ await expect ( log ) . not . toContainText ( "SKIP Asteroids" ) ;
2013+ const previewWrites = await page . evaluate ( ( ) => JSON . parse ( sessionStorage . getItem ( "workspace.repo.writes" ) || "[]" ) ) ;
2014+ expect ( previewWrites ) . toHaveLength ( 2 ) ;
2015+ expect ( previewWrites . at ( - 1 ) . path ) . toBe ( "HTML-JavaScript-Gaming/games/Asteroids/assets/images/preview.svg" ) ;
2016+ expect ( previewWrites . at ( - 1 ) . contents ) . toContain ( "<svg" ) ;
2017+ expect ( previewWrites . at ( - 1 ) . contents ) . not . toContain ( "stale cached prior preview" ) ;
2018+ expect ( pageErrors ) . toEqual ( [ ] ) ;
2019+ } finally {
2020+ await coverageReporter . stop ( page ) ;
2021+ await server . close ( ) ;
2022+ }
2023+ } ) ;
2024+
19332025 test ( "imports a schema-valid manifest and exports the imported session manifest" , async ( { page } ) => {
19342026 const server = await openWorkspaceManagerV2 ( page ) ;
19352027 const pageErrors = [ ] ;
0 commit comments