mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-10-19 22:17:28 +02:00
refactor: cleanup
This commit is contained in:
1 parent
7962e97474
commit
f05aaa2cf2
31 files changed
+432
-2305
No files matched your search
@@ -1076,25 +1076,6 @@ test("cookie import/copy/export, profile encryption, and traffic-stat read/clear
|
||||
|
||||
test("deleted profiles land in the trash and come back intact on restore", async () => {
|
||||
await withApp("entities-trash", async (app) => {
|
||||
const initialSettings = await app.invoke("get_app_settings");
|
||||
assert.equal(initialSettings.trash_retention_days, 30);
|
||||
const savedSettings = await app.invoke("save_app_settings", {
|
||||
settings: { ...initialSettings, trash_retention_days: 7 },
|
||||
});
|
||||
assert.equal(savedSettings.trash_retention_days, 7);
|
||||
assert.equal(
|
||||
(await app.invoke("get_app_settings")).trash_retention_days,
|
||||
7,
|
||||
);
|
||||
// Out-of-range values are clamped, never rejected.
|
||||
const clamped = await app.invoke("save_app_settings", {
|
||||
settings: { ...savedSettings, trash_retention_days: 9000 },
|
||||
});
|
||||
assert.equal(clamped.trash_retention_days, 365);
|
||||
await app.invoke("save_app_settings", {
|
||||
settings: { ...clamped, trash_retention_days: 7 },
|
||||
});
|
||||
|
||||
assert.deepEqual(await app.invoke("list_trashed_profiles"), []);
|
||||
|
||||
const group = await app.invoke("create_profile_group", {
|
||||
@@ -1157,7 +1138,7 @@ test("deleted profiles land in the trash and come back intact on restore", async
|
||||
assert.equal(trashed[0].password_protected, false);
|
||||
assert.equal(
|
||||
trashed[0].expires_at - trashed[0].deleted_at,
|
||||
7 * 24 * 60 * 60,
|
||||
30 * 24 * 60 * 60,
|
||||
);
|
||||
assert.ok(trashed[0].size_bytes > 0);
|
||||
const trashDir = path.join(app.dataRoot, "data", "trash");
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { existsSync } from "node:fs";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
@@ -275,115 +274,3 @@ test("tray labels, hide-to-tray, and confirmed quit follow the native lifecycle"
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("the data directory can be moved to another folder and the choice survives a restart", async () => {
|
||||
await withApp(
|
||||
"smoke-data-root",
|
||||
async (app) => {
|
||||
// Every path below is inside this session's own temporary root. The
|
||||
// real installation is never a source or a destination here.
|
||||
const defaultRoot = path.join(app.dataRoot, "data");
|
||||
const pointerFile = path.join(app.dataRoot, "data-root.json");
|
||||
const destination = path.join(app.root, "moved-donut-data");
|
||||
|
||||
const before = await app.invoke("get_data_root_info");
|
||||
assert.equal(before.active_path, defaultRoot);
|
||||
assert.equal(before.configured_path, null);
|
||||
assert.equal(before.restart_required, false);
|
||||
assert.equal(before.active_path_missing, false);
|
||||
assert.equal(before.overridden_by_environment, false);
|
||||
assert.ok(before.file_count > 0, "the seeded settings file is counted");
|
||||
assert.ok(before.size_bytes > 0, "the directory reports a real size");
|
||||
assert.equal(typeof before.app_directory_name, "string");
|
||||
|
||||
const profile = await app.invoke("create_browser_profile_new", {
|
||||
name: "Carried Across",
|
||||
browserStr: "wayfern",
|
||||
version: "150.0.7871.100",
|
||||
releaseType: "stable",
|
||||
proxyId: null,
|
||||
vpnId: null,
|
||||
wayfernConfig: { fingerprint: "{}" },
|
||||
groupId: null,
|
||||
ephemeral: false,
|
||||
dnsBlocklist: null,
|
||||
launchHook: null,
|
||||
});
|
||||
|
||||
// Each refusal is its own code, because each one has a different fix.
|
||||
assert.match(
|
||||
await app.invokeError("move_data_root", { destination: defaultRoot }),
|
||||
/DATA_ROOT_SAME_AS_CURRENT/,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("move_data_root", {
|
||||
destination: path.join(defaultRoot, "profiles", "elsewhere"),
|
||||
}),
|
||||
/DATA_ROOT_DESTINATION_INSIDE_SOURCE/,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("move_data_root", {
|
||||
destination: "not/absolute",
|
||||
}),
|
||||
/DATA_ROOT_DESTINATION_NOT_WRITABLE/,
|
||||
);
|
||||
assert.equal(
|
||||
existsSync(destination),
|
||||
false,
|
||||
"a refused move must not create the destination",
|
||||
);
|
||||
|
||||
const moved = await app.invoke("move_data_root", { destination });
|
||||
assert.equal(moved.configured_path, destination);
|
||||
assert.equal(moved.restart_required, true);
|
||||
// The move takes effect at the next start: this process keeps every
|
||||
// path it resolved when it started.
|
||||
assert.equal(moved.active_path, defaultRoot);
|
||||
|
||||
// Copy, then verify, then delete: the old directory only goes once the
|
||||
// copy has been proven whole.
|
||||
assert.equal(existsSync(defaultRoot), false, "the source is removed");
|
||||
assert.ok(
|
||||
existsSync(path.join(destination, "settings", "app_settings.json")),
|
||||
"settings travelled with the move",
|
||||
);
|
||||
assert.ok(
|
||||
existsSync(path.join(destination, "profiles")),
|
||||
"profiles travelled with the move",
|
||||
);
|
||||
|
||||
// The pointer lives beside the data directory, never inside it, or the
|
||||
// delete above would have taken it and the next start would forget.
|
||||
const pointer = JSON.parse(await readFile(pointerFile, "utf8"));
|
||||
assert.equal(pointer.path, destination);
|
||||
|
||||
await app.restart();
|
||||
|
||||
const after = await app.invoke("get_data_root_info");
|
||||
assert.equal(after.active_path, destination);
|
||||
assert.equal(after.configured_path, destination);
|
||||
assert.equal(after.restart_required, false);
|
||||
assert.equal(after.active_path_missing, false);
|
||||
|
||||
const profiles = await app.invoke("list_browser_profiles");
|
||||
assert.ok(
|
||||
profiles.some((entry) => entry.id === profile.id),
|
||||
"the moved directory still holds the profile",
|
||||
);
|
||||
const settings = await app.invoke("get_app_settings");
|
||||
assert.equal(settings.onboarding_completed, true);
|
||||
|
||||
// Forgetting the choice is the escape hatch for a drive that is gone
|
||||
// for good; it moves nothing, so it too only lands on the next start.
|
||||
const cleared = await app.invoke("clear_data_root_choice");
|
||||
assert.equal(cleared.configured_path, null);
|
||||
assert.equal(existsSync(pointerFile), false);
|
||||
|
||||
await app.restart();
|
||||
const restored = await app.invoke("get_data_root_info");
|
||||
assert.equal(restored.active_path, defaultRoot);
|
||||
assert.equal(restored.configured_path, null);
|
||||
},
|
||||
{ seedDownloadedBrowser: true },
|
||||
);
|
||||
});
|
||||
@@ -2150,138 +2150,6 @@ async function restoreStubs(app) {
|
||||
);
|
||||
}
|
||||
|
||||
const DATA_ROOT = en.settings.dataRoot;
|
||||
|
||||
test("the data directory setting shows where state lives, refuses a bad move, and reports the one it makes", async () => {
|
||||
await withApp("ui-data-root", async (app) => {
|
||||
const defaultRoot = path.join(app.dataRoot, "data");
|
||||
await app.clickSelector(`[aria-label="${en.rail.settings}"]`);
|
||||
await app.waitFor(
|
||||
() =>
|
||||
app.execute(
|
||||
`return Boolean(document.querySelector('[data-slot="data-root-setting"]'));`,
|
||||
),
|
||||
{ description: "the data directory control" },
|
||||
);
|
||||
|
||||
const shown = await app.execute(
|
||||
`return {
|
||||
path: document.querySelector('[data-slot="data-root-active-path"]')?.innerText ?? null,
|
||||
size: document.querySelector('[data-slot="data-root-size"]')?.innerText ?? null,
|
||||
moveDisabled: document.querySelector('[data-slot="data-root-move"]')?.disabled ?? null,
|
||||
missing: Boolean(document.querySelector('[data-slot="data-root-missing"]')),
|
||||
restart: Boolean(document.querySelector('[data-slot="data-root-restart-required"]')),
|
||||
};`,
|
||||
);
|
||||
assert.equal(shown.path, defaultRoot, "the real directory is on screen");
|
||||
assert.match(shown.size, /\d/, "the size has to be a real figure");
|
||||
assert.equal(
|
||||
shown.moveDisabled,
|
||||
true,
|
||||
"there is nowhere to move to until a folder is chosen",
|
||||
);
|
||||
assert.equal(shown.missing, false);
|
||||
assert.equal(shown.restart, false);
|
||||
assert.equal(await app.visibleTextIncludes(DATA_ROOT.title), true);
|
||||
|
||||
// A folder inside the current directory: the copy would never finish and
|
||||
// the delete afterwards would take the copy with it.
|
||||
await stubFolderPicker(app, path.join(defaultRoot, "profiles"));
|
||||
await app.clickSelector('[data-slot="data-root-choose"]');
|
||||
await app.waitFor(
|
||||
async () =>
|
||||
(await app.execute(
|
||||
`return document.querySelector('[data-slot="data-root-move"]')?.disabled;`,
|
||||
)) === false,
|
||||
{ description: "the move button waking up once a folder is chosen" },
|
||||
);
|
||||
const chosen = await app.execute(
|
||||
`return document.querySelector('[data-slot="data-root-destination"]')?.innerText ?? null;`,
|
||||
);
|
||||
assert.ok(
|
||||
chosen?.startsWith(path.join(defaultRoot, "profiles")),
|
||||
`the exact destination has to be shown before committing, got: ${chosen}`,
|
||||
);
|
||||
|
||||
await app.clickSelector('[data-slot="data-root-move"]');
|
||||
await app.waitFor(
|
||||
() =>
|
||||
app.execute(
|
||||
`return Boolean(document.querySelector('[data-slot="data-root-error"]'));`,
|
||||
),
|
||||
{ description: "the refusal" },
|
||||
);
|
||||
assert.equal(
|
||||
(await restoreFolderPicker(app)).length,
|
||||
1,
|
||||
"the first choice went through the picker",
|
||||
);
|
||||
assert.equal(
|
||||
await app.execute(
|
||||
`return document.querySelector('[data-slot="data-root-error"]').innerText.trim();`,
|
||||
),
|
||||
en.backendErrors.dataRootDestinationInsideSource,
|
||||
"a refusal is a translated sentence, never a raw code",
|
||||
);
|
||||
await app.capture("data-root-refused");
|
||||
|
||||
// Nothing was created for a move that was never going to run.
|
||||
assert.equal(
|
||||
await app
|
||||
.invoke("get_data_root_info")
|
||||
.then((info) => info.configured_path),
|
||||
null,
|
||||
);
|
||||
|
||||
// Now a real move, into this session's own temporary root.
|
||||
const destination = path.join(app.root, "ui-moved-data");
|
||||
await stubFolderPicker(app, destination);
|
||||
await app.clickSelector('[data-slot="data-root-choose"]');
|
||||
await app.waitFor(
|
||||
async () =>
|
||||
(
|
||||
await app.execute(
|
||||
`return document.querySelector('[data-slot="data-root-destination"]')?.innerText ?? "";`,
|
||||
)
|
||||
).startsWith(destination),
|
||||
{ description: "the new destination on screen" },
|
||||
);
|
||||
await app.clickSelector('[data-slot="data-root-move"]');
|
||||
await app.waitFor(
|
||||
() =>
|
||||
app.execute(
|
||||
`return Boolean(document.querySelector('[data-slot="data-root-restart-required"]'));`,
|
||||
),
|
||||
{ description: "the restart notice", timeoutMs: 60_000 },
|
||||
);
|
||||
assert.equal(
|
||||
await app.execute(
|
||||
`return Boolean(document.querySelector('[data-slot="data-root-error"]'));`,
|
||||
),
|
||||
false,
|
||||
"a move that worked must not also report an error",
|
||||
);
|
||||
await app.capture("data-root-moved");
|
||||
|
||||
// The fixture clears its own log each time it is installed, so this reads
|
||||
// only the second choice.
|
||||
const picks = await restoreFolderPicker(app);
|
||||
assert.equal(picks.length, 1);
|
||||
assert.equal(
|
||||
picks[0]?.options?.directory,
|
||||
true,
|
||||
"the control asks for a folder, not a file",
|
||||
);
|
||||
|
||||
const info = await app.invoke("get_data_root_info");
|
||||
assert.ok(
|
||||
info.configured_path?.startsWith(destination),
|
||||
`the choice has to be recorded, got: ${info.configured_path}`,
|
||||
);
|
||||
assert.equal(info.restart_required, true);
|
||||
});
|
||||
});
|
||||
|
||||
const SYNC = en.profiles.synchronizer;
|
||||
|
||||
test("the synchroniser panel lists a live session and its controls act on the real state", async () => {
|
||||
|
||||
Reference in new issue
Block a user