mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-27 15:02:59 +00:00
86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { POSTPONED, ConflictResolveModal } from "./ConflictResolveModal.ts";
|
|
import { CANCELLED, type diff_result, type FilePathWithPrefix } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
|
|
|
vi.mock("@/deps.ts", () => ({
|
|
App: class App {},
|
|
Modal: class Modal {
|
|
private createElement(): Record<string, unknown> {
|
|
const element: Record<string, unknown> = {
|
|
addClass: vi.fn(),
|
|
addEventListener: vi.fn(),
|
|
appendText: vi.fn(),
|
|
classList: {
|
|
add: vi.fn(),
|
|
remove: vi.fn(),
|
|
},
|
|
empty: vi.fn(),
|
|
querySelector: vi.fn(() => null),
|
|
querySelectorAll: vi.fn(() => []),
|
|
scrollIntoView: vi.fn(),
|
|
setText: vi.fn(),
|
|
};
|
|
element.createDiv = vi.fn(() => this.createElement());
|
|
element.createEl = vi.fn((_tag: string, _options?: unknown, callback?: (child: unknown) => void) => {
|
|
const child = this.createElement();
|
|
callback?.(child);
|
|
return child;
|
|
});
|
|
element.createSpan = vi.fn(() => this.createElement());
|
|
return element;
|
|
}
|
|
|
|
contentEl = this.createElement();
|
|
titleEl = {
|
|
setText: vi.fn(),
|
|
};
|
|
|
|
close() {
|
|
(this as { onClose?: () => void }).onClose?.();
|
|
}
|
|
},
|
|
}));
|
|
|
|
const conflict: diff_result = {
|
|
left: { rev: "2-left", data: "left", ctime: 1, mtime: 2 },
|
|
right: { rev: "2-right", data: "right", ctime: 1, mtime: 2 },
|
|
diff: [],
|
|
};
|
|
|
|
describe("ConflictResolveModal result lifecycle", () => {
|
|
it("returns a response which closes the dialogue before the caller begins waiting", async () => {
|
|
const modal = new ConflictResolveModal({} as never, "early-response.md" as FilePathWithPrefix, conflict);
|
|
|
|
modal.sendResponse(POSTPONED);
|
|
const result = await Promise.race([
|
|
modal.waitForResult(),
|
|
new Promise<"timed-out">((resolve) => setTimeout(() => resolve("timed-out"), 250)),
|
|
]);
|
|
|
|
expect(result).toBe(POSTPONED);
|
|
});
|
|
|
|
it("cancels the previous same-path dialogue without cancelling the replacement", async () => {
|
|
const filename = "same-path.md" as FilePathWithPrefix;
|
|
const previous = new ConflictResolveModal({} as never, filename, conflict);
|
|
const replacement = new ConflictResolveModal({} as never, filename, conflict);
|
|
previous.onOpen();
|
|
|
|
replacement.onOpen();
|
|
const previousResult = await Promise.race([
|
|
previous.waitForResult(),
|
|
new Promise<"timed-out">((resolve) => setTimeout(() => resolve("timed-out"), 250)),
|
|
]);
|
|
const replacementState = await Promise.race([
|
|
replacement.waitForResult(),
|
|
new Promise<"still-open">((resolve) => setTimeout(() => resolve("still-open"), 25)),
|
|
]);
|
|
|
|
previous.sendResponse(CANCELLED);
|
|
replacement.sendResponse(CANCELLED);
|
|
|
|
expect(previousResult).toBe(CANCELLED);
|
|
expect(replacementState).toBe("still-open");
|
|
});
|
|
});
|