11import { type Page , expect } from "@playwright/test" ;
22import { resetLocalEventDb } from "./event-test-utils" ;
33
4+ const getTaskInput = ( page : Page , title : string ) =>
5+ page . getByRole ( "textbox" , { name : `Edit ${ title } ` } ) ;
6+
47export const prepareTaskPage = async ( page : Page ) => {
58 await page . goto ( "/day" , { waitUntil : "domcontentloaded" } ) ;
69 await page . evaluate ( ( ) => {
710 localStorage . removeItem ( "compass.auth" ) ;
811 } ) ;
9- await page . waitForURL ( / \/ d a y \/ \d { 4 } - \d { 2 } - \d { 2 } $ / ) ;
10- await page . waitForFunction (
11- ( ) => {
12- const root = document . querySelector ( "#root" ) ;
13- return root && root . children . length > 0 ;
14- } ,
15- { timeout : 10000 } ,
16- ) ;
1712
1813 await resetLocalEventDb ( page ) ;
19- await page . reload ( { waitUntil : "domcontentloaded" } ) ;
20- await page . waitForURL ( / \/ d a y \/ \d { 4 } - \d { 2 } - \d { 2 } $ / ) ;
21- await page . waitForFunction (
22- ( ) => {
23- const root = document . querySelector ( "#root" ) ;
24- return root && root . children . length > 0 ;
25- } ,
26- { timeout : 10000 } ,
27- ) ;
14+ await reloadTaskPage ( page ) ;
15+ } ;
2816
29- // Wait for task list to be visible
30- await expect ( page . locator ( '[aria-label="daily-tasks"]' ) ) . toBeVisible ( ) ;
17+ export const reloadTaskPage = async ( page : Page ) => {
18+ await page . goto ( "/day" , { waitUntil : "domcontentloaded" } ) ;
19+ await page . waitForURL ( / \/ d a y \/ \d { 4 } - \d { 2 } - \d { 2 } $ / ) ;
20+ await expect ( page . locator ( '[aria-label="daily-tasks"]' ) ) . toBeVisible ( {
21+ timeout : 15000 ,
22+ } ) ;
3123} ;
3224
3325export const createTask = async ( page : Page , title : string ) => {
@@ -54,21 +46,18 @@ export const expectTaskVisible = async (
5446 title : string ,
5547 timeout = 10000 ,
5648) => {
57- await expect (
58- page . getByRole ( "textbox" , { name : `Edit ${ title } ` } ) ,
59- ) . toBeVisible ( {
49+ await expect ( page . locator ( '[aria-label="daily-tasks"]' ) ) . toBeVisible ( {
6050 timeout,
6151 } ) ;
52+ await expect ( getTaskInput ( page , title ) ) . toBeVisible ( { timeout } ) ;
6253} ;
6354
6455export const expectTaskMissing = async (
6556 page : Page ,
6657 title : string ,
6758 timeout = 10000 ,
6859) => {
69- await expect (
70- page . getByRole ( "textbox" , { name : `Edit ${ title } ` } ) ,
71- ) . toHaveCount ( 0 , {
60+ await expect ( getTaskInput ( page , title ) ) . toHaveCount ( 0 , {
7261 timeout,
7362 } ) ;
7463} ;
@@ -84,106 +73,59 @@ export const deleteTaskWithKeyboard = async (page: Page, title: string) => {
8473} ;
8574
8675export const restoreDeletedTaskFromUndoToast = async ( page : Page ) => {
87- const undoDeleteText = page . getByText ( "Deleted" ) . first ( ) ;
76+ const undoDeleteToast = page
77+ . getByRole ( "button" , { name : / d e l e t e d / i } )
78+ . first ( ) ;
8879
89- await expect ( undoDeleteText ) . toBeVisible ( ) ;
90- await undoDeleteText . click ( ) ;
91- await page . keyboard . press ( "Meta+z" ) ;
92- await page . keyboard . press ( "Control+z" ) ;
80+ await expect ( undoDeleteToast ) . toBeVisible ( ) ;
81+ await undoDeleteToast . click ( ) ;
9382} ;
9483
9584export const expectTaskSavedToIndexedDB = async ( page : Page , title : string ) => {
96- let lastSnapshot : unknown = null ;
97-
98- for ( let attempt = 0 ; attempt < 20 ; attempt ++ ) {
99- lastSnapshot = await page . evaluate ( async ( ) => {
100- const currentDateKey = window . location . pathname . split ( "/" ) . pop ( ) ?? "" ;
101-
102- return await new Promise < {
103- openError ?: boolean ;
104- storeError ?: string ;
105- currentDateKey ?: string ;
106- tasks ?: Array < { title : string ; dateKey : string } > ;
107- } > ( ( resolve ) => {
85+ const currentDateKey = page . url ( ) . split ( "/" ) . pop ( ) ?? "" ;
86+
87+ await page . waitForFunction (
88+ async ( [ taskTitle , dateKey ] ) =>
89+ new Promise < boolean > ( ( resolve ) => {
10890 const openRequest = indexedDB . open ( "compass-local" ) ;
109- openRequest . onerror = ( ) => resolve ( { openError : true } ) ;
91+ openRequest . onerror = ( ) => resolve ( false ) ;
11092 openRequest . onsuccess = ( ) => {
11193 const db = openRequest . result ;
11294
113- let store ;
95+ let transaction : IDBTransaction ;
11496 try {
115- const transaction = db . transaction ( "tasks" , "readonly" ) ;
116- store = transaction . objectStore ( "tasks" ) ;
117- } catch ( error ) {
118- resolve ( { storeError : String ( error ) } ) ;
97+ transaction = db . transaction ( "tasks" , "readonly" ) ;
98+ } catch {
99+ db . close ( ) ;
100+ resolve ( false ) ;
119101 return ;
120102 }
121103
122- const getAllRequest = store . getAll ( ) ;
123- getAllRequest . onerror = ( ) => resolve ( { currentDateKey, tasks : [ ] } ) ;
104+ const getAllRequest = transaction . objectStore ( "tasks" ) . getAll ( ) ;
105+ getAllRequest . onerror = ( ) => {
106+ db . close ( ) ;
107+ resolve ( false ) ;
108+ } ;
124109 getAllRequest . onsuccess = ( ) => {
125110 const tasks = getAllRequest . result as Array < {
126111 title ?: string ;
127112 dateKey ?: string ;
128113 } > ;
129- resolve ( {
130- currentDateKey,
131- tasks : tasks
132- . filter (
133- ( task ) : task is { title : string ; dateKey : string } =>
134- Boolean ( task ?. title ) && Boolean ( task ?. dateKey ) ,
135- )
136- . map ( ( task ) => ( {
137- title : task . title ,
138- dateKey : task . dateKey ,
139- } ) ) ,
140- } ) ;
114+ db . close ( ) ;
115+ resolve (
116+ tasks . some (
117+ ( task ) => task . title === taskTitle && task . dateKey === dateKey ,
118+ ) ,
119+ ) ;
141120 } ;
142121 } ;
143- } ) ;
144- } ) ;
145-
146- if (
147- typeof lastSnapshot === "object" &&
148- lastSnapshot !== null &&
149- "tasks" in lastSnapshot
150- ) {
151- const tasks =
152- (
153- lastSnapshot as {
154- tasks ?: Array < { title : string ; dateKey : string } > ;
155- }
156- ) . tasks ?? [ ] ;
157- const currentDateKey =
158- ( lastSnapshot as { currentDateKey ?: string } ) . currentDateKey ?? "" ;
159-
160- const isTaskSavedForCurrentDate = tasks . some (
161- ( task ) => task . title === title && task . dateKey === currentDateKey ,
162- ) ;
163-
164- if ( isTaskSavedForCurrentDate ) {
165- return ;
166- }
167- }
168-
169- await page . waitForTimeout ( 200 ) ;
170- }
171-
172- throw new Error (
173- `Task was not found in IndexedDB after polling: ${ JSON . stringify ( lastSnapshot ) } ` ,
122+ } ) ,
123+ [ title , currentDateKey ] as [ string , string ] ,
124+ { timeout : 5000 } ,
174125 ) ;
175126} ;
176127
177128export const clearAllLocalData = async ( page : Page ) => {
178129 await resetLocalEventDb ( page ) ;
179- await page . reload ( ) ;
180- await expect ( page . locator ( '[aria-label="daily-tasks"]' ) ) . toBeVisible ( ) ;
181- } ;
182-
183- /**
184- * @deprecated Use clearAllLocalData. This clears the shared local IndexedDB
185- * database (both events and tasks).
186- */
187- export const clearTasks = async ( page : Page ) => {
188- await clearAllLocalData ( page ) ;
130+ await reloadTaskPage ( page ) ;
189131} ;
0 commit comments