@@ -2,42 +2,30 @@ import type { Page } from "@playwright/test";
22import { expect } from "@playwright/test" ;
33
44/**
5- * Navigate to a page that has an editor. Waits for the sidebar page tree to
6- * load, then clicks an existing page. If no pages exist, creates one via the
7- * sidebar "New Page" button.
5+ * Navigate to a page that has an editor. Always creates a fresh page via the
6+ * sidebar "New Page" button so each test gets its own isolated page. This
7+ * prevents parallel tests (e.g. the delete test) from interfering by deleting
8+ * a shared page mid-test.
89 *
910 * Returns once `[contenteditable="true"]` is visible.
1011 */
1112export async function navigateToEditorPage ( page : Page ) : Promise < void > {
1213 const sidebar = page . getByRole ( "complementary" ) ;
1314
14- // The page tree loads asynchronously: fetches workspace ID, then pages.
15- // While loading it shows skeleton pulse divs. Once loaded it renders either
16- // role="tree" with role="treeitem" children (pages exist) or "No pages yet".
17- // Wait for tree items to appear — this is the most reliable signal that
18- // the async data has loaded and the sidebar is interactive.
19- const treeItem = sidebar . locator ( '[role="treeitem"]' ) . first ( ) ;
20- try {
21- await expect ( treeItem ) . toBeVisible ( { timeout : 10_000 } ) ;
22- } catch {
23- // Tree loaded but has no pages, or workspace has no pages yet
24- }
15+ // The page tree loads asynchronously: workspace ID lookup → page fetch.
16+ // The "New Page" button silently no-ops if the workspace ID hasn't resolved
17+ // yet, so we must wait for the tree to finish loading before clicking it.
18+ // The tree renders either treeitem elements (pages exist) or "No pages yet"
19+ // once loading completes. Wait for either signal.
20+ const treeLoaded = sidebar
21+ . locator ( '[role="treeitem"], :text("No pages yet")' )
22+ . first ( ) ;
23+ await expect ( treeLoaded ) . toBeVisible ( { timeout : 10_000 } ) ;
2524
26- if ( ( await treeItem . count ( ) ) > 0 ) {
27- // The tree item row contains: grip icon, expand button, file icon, title button, action buttons.
28- // The title button has class "flex-1 truncate text-left" and triggers navigation.
29- // Use text-left as a more specific selector since it's unique to the title button.
30- const titleBtn = treeItem . locator ( "button.text-left" ) ;
31- if ( ( await titleBtn . count ( ) ) > 0 ) {
32- await titleBtn . click ( ) ;
33- } else {
34- // Fallback: click the last button in the tree item (the title button)
35- await treeItem . locator ( "button" ) . last ( ) . click ( ) ;
36- }
37- } else {
38- // No pages exist — create one via the sidebar "New Page" button
39- await sidebar . getByRole ( "button" , { name : / n e w p a g e / i } ) . click ( ) ;
40- }
25+ // Create a fresh page so this test owns it and parallel tests cannot
26+ // delete or modify it underneath us.
27+ const newPageBtn = sidebar . getByRole ( "button" , { name : / n e w p a g e / i } ) ;
28+ await newPageBtn . click ( ) ;
4129
4230 // Wait for the editor to appear (works for both hard and soft navigation)
4331 const editor = page . locator ( '[contenteditable="true"]' ) ;
0 commit comments