mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-04-04 23:05:19 -04:00
Update tests and reload state after sync (#1617)
This commit is contained in:
committed by
Leendert de Borst
parent
0148a2967a
commit
c8ee8dabde
@@ -1,6 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import { sendMessage } from 'webext-bridge/popup';
|
||||
|
||||
import type { FullVaultSyncResult } from '@/entrypoints/background/VaultMessageHandler';
|
||||
import { useDb } from '@/entrypoints/popup/context/DbContext';
|
||||
|
||||
import { EncryptionUtility } from '@/utils/EncryptionUtility';
|
||||
@@ -56,6 +57,9 @@ export function useVaultMutate(): {
|
||||
* Trigger a sync in the background script.
|
||||
* This is fire-and-forget - the sync runs entirely in the background context
|
||||
* and continues even if the popup closes.
|
||||
*
|
||||
* If a merge happened during sync (hasNewVault=true), reload the database
|
||||
* so the popup shows the merged data.
|
||||
*/
|
||||
const triggerBackgroundSync = useCallback((): void => {
|
||||
/*
|
||||
@@ -63,7 +67,11 @@ export function useVaultMutate(): {
|
||||
* The background script will handle the full sync orchestration
|
||||
* and will re-sync if mutations happened during the sync.
|
||||
*/
|
||||
sendMessage('FULL_VAULT_SYNC', {}, 'background').then(async () => {
|
||||
sendMessage('FULL_VAULT_SYNC', {}, 'background').then(async (result: FullVaultSyncResult) => {
|
||||
// If a merge happened, reload the database to show merged data
|
||||
if (result.hasNewVault) {
|
||||
await dbContext.loadStoredDatabase();
|
||||
}
|
||||
// Refresh sync state if popup is still open
|
||||
await dbContext.refreshSyncState();
|
||||
}).catch((error) => {
|
||||
|
||||
@@ -73,8 +73,10 @@ test.describe.serial('5. Vault Merge', () => {
|
||||
});
|
||||
|
||||
test('5.4 Client B vault should contain both credentials after merge', async () => {
|
||||
// Trigger sync to ensure background merge has completed and database is reloaded
|
||||
await clientB
|
||||
.goToVault()
|
||||
.triggerSync()
|
||||
.then((c) => c.goToVault())
|
||||
.then((c) => c.screenshot('5.4-client-b-vault-state.png'))
|
||||
.then((c) => c.verifyCredentialExists(credentialNameA));
|
||||
|
||||
|
||||
@@ -81,7 +81,9 @@ test.describe.serial('6. Field-Level Merge', () => {
|
||||
.then((c) => c.fillNotes(clientBNotes))
|
||||
.then((c) => c.screenshot('6.4-client-b-before-save.png'))
|
||||
.then((c) => c.saveCredential())
|
||||
.then((c) => c.screenshot('6.4-client-b-after-save.png'));
|
||||
.then((c) => c.screenshot('6.4-client-b-after-save.png'))
|
||||
// Wait for background sync (including merge) to complete before next test
|
||||
.then((c) => c.triggerSync());
|
||||
});
|
||||
|
||||
test('6.5 Client B verifies field-level merge result', async () => {
|
||||
|
||||
39
apps/browser-extension/tests/fixtures/waits.ts
vendored
39
apps/browser-extension/tests/fixtures/waits.ts
vendored
@@ -65,6 +65,11 @@ export async function waitForVaultReady(popup: Page, timeout: number = Timeouts.
|
||||
* Wait for a sync operation to complete.
|
||||
* Waits for vault UI to be ready, then waits for sync/pending indicators to disappear.
|
||||
*
|
||||
* Indicator elements:
|
||||
* - Syncing (green): <div> with bg-green-100
|
||||
* - Pending (blue): <button> with bg-blue-100
|
||||
* - Offline (amber): <button> with bg-amber-100
|
||||
*
|
||||
* @param popup - The popup page
|
||||
* @param timeout - Timeout in milliseconds
|
||||
*/
|
||||
@@ -78,20 +83,38 @@ export async function waitForSyncComplete(popup: Page, timeout: number = Timeout
|
||||
// Loading overlay might not exist, which is fine
|
||||
});
|
||||
|
||||
// Wait for the sync indicator (green spinning icon) to disappear
|
||||
// Wait for the sync indicator (green spinning div) to disappear
|
||||
const syncIndicator = popup.locator('div.bg-green-100, div.bg-green-900\\/30');
|
||||
await syncIndicator.waitFor({ state: 'hidden', timeout }).catch(() => {
|
||||
// Sync indicator might not exist or sync was very fast, which is fine
|
||||
});
|
||||
|
||||
// Also wait for pending sync indicator (blue icon) to disappear
|
||||
const pendingSyncIndicator = popup.locator('div.bg-blue-100, div.bg-blue-900\\/30');
|
||||
// Also wait for pending sync indicator (blue button) to disappear
|
||||
const pendingSyncIndicator = popup.locator('button.bg-blue-100, button.bg-blue-900\\/30');
|
||||
await pendingSyncIndicator.waitFor({ state: 'hidden', timeout }).catch(() => {
|
||||
// Pending sync indicator might not exist, which is fine
|
||||
});
|
||||
|
||||
// Small buffer to ensure async operations complete after UI indicators disappear
|
||||
await popup.waitForTimeout(100);
|
||||
// Wait for isDirty to be false, indicating sync completed successfully.
|
||||
// This is more reliable than UI indicators since sync now runs in background.
|
||||
const startTime = Date.now();
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const isDirty = await popup.evaluate(() => {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
chrome.storage.local.get('isDirty', (result) => {
|
||||
resolve(result.isDirty ?? false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (!isDirty) {
|
||||
break;
|
||||
}
|
||||
await popup.waitForTimeout(100);
|
||||
}
|
||||
|
||||
// Additional buffer to ensure React state updates and database reload have completed
|
||||
await popup.waitForTimeout(500);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,12 +175,13 @@ export async function waitForNavigation(popup: Page, timeout: number = Timeouts.
|
||||
|
||||
/**
|
||||
* Wait for the offline indicator to appear on the page.
|
||||
* The offline indicator is a <button> element with amber background.
|
||||
*
|
||||
* @param popup - The popup page
|
||||
* @param timeout - Timeout in milliseconds
|
||||
*/
|
||||
export async function waitForOfflineIndicator(popup: Page, timeout: number = Timeouts.SHORT): Promise<void> {
|
||||
const offlineIndicator = popup.locator('div.bg-amber-100, div.bg-amber-900\\/30').filter({ hasText: 'Offline' });
|
||||
const offlineIndicator = popup.locator('button.bg-amber-100, button.bg-amber-900\\/30').filter({ hasText: 'Offline' });
|
||||
await expect(offlineIndicator).toBeVisible({ timeout });
|
||||
}
|
||||
|
||||
@@ -173,11 +197,12 @@ export async function waitForLoginForm(popup: Page, timeout: number = Timeouts.S
|
||||
|
||||
/**
|
||||
* Check if the offline indicator is visible.
|
||||
* The offline indicator is a <button> element with amber background.
|
||||
*
|
||||
* @param popup - The popup page
|
||||
* @returns True if the offline indicator is visible
|
||||
*/
|
||||
export async function isOfflineIndicatorVisible(popup: Page): Promise<boolean> {
|
||||
const offlineIndicator = popup.locator('div.bg-amber-100, div.bg-amber-900\\/30').filter({ hasText: 'Offline' });
|
||||
const offlineIndicator = popup.locator('button.bg-amber-100, button.bg-amber-900\\/30').filter({ hasText: 'Offline' });
|
||||
return offlineIndicator.isVisible().catch(() => false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user