@@ -52,6 +52,9 @@ export class NotebookSidebarPage extends BasePage {
5252 // Ensure sidebar is visible first
5353 await expect ( this . sidebarContainer ) . toBeVisible ( ) ;
5454
55+ // Get initial state to check for changes
56+ const initialState = await this . getSidebarState ( ) ;
57+
5558 // Try multiple strategies to find and click the TOC button
5659 const strategies = [
5760 // Strategy 1: Original button selector
@@ -88,6 +91,25 @@ export class NotebookSidebarPage extends BasePage {
8891 for ( const strategy of strategies ) {
8992 try {
9093 await strategy ( ) ;
94+
95+ // Wait for state change after click - check for visible content instead of state
96+ await Promise . race ( [
97+ // Option 1: Wait for TOC content to appear
98+ this . page
99+ . locator ( 'zeppelin-note-toc, .sidebar-content .toc' )
100+ . waitFor ( { state : 'visible' , timeout : 3000 } )
101+ . catch ( ( ) => { } ) ,
102+ // Option 2: Wait for file tree content to appear
103+ this . page
104+ . locator ( 'zeppelin-node-list, .sidebar-content .file-tree' )
105+ . waitFor ( { state : 'visible' , timeout : 3000 } )
106+ . catch ( ( ) => { } ) ,
107+ // Option 3: Wait for any sidebar content change
108+ this . page . waitForLoadState ( 'networkidle' , { timeout : 3000 } ) . catch ( ( ) => { } )
109+ ] ) . catch ( ( ) => {
110+ // If all fail, continue - this is acceptable
111+ } ) ;
112+
91113 success = true ;
92114 break ;
93115 } catch ( error ) {
@@ -99,12 +121,18 @@ export class NotebookSidebarPage extends BasePage {
99121 console . log ( 'All TOC button strategies failed - sidebar may not have TOC functionality' ) ;
100122 }
101123
102- // Wait for TOC to be visible if it was successfully opened
103- const tocContent = this . page . locator ( '.sidebar-content .toc, .outline-content' ) ;
124+ // Wait for TOC content to be visible if it was successfully opened
125+ const tocContent = this . page . locator ( 'zeppelin-note-toc, .sidebar-content .toc, .outline-content' ) ;
104126 try {
105127 await expect ( tocContent ) . toBeVisible ( { timeout : 3000 } ) ;
106128 } catch {
107- // TOC might not be available or visible
129+ // TOC might not be available or visible, check if file tree opened instead
130+ const fileTreeContent = this . page . locator ( 'zeppelin-node-list, .sidebar-content .file-tree' ) ;
131+ try {
132+ await expect ( fileTreeContent ) . toBeVisible ( { timeout : 2000 } ) ;
133+ } catch {
134+ // Neither TOC nor file tree visible
135+ }
108136 }
109137 }
110138
@@ -121,8 +149,18 @@ export class NotebookSidebarPage extends BasePage {
121149 await fallbackFileTreeButton . click ( ) ;
122150 }
123151
152+ // Wait for file tree content to appear after click
153+ await Promise . race ( [
154+ // Wait for file tree content to appear
155+ this . page . locator ( 'zeppelin-node-list, .sidebar-content .file-tree' ) . waitFor ( { state : 'visible' , timeout : 3000 } ) ,
156+ // Wait for network to stabilize
157+ this . page . waitForLoadState ( 'networkidle' , { timeout : 3000 } )
158+ ] ) . catch ( ( ) => {
159+ // If both fail, continue - this is acceptable
160+ } ) ;
161+
124162 // Wait for file tree content to be visible
125- const fileTreeContent = this . page . locator ( '.sidebar-content .file-tree, .file-browser' ) ;
163+ const fileTreeContent = this . page . locator ( 'zeppelin-node-list, .sidebar-content .file-tree, .file-browser' ) ;
126164 try {
127165 await expect ( fileTreeContent ) . toBeVisible ( { timeout : 3000 } ) ;
128166 } catch {
@@ -170,6 +208,21 @@ export class NotebookSidebarPage extends BasePage {
170208 for ( const strategy of strategies ) {
171209 try {
172210 await strategy ( ) ;
211+
212+ // Wait for sidebar to close or become hidden
213+ await Promise . race ( [
214+ // Wait for sidebar to be hidden
215+ this . sidebarContainer . waitFor ( { state : 'hidden' , timeout : 3000 } ) ,
216+ // Wait for sidebar content to disappear
217+ this . page
218+ . locator ( 'zeppelin-notebook-sidebar zeppelin-note-toc, zeppelin-notebook-sidebar zeppelin-node-list' )
219+ . waitFor ( { state : 'hidden' , timeout : 3000 } ) ,
220+ // Wait for network to stabilize
221+ this . page . waitForLoadState ( 'networkidle' , { timeout : 3000 } )
222+ ] ) . catch ( ( ) => {
223+ // If all fail, continue - close functionality may not be available
224+ } ) ;
225+
173226 success = true ;
174227 break ;
175228 } catch ( error ) {
@@ -181,24 +234,40 @@ export class NotebookSidebarPage extends BasePage {
181234 console . log ( 'All close button strategies failed - sidebar may not have close functionality' ) ;
182235 }
183236
184- // Wait for sidebar to be hidden if it was successfully closed
237+ // Final check - wait for sidebar to be hidden if it was successfully closed
185238 try {
186239 await expect ( this . sidebarContainer ) . toBeHidden ( { timeout : 3000 } ) ;
187240 } catch {
188241 // Sidebar might still be visible or close functionality not available
242+ // This is acceptable as some applications don't support closing sidebar
189243 }
190244 }
191245
192246 async isSidebarVisible ( ) : Promise < boolean > {
193- return await this . sidebarContainer . isVisible ( ) ;
247+ try {
248+ return await this . sidebarContainer . isVisible ( ) ;
249+ } catch ( error ) {
250+ // If page is closed or connection lost, assume sidebar is not visible
251+ return false ;
252+ }
194253 }
195254
196255 async isTocContentVisible ( ) : Promise < boolean > {
197- return await this . noteToc . isVisible ( ) ;
256+ try {
257+ return await this . noteToc . isVisible ( ) ;
258+ } catch ( error ) {
259+ // If page is closed or connection lost, assume TOC is not visible
260+ return false ;
261+ }
198262 }
199263
200264 async isFileTreeContentVisible ( ) : Promise < boolean > {
201- return await this . nodeList . isVisible ( ) ;
265+ try {
266+ return await this . nodeList . isVisible ( ) ;
267+ } catch ( error ) {
268+ // If page is closed or connection lost, assume file tree is not visible
269+ return false ;
270+ }
202271 }
203272
204273 async getSidebarState ( ) : Promise < 'CLOSED' | 'TOC' | 'FILE_TREE' | 'UNKNOWN' > {
@@ -294,6 +363,49 @@ export class NotebookSidebarPage extends BasePage {
294363 return 'UNKNOWN' ;
295364 }
296365
366+ getSidebarStateSync ( ) : 'CLOSED' | 'TOC' | 'FILE_TREE' | 'UNKNOWN' {
367+ // Synchronous version for use in waitForFunction
368+ try {
369+ const sidebarContainer = document . querySelector ( 'zeppelin-notebook-sidebar' ) as HTMLElement | null ;
370+ if ( ! sidebarContainer || ! sidebarContainer . offsetParent ) {
371+ return 'CLOSED' ;
372+ }
373+
374+ // Check for TOC content
375+ const tocContent = sidebarContainer . querySelector ( 'zeppelin-note-toc' ) as HTMLElement | null ;
376+ if ( tocContent && tocContent . offsetParent ) {
377+ return 'TOC' ;
378+ }
379+
380+ // Check for file tree content
381+ const fileTreeContent = sidebarContainer . querySelector ( 'zeppelin-node-list' ) as HTMLElement | null ;
382+ if ( fileTreeContent && fileTreeContent . offsetParent ) {
383+ return 'FILE_TREE' ;
384+ }
385+
386+ // Check for alternative selectors
387+ const tocAlternatives = [ '.toc-content' , '.note-toc' , '[class*="toc"]' ] ;
388+ for ( const selector of tocAlternatives ) {
389+ const element = sidebarContainer . querySelector ( selector ) as HTMLElement | null ;
390+ if ( element && element . offsetParent ) {
391+ return 'TOC' ;
392+ }
393+ }
394+
395+ const fileTreeAlternatives = [ '.file-tree' , '.node-list' , '[class*="file"]' , '[class*="tree"]' ] ;
396+ for ( const selector of fileTreeAlternatives ) {
397+ const element = sidebarContainer . querySelector ( selector ) as HTMLElement | null ;
398+ if ( element && element . offsetParent ) {
399+ return 'FILE_TREE' ;
400+ }
401+ }
402+
403+ return 'FILE_TREE' ; // Default fallback
404+ } catch {
405+ return 'UNKNOWN' ;
406+ }
407+ }
408+
297409 async getTocItems ( ) : Promise < string [ ] > {
298410 const tocItems = this . noteToc . locator ( 'li' ) ;
299411 const count = await tocItems . count ( ) ;
0 commit comments