mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-09-03 01:07:07 +00:00
202 lines
7.1 KiB
TypeScript
202 lines
7.1 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import type { Command } from "@/deps";
|
|
import {
|
|
REPLICATION_PROGRESS_PRESENTATIONS,
|
|
USER_INITIATED_REPLICATION_AUTHORITY,
|
|
} from "@vrtmrz/livesync-commonlib/replication";
|
|
import { ModuleBasicMenu } from "./ModuleBasicMenu";
|
|
|
|
type RegisteredCommand = Command & {
|
|
checkCallback?: (checking: boolean) => boolean | void;
|
|
};
|
|
|
|
function createFixture() {
|
|
const commands: RegisteredCommand[] = [];
|
|
const settings = {
|
|
liveSync: false,
|
|
useAdvancedMode: false,
|
|
enableDebugTools: false,
|
|
};
|
|
const services = {
|
|
API: {
|
|
addLog: vi.fn(),
|
|
addCommand: vi.fn((command: RegisteredCommand) => {
|
|
commands.push(command);
|
|
return command;
|
|
}),
|
|
registerWindow: vi.fn(),
|
|
addRibbonIcon: vi.fn(),
|
|
registerProtocolHandler: vi.fn(),
|
|
},
|
|
replication: {
|
|
replicateUserInitiated: vi.fn(async () => ({ status: "completed" as const })),
|
|
stopActiveTransfer: vi.fn(async () => ({ status: "completed" as const })),
|
|
},
|
|
vault: {
|
|
getActiveFilePath: vi.fn((): string | null => "note.md"),
|
|
scanVault: vi.fn(async () => undefined),
|
|
},
|
|
control: {
|
|
applySettings: vi.fn(async () => undefined),
|
|
},
|
|
setting: {
|
|
saveSettingData: vi.fn(async () => undefined),
|
|
},
|
|
appLifecycle: {
|
|
isSuspended: vi.fn(() => false),
|
|
setSuspended: vi.fn(),
|
|
},
|
|
fileProcessing: {
|
|
commitPendingFileEvents: vi.fn(async () => true),
|
|
},
|
|
UI: {
|
|
promptCopyToClipboard: vi.fn(async (_title: string, _value: string) => true),
|
|
},
|
|
path: {
|
|
path2id: vi.fn(async () => "f:note"),
|
|
},
|
|
};
|
|
const core = {
|
|
settings,
|
|
_services: services,
|
|
services,
|
|
localDatabase: {
|
|
getDBEntry: vi.fn(async () => false),
|
|
localDatabase: {
|
|
get: vi.fn(async () => ({
|
|
_id: "f:note",
|
|
_rev: "2-current",
|
|
_conflicts: [],
|
|
path: "note.md",
|
|
ctime: 100,
|
|
mtime: 200,
|
|
size: 12,
|
|
type: "plain",
|
|
children: ["h:private-chunk-id"],
|
|
eden: {},
|
|
})),
|
|
},
|
|
getDBEntryMeta: vi.fn(async () => ({
|
|
_id: "f:note",
|
|
_rev: "2-current",
|
|
_conflicts: [],
|
|
path: "note.md",
|
|
ctime: 100,
|
|
mtime: 200,
|
|
size: 12,
|
|
type: "plain",
|
|
datatype: "plain",
|
|
data: "",
|
|
children: ["h:private-chunk-id"],
|
|
eden: {},
|
|
})),
|
|
allDocsRaw: vi.fn(async () => ({
|
|
rows: [{ id: "h:private-chunk-id", key: "h:private-chunk-id", value: { rev: "1-chunk" } }],
|
|
})),
|
|
},
|
|
storageAccess: {
|
|
isExistsIncludeHidden: vi.fn(async () => true),
|
|
statHidden: vi.fn(async () => ({ ctime: 100, mtime: 200, size: 12, type: "file" })),
|
|
},
|
|
replicator: {
|
|
terminateSync: vi.fn(),
|
|
},
|
|
};
|
|
const module = new ModuleBasicMenu(core as never);
|
|
|
|
return {
|
|
commands,
|
|
core,
|
|
module,
|
|
services,
|
|
settings,
|
|
getCommand(id: string) {
|
|
const command = commands.find((candidate) => candidate.id === id);
|
|
expect(command, `command ${id}`).toBeDefined();
|
|
return command!;
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("ModuleBasicMenu command palette", () => {
|
|
it("uses clear user-facing names without changing the established command IDs", async () => {
|
|
const fixture = createFixture();
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
|
|
expect(fixture.getCommand("livesync-replicate").name).toBe("Sync now");
|
|
expect(fixture.getCommand("livesync-runbatch").name).toBe("Apply pending changes now");
|
|
});
|
|
|
|
it("keeps Sync now progress quiet while retaining failure-recovery authority", async () => {
|
|
const fixture = createFixture();
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
await fixture.getCommand("livesync-replicate").callback?.();
|
|
|
|
expect(fixture.services.replication.replicateUserInitiated).toHaveBeenCalledWith({
|
|
trigger: "manual",
|
|
progressPresentation: REPLICATION_PROGRESS_PRESENTATIONS.QUIET,
|
|
interaction: USER_INITIATED_REPLICATION_AUTHORITY,
|
|
});
|
|
});
|
|
|
|
it("keeps maintenance commands out of the normal palette", async () => {
|
|
const fixture = createFixture();
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
|
|
expect(fixture.getCommand("livesync-scan-files").checkCallback?.(true)).toBe(false);
|
|
expect(fixture.getCommand("livesync-abortsync").checkCallback?.(true)).toBe(false);
|
|
|
|
fixture.settings.useAdvancedMode = true;
|
|
expect(fixture.getCommand("livesync-scan-files").checkCallback?.(true)).toBe(true);
|
|
expect(fixture.getCommand("livesync-abortsync").checkCallback?.(true)).toBe(true);
|
|
});
|
|
|
|
it("routes an explicit stop through the active provider capability", async () => {
|
|
const fixture = createFixture();
|
|
fixture.settings.useAdvancedMode = true;
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
|
|
expect(fixture.getCommand("livesync-abortsync").checkCallback?.(false)).toBe(true);
|
|
await vi.waitFor(() => {
|
|
expect(fixture.services.replication.stopActiveTransfer).toHaveBeenCalledOnce();
|
|
});
|
|
expect(fixture.core.replicator.terminateSync).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("keeps active-file database information available and opens it in a copy dialogue", async () => {
|
|
const fixture = createFixture();
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
|
|
const command = fixture.getCommand("livesync-dump");
|
|
expect(command.name).toBe("Copy database information for the active file");
|
|
expect(command.checkCallback?.(true)).toBe(true);
|
|
|
|
command.checkCallback?.(false);
|
|
|
|
await vi.waitFor(() => {
|
|
expect(fixture.services.UI.promptCopyToClipboard).toHaveBeenCalledOnce();
|
|
});
|
|
const [title, report] = fixture.services.UI.promptCopyToClipboard.mock.calls[0];
|
|
expect(title).toBe("Database information for note.md");
|
|
expect(report).toContain("note.md");
|
|
expect(report).toContain("2-current");
|
|
expect(report).toContain("h:private-chunk-id");
|
|
expect(report).toContain("1-chunk");
|
|
expect(fixture.core.localDatabase.getDBEntry).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("hides the active-file database report when no file is active", async () => {
|
|
const fixture = createFixture();
|
|
fixture.services.vault.getActiveFilePath.mockReturnValue(null);
|
|
|
|
await fixture.module._everyOnloadStart();
|
|
|
|
expect(fixture.getCommand("livesync-dump").checkCallback?.(true)).toBe(false);
|
|
});
|
|
});
|