mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-08 04:08:46 +02:00
refactor: cleanup
This commit is contained in:
Generated
+1
@@ -1809,6 +1809,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"futures-util",
|
||||
"globset",
|
||||
"gtk",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const commandCoverage = {
|
||||
"get_system_info",
|
||||
"dismiss_window_resize_warning",
|
||||
"get_window_resize_warning_dismissed",
|
||||
"window_decorations::get_window_decoration_layout",
|
||||
"get_onboarding_completed",
|
||||
"complete_onboarding",
|
||||
],
|
||||
@@ -71,6 +72,7 @@ export const commandCoverage = {
|
||||
"update_stored_proxy",
|
||||
"delete_stored_proxy",
|
||||
"check_proxy_validity",
|
||||
"validate_vless_uri",
|
||||
"get_cached_proxy_check",
|
||||
"export_proxies",
|
||||
"import_proxies_json",
|
||||
@@ -277,6 +279,10 @@ export const commandCoverage = {
|
||||
"get_cookie_bot_presets",
|
||||
"get_remote_hours_quota",
|
||||
"get_cookie_bot_usage",
|
||||
"cookie_bot::get_cookie_bot_user_templates",
|
||||
"cookie_bot::create_cookie_bot_user_template",
|
||||
"cookie_bot::update_cookie_bot_user_template",
|
||||
"cookie_bot::delete_cookie_bot_user_template",
|
||||
],
|
||||
},
|
||||
updateContracts: {
|
||||
|
||||
@@ -93,6 +93,34 @@ test("profile, group, proxy, tag, metadata, clone, and bulk-delete lifecycle", a
|
||||
});
|
||||
assert.ok(cachedValidity === null || cachedValidity.is_valid === false);
|
||||
|
||||
// Donut accepts one VLESS shape (REALITY + XTLS Vision over TCP). The form
|
||||
// uses this to tell the user WHICH part of their setup is unsupported
|
||||
// instead of implying they mistyped, so the reason must survive the IPC hop.
|
||||
const goodVless =
|
||||
"vless://6d6e21a1-4829-4d2b-bc7f-1b25707b61e4@example.com:443" +
|
||||
"?security=reality&flow=xtls-rprx-vision&encryption=none&type=tcp" +
|
||||
"&sni=a.com&pbk=mQB9jxUDHO7g49VaNXLEdcNQ_jLhTbLolUsMUNwb6W4&sid=00&fp=chrome";
|
||||
assert.equal(
|
||||
await app.invoke("validate_vless_uri", { uri: goodVless }),
|
||||
null,
|
||||
);
|
||||
|
||||
for (const [uri, reason] of [
|
||||
[goodVless.replace("security=reality", "security=tls"), "security"],
|
||||
[goodVless.replace("type=tcp", "type=ws"), "transport"],
|
||||
[goodVless.replace("flow=xtls-rprx-vision", "flow=none"), "flow"],
|
||||
]) {
|
||||
// invokeError returns the command's error wrapped in a message, so match
|
||||
// rather than JSON.parse the whole string.
|
||||
const error = await app.invokeError("validate_vless_uri", { uri });
|
||||
assert.match(error, /VLESS_CONFIG_INVALID/);
|
||||
assert.match(
|
||||
error,
|
||||
new RegExp(`"reason":"${reason}"`),
|
||||
`expected reason ${reason} for ${uri}, got: ${error}`,
|
||||
);
|
||||
}
|
||||
|
||||
const exported = JSON.parse(
|
||||
await app.invoke("export_proxies", { format: "json" }),
|
||||
);
|
||||
|
||||
@@ -718,6 +718,33 @@ test("offline cloud, update, team-lock, trial, and synchronizer contracts are de
|
||||
}),
|
||||
notSignedIn,
|
||||
);
|
||||
// Saved site lists are cloud-backed like the schedules above, so they
|
||||
// must refuse the same way rather than appearing to work offline.
|
||||
assert.match(
|
||||
await app.invokeError("get_cookie_bot_user_templates", {}),
|
||||
notSignedIn,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("create_cookie_bot_user_template", {
|
||||
name: "e2e list",
|
||||
sites: ["example.com"],
|
||||
}),
|
||||
notSignedIn,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("update_cookie_bot_user_template", {
|
||||
id: "00000000-0000-0000-0000-000000000000",
|
||||
name: "renamed",
|
||||
sites: null,
|
||||
}),
|
||||
notSignedIn,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("delete_cookie_bot_user_template", {
|
||||
id: "00000000-0000-0000-0000-000000000000",
|
||||
}),
|
||||
notSignedIn,
|
||||
);
|
||||
assert.match(
|
||||
await app.invokeError("check_cookie_bot_conflicts", {
|
||||
profileId: missingProfileId,
|
||||
|
||||
@@ -22,6 +22,30 @@ test("fresh app renders, completes onboarding, persists settings, and never touc
|
||||
true,
|
||||
);
|
||||
|
||||
// Where the app draws its own titlebar it also owns the window controls,
|
||||
// so it needs the desktop's button layout to know which side they go on.
|
||||
const decorations = await app.invoke("get_window_decoration_layout");
|
||||
assert.equal(typeof decorations?.client_side, "boolean");
|
||||
if (decorations.client_side) {
|
||||
// Only reported where decorations were actually dropped, which is
|
||||
// every Linux session except KDE on Wayland.
|
||||
assert.equal(process.platform, "linux");
|
||||
// `layout` may be null when GtkSettings is unavailable; the frontend
|
||||
// falls back to the default arrangement rather than drawing nothing,
|
||||
// so asserting a string here would be stricter than the contract.
|
||||
if (decorations.layout !== null) {
|
||||
assert.equal(typeof decorations.layout, "string");
|
||||
assert.match(
|
||||
decorations.layout,
|
||||
/close|minimize|maximize/,
|
||||
`layout must name a drawable control, got: ${decorations.layout}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// The platform still draws a titlebar; the app must not draw a second.
|
||||
assert.equal(decorations.layout, null);
|
||||
}
|
||||
|
||||
const saved = await app.invoke("save_app_settings", {
|
||||
settings: {
|
||||
...initial,
|
||||
@@ -113,8 +137,12 @@ test("keyboard command palette and major navigation surfaces are operable throug
|
||||
assert.match(body, /Settings/i);
|
||||
|
||||
// Exercise native WebDriver element marshalling and click, not just script execution.
|
||||
// Scoped to the open dialog on purpose: on Linux the app draws its own
|
||||
// titlebar, whose "Close window" control appears earlier in the DOM, and
|
||||
// clicking that would exercise the window lifecycle instead of the palette.
|
||||
const close = await app.execute(
|
||||
`return [...document.querySelectorAll("button")].find(
|
||||
`const dialog = document.querySelector("[role='dialog']") ?? document;
|
||||
return [...dialog.querySelectorAll("button")].find(
|
||||
(button) => /close/i.test(button.getAttribute("aria-label") || button.textContent || "")
|
||||
) ?? null;`,
|
||||
);
|
||||
|
||||
+17
-1
@@ -474,7 +474,7 @@ test("VLESS proxy form keeps the share URI as one clear, validated input", async
|
||||
await app.clickSelector('[aria-label="New proxy"]');
|
||||
await app.waitForText("Add Proxy");
|
||||
await app.fillSelector("#proxy-name", "E2E VLESS");
|
||||
await chooseSelectOption(app, "#proxy-type", "VLESS · Vision · REALITY");
|
||||
await chooseSelectOption(app, "#proxy-type", "VLESS");
|
||||
|
||||
assert.equal(
|
||||
await app.execute(
|
||||
@@ -512,6 +512,22 @@ test("VLESS proxy form keeps the share URI as one clear, validated input", async
|
||||
true,
|
||||
);
|
||||
|
||||
// A well-formed URI for a setup Donut cannot use must say WHICH part is
|
||||
// unsupported, rather than implying the user mistyped it.
|
||||
await app.fillSelector(
|
||||
"#proxy-vless-uri",
|
||||
`${uri.replace("type=tcp", "type=ws")}&path=%2Fray`,
|
||||
);
|
||||
await app.waitFor(
|
||||
() =>
|
||||
app.execute(
|
||||
`return /only|TCP|transport/i.test(
|
||||
document.querySelector("#proxy-vless-uri-help")?.textContent || ""
|
||||
);`,
|
||||
),
|
||||
{ description: "transport-specific unsupported message" },
|
||||
);
|
||||
|
||||
await app.fillSelector("#proxy-vless-uri", uri);
|
||||
await app.waitFor(
|
||||
() =>
|
||||
|
||||
Reference in New Issue
Block a user