From 0be1d543479e756cd04081ac0a8bb89a9bcab47f Mon Sep 17 00:00:00 2001 From: "Adrien W." Date: Sat, 10 Oct 2026 17:10:00 +0200 Subject: [PATCH] Fixed sync tests --- SYNC.md | 5 ++--- src/routes/SyncSettings.svelte | 10 +++++++++- tests/e2e/sync.spec.js | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/SYNC.md b/SYNC.md index f597baa..b9d1a2c 100644 --- a/SYNC.md +++ b/SYNC.md @@ -15,9 +15,8 @@ Dans **Données et sauvegardes → Synchronisation et appareils** : de gestionnaire de secrets. - Ajouter un appareil depuis ce même écran. L’invitation expire après cinq minutes, n’accepte qu’un candidat et doit être renouvelée par l’écran visible toutes les - quelques secondes. En quittant l’écran ou en passant à l’appareil photo, les - battements s’arrêtent et le bail serveur expire sous 25 secondes si l’invitation - n’est pas reprise. + quelques secondes. Quitter ou masquer l’écran l’annule ; après une fermeture + brutale, le bail serveur expire sous 25 secondes. - Saisir les huit caractères sur le nouvel appareil ou scanner le QR avec la caméra d’un appareil compatible. Le QR ouvre l’application web ; le navigateur/profil qui reçoit ce lien doit être celui dans lequel on veut utiliser Pardis. Les copies diff --git a/src/routes/SyncSettings.svelte b/src/routes/SyncSettings.svelte index e755204..0b30871 100644 --- a/src/routes/SyncSettings.svelte +++ b/src/routes/SyncSettings.svelte @@ -181,7 +181,15 @@ const hash = () => { void resumePairback(); }; window.addEventListener('hashchange', hash); const timer = setInterval(poll, 3000); - return () => { alive = false; clearInterval(timer); window.removeEventListener('hashchange', hash); void stopScanner(); }; + const hide = () => { if (document.visibilityState === 'hidden' && invite) void stopInvitation(); }; + const leave = () => { void stopInvitation(); }; + document.addEventListener('visibilitychange', hide); + window.addEventListener('pagehide', leave); + return () => { + alive = false; clearInterval(timer); window.removeEventListener('hashchange', hash); + document.removeEventListener('visibilitychange', hide); window.removeEventListener('pagehide', leave); + void stopScanner(); void cancelInvitation(); + }; }); const settingLabels = { workdays: 'Jours travaillés', nonWorkingDates: 'Jours non travaillés', diff --git a/tests/e2e/sync.spec.js b/tests/e2e/sync.spec.js index 1a558ce..2f1635e 100644 --- a/tests/e2e/sync.spec.js +++ b/tests/e2e/sync.spec.js @@ -26,11 +26,11 @@ async function ready(page) { async function create(page) { await ready(page); await page.getByLabel('Nom de cet appareil', { exact: true }).fill('Téléphone test'); - await page.getByRole('button', { name: 'Préparer la synchronisation', exact: true }).click(); + await page.getByRole('button', { name: 'Créer mon coffre', exact: true }).click(); await page.getByText('Afficher le document pour le copier', { exact: true }).click(); const recovery = await page.getByLabel('Contenu du document de secours').inputValue(); await page.getByRole('checkbox', { name: 'J’ai conservé une copie du document à part' }).check(); - await page.getByRole('button', { name: 'Activer la synchronisation', exact: true }).click(); + await page.getByRole('button', { name: 'Créer le coffre et activer la synchronisation', exact: true }).click(); await expect(page.getByRole('heading', { name: 'Appareils autorisés', exact: true })).toBeVisible(); await expect(page.getByRole('button', { name: 'Synchroniser maintenant', exact: true })).toBeEnabled(); await expect(page.locator('fieldset')).not.toContainText('Opération impossible'); @@ -54,6 +54,8 @@ async function pair(a, b) { await a.getByLabel('Nom du nouvel appareil', { exact: true }).fill('Ordinateur test'); await a.getByRole('checkbox', { name: 'Les deux empreintes sont identiques' }).check(); await a.getByRole('button', { name: 'Autoriser cet appareil', exact: true }).click(); + await expect(b.getByRole('heading', { name: 'Choisir les données à conserver', exact: true })).toBeVisible({ timeout: 15000 }); + await b.getByRole('button', { name: 'Tout conserver du coffre existant', exact: true }).click(); await expect(b.getByRole('heading', { name: 'Appareils autorisés', exact: true })).toBeVisible({ timeout: 15000 }); await sync(b); } @@ -85,6 +87,7 @@ test('association, modification hors ligne, conflit, rôle et révocation entre await editTask(page, 'Modification téléphone'); await editTask(other, 'Modification ordinateur'); await page.context().setOffline(false); await sync(page); await otherContext.setOffline(false); await sync(other); await sync(page); + await page.getByRole('button', { name: 'Fusion manuelle détaillée (1)', exact: true }).click(); await expect(page.getByRole('heading', { name: 'Versions à départager (1)', exact: true })).toBeVisible(); await expect(page.locator('.conflict')).toContainText('Modification téléphone'); await expect(page.locator('.conflict')).toContainText('Modification ordinateur'); @@ -96,6 +99,7 @@ test('association, modification hors ligne, conflit, rôle et révocation entre expect((await store(other, 'entries', 'getAll'))[0].task).toBe('Modification ordinateur'); await other.getByRole('button', { name: 'Utiliser cet appareil pour les automatismes', exact: true }).click(); await expect(other.getByRole('button', { name: 'Utiliser cet appareil pour les automatismes', exact: true })).toHaveCount(0); + await page.getByRole('button', { name: 'Retour aux appareils', exact: true }).click(); await sync(page); await expect(page.getByRole('button', { name: 'Utiliser cet appareil pour les automatismes', exact: true })).toBeVisible(); await page.getByRole('button', { name: 'Retirer cet appareil…', exact: true }).click();