mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
test(e2e): improve sync test robustness with archive persistence waits
Adds explicit waits after archive operations to ensure IndexedDB writes complete before proceeding with sync operations. This prevents race conditions where sync attempts to read state before archive persistence finishes. Changes: - Add waitForArchivePersistence() helper to sync-helpers.ts - Waits 1000ms for IndexedDB operations to complete - Additional 100ms for pending micro-tasks/animations - Add 500ms waits in waitForSyncComplete() after detecting sync success - Ensures IndexedDB writes fully settle before returning - Apply waitForArchivePersistence() in webdav-sync-archive.spec.ts - After Client A archives Task1 - After Client B archives Task3 - Apply waitForArchivePersistence() in webdav-sync-delete-cascade.spec.ts - After Client A archives task (tag deletion test) - After Client B archives Task1 (concurrent archive test) These changes address flakiness in CI environments where async IndexedDB operations may not complete before the next test assertion. Related to: Bug #5995, Bug #6044 (focus-mode test fixes)
This commit is contained in:
parent
66a0ab856e
commit
a49a863a08
3 changed files with 29 additions and 0 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
createSyncFolder,
|
||||
waitForSyncComplete,
|
||||
generateSyncFolderName,
|
||||
waitForArchivePersistence,
|
||||
} from '../../utils/sync-helpers';
|
||||
|
||||
/**
|
||||
|
|
@ -145,6 +146,7 @@ test.describe('@webdav WebDAV Archive Sync', () => {
|
|||
console.log('[Archive Diff] Client A marked Task1 done');
|
||||
|
||||
await archiveDoneTasks(pageA);
|
||||
await waitForArchivePersistence(pageA);
|
||||
await expect(pageA.locator('task')).toHaveCount(1); // Only Task2 remains
|
||||
console.log('[Archive Diff] Client A archived Task1');
|
||||
|
||||
|
|
@ -168,6 +170,7 @@ test.describe('@webdav WebDAV Archive Sync', () => {
|
|||
console.log('[Archive Diff] Client B marked Task3 done');
|
||||
|
||||
await archiveDoneTasks(pageB);
|
||||
await waitForArchivePersistence(pageB);
|
||||
// Note: Daily Summary flow automatically syncs after archiving.
|
||||
// So Client B downloads Client A's archive of Task1 during this flow.
|
||||
// Final state on Client B: only Task2 (both Task1 and Task3 archived)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
waitForSyncComplete,
|
||||
generateSyncFolderName,
|
||||
dismissTourIfVisible,
|
||||
waitForArchivePersistence,
|
||||
} from '../../utils/sync-helpers';
|
||||
import { Page } from 'playwright';
|
||||
|
||||
|
|
@ -117,6 +118,7 @@ test.describe('@webdav WebDAV Delete Cascade Sync', () => {
|
|||
await taskPageA.markTaskAsDone(task);
|
||||
await pageA.waitForTimeout(300);
|
||||
await archiveDoneTasks(pageA);
|
||||
await waitForArchivePersistence(pageA);
|
||||
await expect(pageA.locator('task')).toHaveCount(0);
|
||||
console.log('[Delete Tag] Client A archived task');
|
||||
|
||||
|
|
@ -415,6 +417,7 @@ test.describe('@webdav WebDAV Delete Cascade Sync', () => {
|
|||
await taskPageB.markTaskAsDone(task1OnB);
|
||||
await pageB.waitForTimeout(300);
|
||||
await archiveDoneTasks(pageB);
|
||||
await waitForArchivePersistence(pageB);
|
||||
await expect(pageB.locator('task')).toHaveCount(1); // Only Task2 visible
|
||||
console.log('[Concurrent] Client B archived Task1 (not synced yet)');
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ export const waitForSyncComplete = async (
|
|||
// The icon is small (10px) and absolutely positioned, so use count() check
|
||||
const syncStateIcon = page.locator('.sync-btn mat-icon.sync-state-ico');
|
||||
if ((await syncStateIcon.count()) > 0) {
|
||||
// Add extra wait to ensure IndexedDB writes complete and state settles
|
||||
await page.waitForTimeout(500);
|
||||
return 'success';
|
||||
}
|
||||
|
||||
|
|
@ -178,6 +180,8 @@ export const waitForSyncComplete = async (
|
|||
// Final check - make sure sync button is still there and no error shown
|
||||
const syncBtnVisible = await syncPage.syncBtn.isVisible().catch(() => false);
|
||||
if (syncBtnVisible) {
|
||||
// Add extra wait to ensure IndexedDB writes complete and state settles
|
||||
await page.waitForTimeout(500);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
|
@ -217,6 +221,25 @@ export const waitForSync = async (
|
|||
syncPage: SyncPage,
|
||||
): Promise<'success' | 'conflict' | void> => waitForSyncComplete(page, syncPage);
|
||||
|
||||
/**
|
||||
* Waits for archive operations to complete and persist.
|
||||
* Archive operations (finish day, archive task) involve async IndexedDB writes
|
||||
* that may not complete immediately. This helper ensures state is stable before proceeding.
|
||||
*
|
||||
* @param page - Playwright page instance
|
||||
* @param waitMs - Time to wait in milliseconds (default: 1000ms)
|
||||
*/
|
||||
export const waitForArchivePersistence = async (
|
||||
page: Page,
|
||||
waitMs: number = 1000,
|
||||
): Promise<void> => {
|
||||
// Wait for IndexedDB operations to complete
|
||||
await page.waitForTimeout(waitMs);
|
||||
|
||||
// Additional check: wait for any pending micro-tasks/animations
|
||||
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 100)));
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulates network failure by aborting all WebDAV requests.
|
||||
* Useful for testing offline/error scenarios.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue