Migrate LiveSync flows to provider-owned resources

This commit is contained in:
vorotamoroz committed 2026-08-28 17:54:04 +00:00
1 parent f7206b1a6e
commit db70b4c2b6
34 files changed
+1830 -365

No files matched your search

@@ -1,9 +1,7 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_SETTINGS, REMOTE_COUCHDB } from "@vrtmrz/livesync-commonlib/compat/common/types";
import { REMOTE_RESOURCE_KINDS } from "@vrtmrz/livesync-commonlib/replication";
const negotiationMocks = vi.hoisted(() => ({
checkSyncInfo: vi.fn(async () => true),
}));
const settingsInitialisationMocks = vi.hoisted(() => ({
applySettingsWithInitialisationChoice: vi.fn(),
}));
@@ -38,10 +36,6 @@ vi.mock("@/common/events.ts", () => ({
eventHub: { emitEvent: vi.fn(), onEvent: vi.fn() },
}));
vi.mock("@/modules/features/SetupManager.ts", () => ({ SetupManager: class {} }));
vi.mock("@vrtmrz/livesync-commonlib/compat/pouchdb/negotiation", () => negotiationMocks);
vi.mock("@vrtmrz/livesync-commonlib/compat/replication/couchdb/LiveSyncReplicator", () => ({
LiveSyncCouchDBReplicator: class {},
}));
vi.mock("./LiveSyncSetting.ts", () => ({ LiveSyncSetting: class {} }));
vi.mock("./SettingPane.ts", () => ({
enableOnly: vi.fn(() => vi.fn()),
@@ -63,7 +57,6 @@ vi.mock("./PanePowerUsers.ts", () => ({ panePowerUsers: vi.fn() }));
vi.mock("./PanePatches.ts", () => ({ panePatches: vi.fn() }));
vi.mock("./PaneMaintenance.ts", () => ({ paneMaintenance: vi.fn() }));
import { LiveSyncCouchDBReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/couchdb/LiveSyncReplicator";
import { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab";
beforeEach(() => {
@@ -71,19 +64,15 @@ beforeEach(() => {
});
describe("ObsidianLiveSyncSettingTab passphrase verification", () => {
it("closes the finite remote connection after checking synchronisation information", async () => {
const remoteDatabase = {
close: vi.fn(async () => undefined),
};
const replicator = Object.assign(new LiveSyncCouchDBReplicator({} as never), {
connectRemoteCouchDBWithSetting: vi.fn(async () => ({ db: remoteDatabase })),
});
it("awaits and disposes the owned synchronisation-information resource", async () => {
const check = vi.fn(async () => true);
const dispose = vi.fn(async () => undefined);
const createRemoteResource = vi.fn(async () => ({ check, dispose }));
const plugin = {
app: {},
core: {
services: {
API: { isMobile: vi.fn(() => false) },
replicator: { getNewReplicator: vi.fn(() => replicator) },
replicator: { createRemoteResource },
},
},
};
@@ -97,8 +86,76 @@ describe("ObsidianLiveSyncSettingTab passphrase verification", () => {
await expect(tab.checkWorkingPassphrase()).resolves.toBe(true);
expect(negotiationMocks.checkSyncInfo).toHaveBeenCalledWith(remoteDatabase);
expect(remoteDatabase.close).toHaveBeenCalledOnce();
expect(createRemoteResource).toHaveBeenCalledWith(
REMOTE_RESOURCE_KINDS.SYNCHRONISATION_INFORMATION,
expect.objectContaining({ remoteType: REMOTE_COUCHDB })
);
expect(check).toHaveBeenCalledOnce();
expect(dispose).toHaveBeenCalledOnce();
});
it("does not use the general Replicator factory solely to verify synchronisation information", async () => {
const getNewReplicator = vi.fn(() => Promise.reject(new Error("must not construct a Replicator")));
const createRemoteResource = vi.fn(async () => ({
check: vi.fn(async () => true),
dispose: vi.fn(async () => undefined),
}));
const plugin = {
app: {},
core: {
services: {
replicator: { createRemoteResource, getNewReplicator },
},
},
};
const tab = new ObsidianLiveSyncSettingTab({} as never, plugin as never);
Object.assign(tab, {
_editingSettings: {
...DEFAULT_SETTINGS,
remoteType: REMOTE_COUCHDB,
},
});
await expect(tab.checkWorkingPassphrase()).resolves.toBe(true);
expect(getNewReplicator).not.toHaveBeenCalled();
});
});
describe("ObsidianLiveSyncSettingTab connection testing", () => {
it("uses and disposes the flow-specific connection probe without borrowing a Replicator", async () => {
const check = vi.fn(async () => ({ ok: true as const }));
const getStatus = vi.fn(async () => ({ estimatedSize: 1024 }));
const dispose = vi.fn(async () => undefined);
const createRemoteResource = vi.fn(async () => ({ check, getStatus, dispose }));
const getNewReplicator = vi.fn(() => Promise.reject(new Error("must not borrow a Replicator")));
const plugin = {
app: {},
core: {
services: {
replicator: { createRemoteResource, getNewReplicator },
},
},
};
const tab = new ObsidianLiveSyncSettingTab({} as never, plugin as never);
Object.assign(tab, {
_editingSettings: {
...DEFAULT_SETTINGS,
remoteType: REMOTE_COUCHDB,
couchDB_DBNAME: "saved",
},
});
await expect(tab.testConnection({ couchDB_DBNAME: "trial" })).resolves.toBeUndefined();
expect(createRemoteResource).toHaveBeenCalledWith(
REMOTE_RESOURCE_KINDS.CONNECTION,
expect.objectContaining({ remoteType: REMOTE_COUCHDB, couchDB_DBNAME: "trial" })
);
expect(check).toHaveBeenCalledWith({ createIfMissing: true, showResult: true });
expect(getStatus).toHaveBeenCalledOnce();
expect(dispose).toHaveBeenCalledOnce();
expect(getNewReplicator).not.toHaveBeenCalled();
});
});