mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-09-13 06:07:05 +00:00
Merge latest main into conflict resolution refactor
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { mkdir } from "node:fs/promises";
|
||||
import { assertLocatorWithinViewport, assertNoHorizontalOverflow } from "@vrtmrz/obsidian-test-session";
|
||||
import { VER } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { discoverObsidianCli, requireObsidianBinary } from "../runner/environment.ts";
|
||||
import { createE2eObsidianDeviceLocalState, waitForLiveSyncCoreReady } from "../runner/liveSyncWorkflow.ts";
|
||||
@@ -597,26 +598,42 @@ async function verifyCompatibilityReview(): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
async function verifyConfigDoctorFollowsCompatibilityReview(): Promise<void> {
|
||||
async function verifyConfigDoctorFollowsCompatibilityReview(): Promise<string> {
|
||||
const screenshot = await captureObsidianDialogue(
|
||||
obsidianRemoteDebuggingPort(),
|
||||
"config-doctor-after-compatibility-review.png",
|
||||
async (page) => {
|
||||
const doctor = page.locator(".modal-container").filter({
|
||||
has: page.locator(".modal-title").filter({ hasText: "Self-hosted LiveSync Config Doctor" }),
|
||||
});
|
||||
await doctor.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await doctor.getByText("Per-file-saved customization sync", { exact: true }).waitFor({
|
||||
state: "visible",
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
await doctor.getByText("Enhance chunk size", { exact: true }).waitFor({
|
||||
state: "visible",
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
if ((await doctor.getByText("Data Compression", { exact: true }).count()) !== 0) {
|
||||
throw new Error("Config Doctor still treats supported Data Compression as a problem.");
|
||||
}
|
||||
await assertLocatorWithinViewport(page, doctor.locator(".modal").last(), {
|
||||
label: "Config Doctor dialogue",
|
||||
});
|
||||
await assertNoHorizontalOverflow(page, doctor.locator(".modal").last(), {
|
||||
label: "Config Doctor dialogue",
|
||||
});
|
||||
}
|
||||
);
|
||||
await withObsidianPage(obsidianRemoteDebuggingPort(), async (page) => {
|
||||
const doctor = page.locator(".modal-container").filter({
|
||||
has: page.locator(".modal-title").filter({ hasText: "Self-hosted LiveSync Config Doctor" }),
|
||||
});
|
||||
await doctor.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await doctor.getByText("Per-file-saved customization sync", { exact: true }).waitFor({
|
||||
state: "visible",
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
await doctor.getByText("Enhance chunk size", { exact: true }).waitFor({
|
||||
state: "visible",
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
if ((await doctor.getByText("Data Compression", { exact: true }).count()) !== 0) {
|
||||
throw new Error("Config Doctor still treats supported Data Compression as a problem.");
|
||||
}
|
||||
await doctor.getByRole("button", { name: /No, and do not ask again/u }).click();
|
||||
await doctor.waitFor({ state: "hidden", timeout: uiTimeoutMs });
|
||||
});
|
||||
return screenshot;
|
||||
}
|
||||
|
||||
async function verifyEffectiveSettings(): Promise<"declarative" | "imperative"> {
|
||||
@@ -1051,7 +1068,8 @@ async function main(): Promise<void> {
|
||||
await resumePendingCompatibilityReviewForSettings();
|
||||
} else {
|
||||
await verifyCompatibilityReview();
|
||||
await verifyConfigDoctorFollowsCompatibilityReview();
|
||||
const configDoctorScreenshot = await verifyConfigDoctorFollowsCompatibilityReview();
|
||||
console.log(`Config Doctor screenshot: ${configDoctorScreenshot}`);
|
||||
}
|
||||
settingsRenderer = await verifyEffectiveSettings();
|
||||
const initialisation = await verifyPendingSettingsInitialisationFlow();
|
||||
|
||||
@@ -4,8 +4,48 @@ import {
|
||||
inspectObsidianServiceContextContract,
|
||||
} from "../runner/liveSyncWorkflow.ts";
|
||||
import { startObsidianLiveSyncSession, type ObsidianLiveSyncSession } from "../runner/session.ts";
|
||||
import { withObsidianPage } from "../runner/ui.ts";
|
||||
import { createTemporaryVault } from "../runner/vault.ts";
|
||||
|
||||
const BASIC_COMMAND_IDS = [
|
||||
"livesync-replicate",
|
||||
"livesync-dump",
|
||||
"livesync-toggle",
|
||||
"livesync-suspendall",
|
||||
"livesync-scan-files",
|
||||
"livesync-runbatch",
|
||||
"livesync-abortsync",
|
||||
] as const;
|
||||
|
||||
type ObsidianCommandHost = typeof globalThis & {
|
||||
app?: { commands?: { commands?: Record<string, unknown> } };
|
||||
};
|
||||
|
||||
async function assertMenuFeaturesAreComposed(remoteDebuggingPort: number): Promise<void> {
|
||||
await withObsidianPage(remoteDebuggingPort, async (page) => {
|
||||
const registered = await page.evaluate((commandIds) => {
|
||||
const commands = (globalThis as ObsidianCommandHost).app?.commands?.commands ?? {};
|
||||
return commandIds.filter((id) => commands[`obsidian-livesync:${id}`] !== undefined);
|
||||
}, BASIC_COMMAND_IDS);
|
||||
if (registered.length !== BASIC_COMMAND_IDS.length) {
|
||||
const missing = BASIC_COMMAND_IDS.filter((id) => !registered.includes(id));
|
||||
throw new Error(`Extracted basic commands were not composed: ${missing.join(", ")}`);
|
||||
}
|
||||
|
||||
const ribbonCount = await page.locator(".livesync-ribbon-replicate").count();
|
||||
if (ribbonCount !== 1) {
|
||||
throw new Error(`Expected one extracted replication ribbon action, found ${ribbonCount}.`);
|
||||
}
|
||||
|
||||
const preservedRibbonPathCount = await page
|
||||
.locator('.livesync-ribbon-replicate path[d*="c-7.66 1.98-12.2 9.61-10 17"]')
|
||||
.count();
|
||||
if (preservedRibbonPathCount !== 1) {
|
||||
throw new Error("The extracted replication ribbon does not preserve its established icon path.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const binary = requireObsidianBinary();
|
||||
const cli = discoverObsidianCli();
|
||||
@@ -34,6 +74,8 @@ async function main(): Promise<void> {
|
||||
console.log(
|
||||
`Obsidian service Context contract passed: ${contextContract.contextType}, ${contextContract.serviceContextMismatches.length} mismatches.`
|
||||
);
|
||||
await assertMenuFeaturesAreComposed(session.remoteDebuggingPort);
|
||||
console.log("Extracted basic commands and replication ribbon were composed exactly once.");
|
||||
await new Promise((resolve) => setTimeout(resolve, Number(process.env.E2E_OBSIDIAN_SMOKE_TIMEOUT_MS ?? 1000)));
|
||||
console.log("Obsidian stayed alive after the plug-in readiness check.");
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user