Improve local backup permissions and change tracking
All checks were successful
Deploy Sokko G / deploy (push) Successful in 19s

This commit is contained in:
Shinuwa 2026-09-25 10:45:12 +02:00
parent 34e542be28
commit ee823d2c37
13 changed files with 372 additions and 37 deletions

View file

@ -1,5 +1,5 @@
// Rôle : couvre les parcours navigateur principaux des toolboxes locales.
/* global window, CustomEvent */
/* global window, navigator, CustomEvent, FileSystemDirectoryHandle */
import { expect, test } from "@playwright/test";
import path from "node:path";
import { fileURLToPath } from "node:url";
@ -249,6 +249,8 @@ test("opens the local automatic backup settings modal", async ({ page }) => {
await expect(dialog).toBeVisible();
await expect(dialog.getByText("Cette fonctionnalité n’est pas disponible dans tous les navigateurs.")).toBeVisible();
await expect(dialog.getByText("Opera GX", { exact: true })).toBeVisible();
await expect(dialog.getByText("Fonctionnement de l’autorisation", { exact: true })).toBeVisible();
await expect(dialog.getByText("la popup système ne peut apparaître qu’après un clic de votre part.")).toBeVisible();
await expect(dialog.getByText("10 versions sont conservées.", { exact: true })).toBeVisible();
await expect(dialog.getByText("Dossier configuré :", { exact: true })).toBeVisible();
await expect(dialog.getByText("Aucun dossier", { exact: true })).toBeVisible();
@ -258,6 +260,96 @@ test("opens the local automatic backup settings modal", async ({ page }) => {
await expect(dialog).toHaveCount(0);
});
test("offers an actionable backup alert without requesting permission at startup", async ({ page }) => {
await page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
const directoryHandle = await navigator.storage.getDirectory();
await db.setSetting("autoBackup", {
enabled: true,
directoryHandle,
lastBackup: "",
lastBackupSignature: "",
hasUnsavedChanges: false
});
});
await page.addInitScript(() => {
window.backupPermissionRequests = 0;
window.backupPermissionGranted = false;
Object.defineProperty(FileSystemDirectoryHandle.prototype, "queryPermission", {
configurable: true,
value: async () => window.backupPermissionGranted ? "granted" : "prompt"
});
Object.defineProperty(FileSystemDirectoryHandle.prototype, "requestPermission", {
configurable: true,
value: async () => {
window.backupPermissionRequests += 1;
window.backupPermissionGranted = true;
return "granted";
}
});
});
await page.reload();
await page.goto("/#/toolboxes");
await expect(page.getByText("Des modifications ont été détectées dans vos toolboxes.")).toHaveCount(0);
await createToolbox(page, "Toolbox à sauvegarder");
const reminder = page.getByRole("status").filter({ hasText: "Des modifications ont été détectées dans vos toolboxes." });
await expect(reminder).toBeVisible();
await expect(page.getByRole("dialog", { name: "Sauvegarde automatique" })).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(0);
await reminder.getByRole("button", { name: "Sauvegarder", exact: true }).click();
await expect(reminder).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(1);
await expect.poll(async () => page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
return (await db.getSetting("autoBackup", {})).hasUnsavedChanges;
})).toBe(false);
});
test("backs up silently when folder access is still granted", async ({ page }) => {
await page.evaluate(async () => {
const db = await import("/src/utils/indexedDbStorage.js");
const directoryHandle = await navigator.storage.getDirectory();
for await (const [name, handle] of directoryHandle.entries()) {
if (handle.kind === "file" && /^sokkog-global-\d{4}-\d{2}-\d{2}\.json$/.test(name)) await directoryHandle.removeEntry(name);
}
await db.setSetting("autoBackup", {
enabled: true,
directoryHandle,
lastBackup: "",
lastBackupSignature: "",
hasUnsavedChanges: false
});
});
await page.addInitScript(() => {
window.backupPermissionRequests = 0;
Object.defineProperty(FileSystemDirectoryHandle.prototype, "queryPermission", {
configurable: true,
value: async () => "granted"
});
Object.defineProperty(FileSystemDirectoryHandle.prototype, "requestPermission", {
configurable: true,
value: async () => {
window.backupPermissionRequests += 1;
return "granted";
}
});
});
await page.reload();
await expect.poll(async () => page.evaluate(async () => {
const directoryHandle = await navigator.storage.getDirectory();
for await (const [name, handle] of directoryHandle.entries()) {
if (handle.kind === "file" && /^sokkog-global-\d{4}-\d{2}-\d{2}\.json$/.test(name)) return true;
}
return false;
})).toBe(true);
await expect(page.getByText("Des modifications ont été détectées dans vos toolboxes.")).toHaveCount(0);
expect(await page.evaluate(() => window.backupPermissionRequests)).toBe(0);
});
test("edits a table with formulas and persists values", async ({ page }) => {
await createToolbox(page, "Table E2E Toolbox");
await addTool(page, "Tableau");