@@ -11,9 +11,9 @@ import {
1111 session ,
1212 sessionHref ,
1313} from "../utils/app"
14- import { mockServers } from "../utils/mock-server"
14+ import { currentSession , mockServers } from "../utils/mock-server"
1515import { fixture , mockStressTimeline } from "../utils/session-fixture"
16- import { fileNode , mockWorkspace , openSession } from "../utils/workspace"
16+ import { fileNode , mockRemoteServer , mockWorkspace , openSession } from "../utils/workspace"
1717import { expectSessionTitle } from "../utils/waits"
1818
1919const a = { id : "ses_tab_a" , title : "Tab A session" }
@@ -24,6 +24,72 @@ const c = { id: "ses_tab_c", title: "Tab C session" }
2424
2525test . use ( { serviceWorkers : "block" } )
2626
27+ for ( const server of [ SERVER , REMOTE_SERVER ] ) {
28+ test ( `session metadata failure does not follow navigation to another tab on ${ server } ` , async ( { page } ) => {
29+ await mockWorkspace ( page , {
30+ name : "Tabs" ,
31+ sessions : [ b ] ,
32+ seed : { tabs : [ a . id , { session : b . id , server } ] } ,
33+ } )
34+ if ( server === REMOTE_SERVER ) {
35+ await mockRemoteServer ( page , { sessions : [ session ( { ...b , directory : "/remote/project" } ) ] } )
36+ }
37+ await page . route (
38+ ( url ) => url . origin === SERVER && url . pathname === `/api/session/${ a . id } ` ,
39+ ( route ) => route . fulfill ( { status : 504 , json : { message : "Fixture metadata timeout" } } ) ,
40+ )
41+ await page . goto ( sessionHref ( a . id ) )
42+ await expect ( page . getByRole ( "heading" , { name : "Server request failed" } ) ) . toBeVisible ( )
43+ const document = await page . locator ( "html" ) . elementHandle ( )
44+
45+ await page . locator ( `a[data-titlebar-tab-link][href="${ sessionHref ( b . id , server ) } "]` ) . click ( )
46+
47+ await expectPath ( page , sessionHref ( b . id , server ) )
48+ await expectSessionTitle ( page , b . title )
49+ await expect ( page . locator ( '[data-component="composer-editor"]' ) ) . toBeEditable ( )
50+ await expect ( page . getByRole ( "heading" , { name : "Server request failed" } ) ) . toHaveCount ( 0 )
51+ expect ( await document ?. evaluate ( ( element ) => element . isConnected ) ) . toBe ( true )
52+ } )
53+ }
54+
55+ test ( "session metadata failure can be retried without reloading or looping" , async ( { page } , testInfo ) => {
56+ await page . setViewportSize ( { width : 1440 , height : 900 } )
57+ const workspace = await mockWorkspace ( page , { name : "Tabs" , sessions : [ b ] , seed : { tabs : [ a . id , b . id ] } } )
58+ const state = { fail : true , requests : 0 }
59+ await page . route (
60+ ( url ) => url . origin === SERVER && url . pathname === `/api/session/${ a . id } ` ,
61+ ( route ) => {
62+ state . requests ++
63+ return route . fulfill (
64+ state . fail
65+ ? { status : 504 , json : { message : "Fixture metadata timeout" } }
66+ : { json : { data : currentSession ( session ( { ...a , directory : workspace . directory } ) ) } } ,
67+ )
68+ } ,
69+ )
70+ await page . goto ( sessionHref ( a . id ) )
71+ const retry = page . getByRole ( "button" , { name : "Try again" , exact : true } )
72+ await expect ( retry ) . toBeVisible ( )
73+ const document = await page . locator ( "html" ) . elementHandle ( )
74+ const before = state . requests
75+ await retry . press ( "Enter" )
76+ await expect ( retry ) . toBeVisible ( )
77+ await expect . poll ( ( ) => state . requests ) . toBe ( before + 1 )
78+ await expect ( retry ) . toBeInViewport ( )
79+ await page . screenshot ( { path : testInfo . outputPath ( "retry-desktop.png" ) } )
80+ expect ( state . requests ) . toBe ( before + 1 )
81+ await page . setViewportSize ( { width : 390 , height : 720 } )
82+ await expect ( retry ) . toBeInViewport ( )
83+ await page . screenshot ( { path : testInfo . outputPath ( "retry-narrow.png" ) } )
84+
85+ state . fail = false
86+ await retry . click ( )
87+ await expectSessionTitle ( page , a . title )
88+ await expect ( page . locator ( '[data-component="composer-editor"]' ) ) . toBeEditable ( )
89+ await expect ( retry ) . toHaveCount ( 0 )
90+ expect ( await document ?. evaluate ( ( element ) => element . isConnected ) ) . toBe ( true )
91+ } )
92+
2793test ( "tab strip keeps draft tabs as wide as session tabs and navigates on mouse down" , async ( { page } ) => {
2894 const workspace = await mockWorkspace ( page , {
2995 name : "Tabs" ,
0 commit comments