mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-28 06:17:06 +00:00
Complete declarative settings runtime integration
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
captureObsidianElement,
|
||||
captureObsidianPage,
|
||||
obsidianRemoteDebuggingPort,
|
||||
openLiveSyncSettings,
|
||||
withObsidianPage,
|
||||
} from "../runner/ui.ts";
|
||||
import { createTemporaryVault } from "../runner/vault.ts";
|
||||
@@ -46,11 +47,6 @@ type LiveSyncTestPlugin = {
|
||||
};
|
||||
};
|
||||
|
||||
type ObsidianSettingsController = {
|
||||
open(): void;
|
||||
openTabById(tabId: string): void;
|
||||
};
|
||||
|
||||
type ObsidianVaultFile = {
|
||||
path: string;
|
||||
};
|
||||
@@ -58,7 +54,6 @@ type ObsidianVaultFile = {
|
||||
type ObsidianTestApp = {
|
||||
commands?: { executeCommandById(commandId: string): boolean };
|
||||
plugins?: { plugins: Record<string, LiveSyncTestPlugin | undefined> };
|
||||
setting?: ObsidianSettingsController;
|
||||
vault?: {
|
||||
delete(file: ObsidianVaultFile, force: boolean): Promise<void>;
|
||||
getFiles(): ObsidianVaultFile[];
|
||||
@@ -748,17 +743,10 @@ async function verifyCompatibleAlignmentSettingDefault(): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
await page.evaluate(() => {
|
||||
const setting = (globalThis as ObsidianTestGlobal).app?.setting;
|
||||
if (setting === undefined) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
const liveSyncSettings = page.locator(".sls-setting");
|
||||
await liveSyncSettings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Advanced"]').click({ timeout: uiTimeoutMs });
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
const liveSyncSettings = await settingsNavigator.openPage("Advanced");
|
||||
const settingItem = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.getByText("Auto-accept compatible tweak mismatches", { exact: true }),
|
||||
has: settingsNavigator.page.getByText("Auto-accept compatible tweak mismatches", { exact: true }),
|
||||
});
|
||||
await settingItem.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
const toggle = settingItem.locator(".checkbox-container");
|
||||
@@ -944,15 +932,8 @@ async function verifyHatchSurfacesAndSafeActions(): Promise<string> {
|
||||
obsidianRemoteDebuggingPort(),
|
||||
"troubleshooting-hatch.png",
|
||||
async (page) => {
|
||||
await page.evaluate(() => {
|
||||
const setting = (globalThis as ObsidianTestGlobal).app?.setting;
|
||||
if (setting === undefined) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
const liveSyncSettings = page.locator(".sls-setting");
|
||||
await liveSyncSettings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Hatch"]').click({ timeout: uiTimeoutMs });
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
const liveSyncSettings = await settingsNavigator.openPage("Hatch");
|
||||
for (const label of [
|
||||
"Write logs into the file",
|
||||
"Recreate chunks for current Vault files",
|
||||
|
||||
@@ -9,7 +9,12 @@ import { evalObsidianJson } from "../runner/cli.ts";
|
||||
import { discoverObsidianCli, requireObsidianBinary } from "../runner/environment.ts";
|
||||
import { assertMobileDialogueLayout, iPhoneSafeArea, setObsidianMobileTestMode } from "../runner/mobileUi.ts";
|
||||
import { startObsidianLiveSyncSession, type ObsidianLiveSyncSession } from "../runner/session.ts";
|
||||
import { captureObsidianDialogue, obsidianRemoteDebuggingPort, withObsidianPage } from "../runner/ui.ts";
|
||||
import {
|
||||
captureObsidianDialogue,
|
||||
obsidianRemoteDebuggingPort,
|
||||
openLiveSyncSettings,
|
||||
withObsidianPage,
|
||||
} from "../runner/ui.ts";
|
||||
import { createTemporaryVault } from "../runner/vault.ts";
|
||||
|
||||
const uiTimeoutMs = Number(process.env.E2E_OBSIDIAN_ONBOARDING_TIMEOUT_MS ?? 15000);
|
||||
@@ -25,15 +30,6 @@ type UnconfiguredStartupEvidence = {
|
||||
};
|
||||
};
|
||||
|
||||
type ObsidianTestApp = {
|
||||
setting?: {
|
||||
open(): void;
|
||||
openTabById(tabId: string): void;
|
||||
};
|
||||
};
|
||||
|
||||
type ObsidianTestGlobal = typeof globalThis & { app?: ObsidianTestApp };
|
||||
|
||||
async function writeMarker(vaultPath: string): Promise<void> {
|
||||
const fullPath = join(vaultPath, markerPath);
|
||||
await mkdir(dirname(fullPath), { recursive: true });
|
||||
@@ -158,25 +154,17 @@ async function captureAndCloseIntro(filename: string, mobile: boolean): Promise<
|
||||
|
||||
async function openOnboardingFromSettings(): Promise<void> {
|
||||
await withObsidianPage(obsidianRemoteDebuggingPort(), async (page) => {
|
||||
await page.evaluate(() => {
|
||||
const setting = (globalThis as ObsidianTestGlobal).app?.setting;
|
||||
if (setting === undefined) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
|
||||
const liveSyncSettings = page.locator(".sls-setting");
|
||||
await liveSyncSettings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Setup"]').click({ timeout: uiTimeoutMs });
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
const liveSyncSettings = await settingsNavigator.openPage("Setup");
|
||||
|
||||
const onboardingSetting = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.locator(".setting-item-name").filter({ hasText: "Rerun Onboarding Wizard" }),
|
||||
has: settingsNavigator.page.locator(".setting-item-name").filter({ hasText: "Rerun Onboarding Wizard" }),
|
||||
});
|
||||
await onboardingSetting.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await onboardingSetting
|
||||
.getByRole("button", { name: "Rerun Wizard", exact: true })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
await onboardingDialogue(page).waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await onboardingDialogue(settingsNavigator.page).waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -197,11 +185,8 @@ async function dismissVisibleNotices(): Promise<void> {
|
||||
|
||||
async function closeSettings(): Promise<void> {
|
||||
await withObsidianPage(obsidianRemoteDebuggingPort(), async (page) => {
|
||||
const settingsContainer = page.locator(".modal-container").filter({
|
||||
has: page.locator(".sls-setting"),
|
||||
});
|
||||
await settingsContainer.locator(".modal-close-button").click({ timeout: uiTimeoutMs });
|
||||
await settingsContainer.waitFor({ state: "hidden", timeout: uiTimeoutMs });
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
await settingsNavigator.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
waitForLocalDatabaseEntry,
|
||||
} from "../runner/liveSyncWorkflow.ts";
|
||||
import { startObsidianLiveSyncSession, type ObsidianLiveSyncSession } from "../runner/session.ts";
|
||||
import { captureObsidianElement, withObsidianPage } from "../runner/ui.ts";
|
||||
import { captureObsidianElement, openLiveSyncSettings, withObsidianPage } from "../runner/ui.ts";
|
||||
import { createTemporaryVault } from "../runner/vault.ts";
|
||||
import type { Locator, Page } from "playwright";
|
||||
|
||||
@@ -35,17 +35,6 @@ type VaultWinnerState = {
|
||||
winnerRevision: string;
|
||||
};
|
||||
|
||||
type ObsidianSettingsController = {
|
||||
open(): void;
|
||||
openTabById(tabId: string): void;
|
||||
};
|
||||
|
||||
type ObsidianTestGlobal = typeof globalThis & {
|
||||
app?: {
|
||||
setting?: ObsidianSettingsController;
|
||||
};
|
||||
};
|
||||
|
||||
async function createAndOpenBaseFile(cliBinary: string, env: NodeJS.ProcessEnv): Promise<void> {
|
||||
await evalObsidianJson<unknown>(
|
||||
cliBinary,
|
||||
@@ -359,17 +348,10 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
await withObsidianPage(session.remoteDebuggingPort, async (page) => {
|
||||
await page.evaluate(() => {
|
||||
const setting = (globalThis as ObsidianTestGlobal).app?.setting;
|
||||
if (setting === undefined) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
const settings = page.locator(".sls-setting");
|
||||
await settings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await settings.locator('.sls-setting-menu-btn[title="Hatch"]').click({ timeout: uiTimeoutMs });
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
const settings = await settingsNavigator.openPage("Hatch");
|
||||
const verifySetting = settings.locator(".setting-item").filter({
|
||||
has: page.getByText("Inspect conflicts and file/database differences", {
|
||||
has: settingsNavigator.page.getByText("Inspect conflicts and file/database differences", {
|
||||
exact: true,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
import { mkdir } from "node:fs/promises";
|
||||
import { VER } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { discoverObsidianCli, requireObsidianBinary } from "../runner/environment.ts";
|
||||
import { waitForLiveSyncCoreReady } from "../runner/liveSyncWorkflow.ts";
|
||||
import { assertMobileDialogueLayout, setObsidianMobileTestMode } from "../runner/mobileUi.ts";
|
||||
import { startObsidianLiveSyncSession, type ObsidianLiveSyncSession } from "../runner/session.ts";
|
||||
import { captureObsidianDialogue, obsidianRemoteDebuggingPort, withObsidianPage } from "../runner/ui.ts";
|
||||
import {
|
||||
allowPendingObsidianTestVaultOpenAction,
|
||||
captureObsidianDialogue,
|
||||
obsidianRemoteDebuggingPort,
|
||||
openLiveSyncSettings,
|
||||
preseedTrustedVaultState,
|
||||
withObsidianPage,
|
||||
} from "../runner/ui.ts";
|
||||
import { createTemporaryVault } from "../runner/vault.ts";
|
||||
|
||||
const uiTimeoutMs = Number(process.env.E2E_OBSIDIAN_SETTINGS_TIMEOUT_MS ?? 10000);
|
||||
const compatibilityReviewMessage = "Review the internal database compatibility change before synchronisation resumes.";
|
||||
|
||||
type ObsidianSettingsController = {
|
||||
open(): void;
|
||||
openTabById(tabId: string): void;
|
||||
const settingsOnly = process.env.E2E_OBSIDIAN_SETTINGS_ONLY === "true";
|
||||
const diagnosticsDirectory = process.env.E2E_OBSIDIAN_DIAGNOSTICS_DIR ?? "/tmp/obsidian-livesync-e2e";
|
||||
const settingsScreenshotOptions = {
|
||||
animations: "disabled" as const,
|
||||
style: ".notice-container { visibility: hidden !important; }",
|
||||
};
|
||||
const compatibilityReviewMessage = "Review the internal database compatibility change before synchronisation resumes.";
|
||||
|
||||
type LiveSyncTestPlugin = {
|
||||
core: {
|
||||
@@ -34,12 +43,39 @@ type LiveSyncTestPlugin = {
|
||||
};
|
||||
|
||||
type ObsidianTestApp = {
|
||||
setting?: ObsidianSettingsController;
|
||||
plugins?: { plugins: Record<string, LiveSyncTestPlugin | undefined> };
|
||||
};
|
||||
|
||||
type ObsidianTestGlobal = typeof globalThis & { app?: ObsidianTestApp };
|
||||
|
||||
const settingsPageNames = [
|
||||
"Change Log",
|
||||
"Setup",
|
||||
"General Settings",
|
||||
"Remote Configuration",
|
||||
"Sync Settings",
|
||||
"Selector",
|
||||
"Customisation sync",
|
||||
"Hatch",
|
||||
"Advanced",
|
||||
"Power users",
|
||||
"Patches",
|
||||
"Maintenance",
|
||||
] as const;
|
||||
|
||||
async function resumePendingCompatibilityReviewForSettings(): Promise<void> {
|
||||
await withObsidianPage(obsidianRemoteDebuggingPort(), async (page) => {
|
||||
const review = page.locator(".modal-container").filter({
|
||||
has: page.locator(".modal-title").filter({
|
||||
hasText: "Synchronisation paused for compatibility review",
|
||||
}),
|
||||
});
|
||||
if (!(await review.isVisible())) return;
|
||||
await review.getByRole("button", { name: "Resume synchronisation" }).click({ timeout: uiTimeoutMs });
|
||||
await review.waitFor({ state: "hidden", timeout: uiTimeoutMs });
|
||||
});
|
||||
}
|
||||
|
||||
async function verifyCompatibilityReview(): Promise<void> {
|
||||
const port = obsidianRemoteDebuggingPort();
|
||||
const summaryScreenshot = await captureObsidianDialogue(port, "compatibility-review-summary.png", async (page) => {
|
||||
@@ -223,41 +259,26 @@ async function verifyEffectiveSettings(): Promise<void> {
|
||||
sleepPreferences.powerUserMode !== false ||
|
||||
sleepPreferences.edgeCaseMode !== false
|
||||
) {
|
||||
throw new Error(
|
||||
`Unexpected effective sleep preferences: ${JSON.stringify(sleepPreferences)}`
|
||||
);
|
||||
throw new Error(`Unexpected effective sleep preferences: ${JSON.stringify(sleepPreferences)}`);
|
||||
}
|
||||
|
||||
await page.evaluate(() => {
|
||||
const setting = (globalThis as ObsidianTestGlobal).app?.setting;
|
||||
if (setting === undefined) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
|
||||
const liveSyncSettings = page.locator(".sls-setting");
|
||||
await liveSyncSettings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
const settingsClass = await liveSyncSettings.getAttribute("class");
|
||||
for (const modeClass of [
|
||||
"menu-setting-advanced-disabled",
|
||||
"menu-setting-poweruser-disabled",
|
||||
"menu-setting-edgecase-disabled",
|
||||
]) {
|
||||
if (!settingsClass?.split(/\s+/u).includes(modeClass)) {
|
||||
throw new Error(`The settings UI did not disable ${modeClass}.`);
|
||||
let settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
for (const hiddenPage of ["Selector", "Customisation sync", "Advanced", "Power users", "Patches"]) {
|
||||
if (await settingsNavigator.isPageListed(hiddenPage)) {
|
||||
throw new Error(`${hiddenPage} was visible before its feature level was enabled.`);
|
||||
}
|
||||
}
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Change Log"]').click();
|
||||
const removedAcknowledgements = liveSyncSettings.getByRole("button", {
|
||||
let settingsPage = await settingsNavigator.openPage("Change Log");
|
||||
const removedAcknowledgements = settingsPage.getByRole("button", {
|
||||
name: /I got it and updated|OK, I have read everything/u,
|
||||
});
|
||||
if ((await removedAcknowledgements.count()) !== 0) {
|
||||
throw new Error("The Change Log still contains a compatibility or release-note acknowledgement control.");
|
||||
}
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Remote Configuration"]').click();
|
||||
const connectionPanel = liveSyncSettings
|
||||
settingsPage = await settingsNavigator.openPage("Remote Configuration");
|
||||
const connectionPanel = settingsPage
|
||||
.locator("h4.sls-setting-panel-title")
|
||||
.filter({ hasText: "Connection settings" })
|
||||
.locator("..");
|
||||
@@ -267,41 +288,74 @@ async function verifyEffectiveSettings(): Promise<void> {
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Sync Settings"]').click();
|
||||
const generalSleepSetting = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.getByText("Allow sleep during synchronisation", { exact: true }),
|
||||
settingsPage = await settingsNavigator.openPage("Sync Settings");
|
||||
const generalSleepSetting = settingsPage.locator(".setting-item").filter({
|
||||
has: settingsNavigator.page.getByText("Allow sleep during synchronisation", { exact: true }),
|
||||
});
|
||||
await generalSleepSetting.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
if ((await generalSleepSetting.locator(".checkbox-container.is-enabled").count()) !== 0) {
|
||||
throw new Error("The general sleep preference must be disabled by default.");
|
||||
}
|
||||
|
||||
const desktopSleepSetting = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.getByText("Allow sleep during synchronisation on the desktop", { exact: true }),
|
||||
const desktopSleepSetting = settingsPage.locator(".setting-item").filter({
|
||||
has: settingsNavigator.page.getByText("Allow sleep during synchronisation on the desktop", {
|
||||
exact: true,
|
||||
}),
|
||||
});
|
||||
await desktopSleepSetting.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
if ((await desktopSleepSetting.locator(".checkbox-container.is-enabled").count()) !== 1) {
|
||||
throw new Error("The desktop sleep preference must be enabled by default.");
|
||||
}
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Setup"]').click();
|
||||
const advancedModeSetting = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.getByText("Enable advanced features", { exact: true }),
|
||||
settingsPage = await settingsNavigator.openPage("Setup");
|
||||
const advancedModeSetting = settingsPage.locator(".setting-item").filter({
|
||||
has: settingsNavigator.page.getByText("Enable advanced features", { exact: true }),
|
||||
});
|
||||
await advancedModeSetting.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await advancedModeSetting.locator(".checkbox-container").click();
|
||||
await page.waitForFunction(
|
||||
() => document.querySelector(".sls-setting")?.classList.contains("menu-setting-advanced-enabled") === true,
|
||||
() => {
|
||||
const plugin = (globalThis as ObsidianTestGlobal).app?.plugins?.plugins["obsidian-livesync"];
|
||||
return plugin?.core.services.setting.currentSettings().useAdvancedMode === true;
|
||||
},
|
||||
undefined,
|
||||
{ timeout: uiTimeoutMs }
|
||||
);
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Advanced"]').click();
|
||||
const cacheSizeSetting = liveSyncSettings.locator(".setting-item").filter({
|
||||
has: page.getByText("Memory cache size (by total items)", { exact: true }),
|
||||
if (settingsNavigator.renderer === "declarative") {
|
||||
for (const mode of [
|
||||
{ label: "Enable poweruser features", key: "usePowerUserMode" },
|
||||
{ label: "Enable edge case treatment features", key: "useEdgeCaseMode" },
|
||||
] as const) {
|
||||
const modeSetting = settingsPage.locator(".setting-item").filter({
|
||||
has: settingsNavigator.page.getByText(mode.label, { exact: true }),
|
||||
});
|
||||
await modeSetting.locator(".checkbox-container").click({ timeout: uiTimeoutMs });
|
||||
await page.waitForFunction(
|
||||
(key) => {
|
||||
const plugin = (globalThis as ObsidianTestGlobal).app?.plugins?.plugins["obsidian-livesync"];
|
||||
return plugin?.core.services.setting.currentSettings()[key] === true;
|
||||
},
|
||||
mode.key,
|
||||
{ timeout: uiTimeoutMs }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
settingsPage = await settingsNavigator.openPage("Advanced");
|
||||
const cacheSizeSetting = settingsPage.locator(".setting-item").filter({
|
||||
has: settingsNavigator.page.getByText("Memory cache size (by total items)", { exact: true }),
|
||||
});
|
||||
await cacheSizeSetting.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await cacheSizeSetting.locator('input[type="number"]').fill("321");
|
||||
const cacheSizeInput = cacheSizeSetting.locator('input[type="number"]');
|
||||
if (settingsNavigator.renderer === "declarative") {
|
||||
await cacheSizeInput.click();
|
||||
await cacheSizeInput.press("ControlOrMeta+A");
|
||||
await cacheSizeInput.pressSequentially("321");
|
||||
await cacheSizeInput.press("Enter");
|
||||
} else {
|
||||
await cacheSizeInput.fill("321");
|
||||
}
|
||||
await page.waitForFunction(
|
||||
() => {
|
||||
const plugin = (globalThis as ObsidianTestGlobal).app?.plugins?.plugins["obsidian-livesync"];
|
||||
@@ -311,9 +365,44 @@ async function verifyEffectiveSettings(): Promise<void> {
|
||||
{ timeout: uiTimeoutMs }
|
||||
);
|
||||
|
||||
await liveSyncSettings.locator('.sls-setting-menu-btn[title="Sync Settings"]').click();
|
||||
if (settingsNavigator.renderer === "declarative") {
|
||||
await settingsNavigator.returnToCatalogue();
|
||||
await settingsNavigator.dialogue
|
||||
.locator(".vertical-tab-content:visible")
|
||||
.last()
|
||||
.evaluate((element) => {
|
||||
element.scrollTop = 0;
|
||||
});
|
||||
await settingsNavigator.dialogue.screenshot({
|
||||
...settingsScreenshotOptions,
|
||||
path: `${diagnosticsDirectory}/settings-declarative-catalogue.png`,
|
||||
});
|
||||
const search = settingsNavigator.dialogue.locator(".setting-search-container input");
|
||||
await search.fill("Memory cache size (by total items)");
|
||||
const searchResult = settingsNavigator.dialogue.locator(".setting-search-result-item").filter({
|
||||
has: settingsNavigator.page.getByText("Memory cache size (by total items)", { exact: true }),
|
||||
});
|
||||
await settingsNavigator.dialogue.screenshot({
|
||||
...settingsScreenshotOptions,
|
||||
path: `${diagnosticsDirectory}/settings-declarative-search.png`,
|
||||
});
|
||||
await searchResult.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await search.fill("");
|
||||
|
||||
const deletionPanel = liveSyncSettings
|
||||
for (const pageName of settingsPageNames) {
|
||||
const pageRoot = await settingsNavigator.openPage(pageName);
|
||||
await pageRoot.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
}
|
||||
settingsPage = await settingsNavigator.openPage("Advanced");
|
||||
await settingsNavigator.dialogue.screenshot({
|
||||
...settingsScreenshotOptions,
|
||||
path: `${diagnosticsDirectory}/settings-declarative-advanced.png`,
|
||||
});
|
||||
}
|
||||
|
||||
settingsPage = await settingsNavigator.openPage("Sync Settings");
|
||||
|
||||
const deletionPanel = settingsPage
|
||||
.locator("h4.sls-setting-panel-title")
|
||||
.filter({ hasText: "Deletion Propagation" })
|
||||
.locator("..");
|
||||
@@ -328,6 +417,22 @@ async function verifyEffectiveSettings(): Promise<void> {
|
||||
`The obsolete LiveSync trash toggle is still present in the settings UI (${obsoleteToggleCount} found).`
|
||||
);
|
||||
}
|
||||
|
||||
if (settingsNavigator.renderer === "declarative") {
|
||||
await settingsNavigator.close();
|
||||
settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
settingsPage = await settingsNavigator.openPage("Advanced");
|
||||
const restoredValue = await settingsPage
|
||||
.locator(".setting-item")
|
||||
.filter({
|
||||
has: settingsNavigator.page.getByText("Memory cache size (by total items)", { exact: true }),
|
||||
})
|
||||
.locator('input[type="number"]')
|
||||
.inputValue();
|
||||
if (restoredValue !== "321") {
|
||||
throw new Error(`The declarative Advanced value was not restored after reopening: ${restoredValue}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -338,6 +443,7 @@ async function main(): Promise<void> {
|
||||
throw new Error(`Could not find obsidian-cli. Checked paths: ${cli.checked.join(", ")}`);
|
||||
}
|
||||
const vault = await createTemporaryVault();
|
||||
await mkdir(diagnosticsDirectory, { recursive: true });
|
||||
let session: ObsidianLiveSyncSession | undefined;
|
||||
try {
|
||||
session = await startObsidianLiveSyncSession({
|
||||
@@ -346,10 +452,10 @@ async function main(): Promise<void> {
|
||||
vault,
|
||||
startupGraceMs: Number(process.env.E2E_OBSIDIAN_STARTUP_GRACE_MS ?? 1000),
|
||||
pluginData: {
|
||||
doctorProcessedVersion: "0.25.27",
|
||||
doctorProcessedVersion: settingsOnly ? "1.0.0" : "0.25.27",
|
||||
isConfigured: true,
|
||||
liveSync: false,
|
||||
versionUpFlash: compatibilityReviewMessage,
|
||||
versionUpFlash: settingsOnly ? "" : compatibilityReviewMessage,
|
||||
notifyThresholdOfRemoteStorageSize: 0,
|
||||
syncOnStart: false,
|
||||
syncOnSave: false,
|
||||
@@ -362,10 +468,22 @@ async function main(): Promise<void> {
|
||||
usePowerUserMode: false,
|
||||
useEdgeCaseMode: false,
|
||||
},
|
||||
lifecycle: settingsOnly
|
||||
? {
|
||||
afterLaunch: async ({ remoteDebuggingPort }) => {
|
||||
await preseedTrustedVaultState(remoteDebuggingPort, vault.id);
|
||||
await allowPendingObsidianTestVaultOpenAction(remoteDebuggingPort, vault.path, uiTimeoutMs);
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
await waitForLiveSyncCoreReady(cli.binary, session.cliEnv);
|
||||
await verifyCompatibilityReview();
|
||||
await verifyConfigDoctorFollowsCompatibilityReview();
|
||||
if (settingsOnly) {
|
||||
await resumePendingCompatibilityReviewForSettings();
|
||||
} else {
|
||||
await verifyCompatibilityReview();
|
||||
await verifyConfigDoctorFollowsCompatibilityReview();
|
||||
}
|
||||
await verifyEffectiveSettings();
|
||||
console.log("Compatibility review and settings expose only effective user controls.");
|
||||
} finally {
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
captureObsidianDialogue,
|
||||
captureObsidianElement,
|
||||
captureObsidianPage,
|
||||
openLiveSyncSettings,
|
||||
withObsidianPage,
|
||||
} from "../runner/ui.ts";
|
||||
import { createTemporaryVault, type TemporaryVault } from "../runner/vault.ts";
|
||||
@@ -90,12 +91,10 @@ function modalByTitle(page: Page, title: string): Locator {
|
||||
});
|
||||
}
|
||||
|
||||
function settingPanelByTitle(page: Page, title: string): Locator {
|
||||
return page
|
||||
.locator(".sls-setting")
|
||||
.locator("h4.sls-setting-panel-title:visible")
|
||||
.filter({ hasText: title })
|
||||
.locator("..");
|
||||
async function liveSyncSettingPanelByTitle(page: Page, pageName: string, title: string): Promise<Locator> {
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
const settingsPage = await settingsNavigator.openPage(pageName);
|
||||
return settingsPage.locator("h4.sls-setting-panel-title:visible").filter({ hasText: title }).locator("..");
|
||||
}
|
||||
|
||||
async function captureGuideDialogue(port: number, filename: string, title: string): Promise<string> {
|
||||
@@ -535,58 +534,27 @@ async function captureHiddenFileGuideSettings(
|
||||
environment
|
||||
);
|
||||
|
||||
await withObsidianPage(port, async (page) => {
|
||||
await page.evaluate(() => {
|
||||
const obsidian = globalThis as typeof globalThis & {
|
||||
app?: {
|
||||
setting?: {
|
||||
open(): void;
|
||||
openTabById(tabId: string): void;
|
||||
};
|
||||
};
|
||||
};
|
||||
const setting = obsidian.app?.setting;
|
||||
if (!setting) throw new Error("Obsidian settings are unavailable");
|
||||
setting.open();
|
||||
setting.openTabById("obsidian-livesync");
|
||||
});
|
||||
const settings = page.locator(".sls-setting");
|
||||
await settings.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await settings.locator('.sls-setting-menu-btn[title="Setup"]').click({ timeout: uiTimeoutMs });
|
||||
});
|
||||
|
||||
const screenshots = [
|
||||
await captureObsidianElement(port, "guide-hidden-file-advanced-features.png", (page) =>
|
||||
settingPanelByTitle(page, "Enable extra and advanced features")
|
||||
liveSyncSettingPanelByTitle(page, "Setup", "Enable extra and advanced features")
|
||||
),
|
||||
];
|
||||
|
||||
await withObsidianPage(port, async (page) => {
|
||||
await page
|
||||
.locator(".sls-setting")
|
||||
.locator('.sls-setting-menu-btn[title="Selector"]')
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
});
|
||||
screenshots.push(
|
||||
await captureObsidianElement(port, "guide-hidden-file-selector.png", (page) =>
|
||||
settingPanelByTitle(page, "Hidden Files")
|
||||
liveSyncSettingPanelByTitle(page, "Selector", "Hidden Files")
|
||||
)
|
||||
);
|
||||
|
||||
await withObsidianPage(port, async (page) => {
|
||||
await page
|
||||
.locator(".sls-setting")
|
||||
.locator('.sls-setting-menu-btn[title="Sync Settings"]')
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
});
|
||||
screenshots.push(
|
||||
await captureObsidianElement(port, "guide-hidden-file-enable.png", (page) =>
|
||||
settingPanelByTitle(page, "Hidden Files")
|
||||
liveSyncSettingPanelByTitle(page, "Sync Settings", "Hidden Files")
|
||||
)
|
||||
);
|
||||
|
||||
await withObsidianPage(port, async (page) => {
|
||||
await page.keyboard.press("Escape");
|
||||
const settingsNavigator = await openLiveSyncSettings(page, uiTimeoutMs);
|
||||
await settingsNavigator.close();
|
||||
});
|
||||
return screenshots;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user