mirror of
https://github.com/priyanshujain/margin-docs.git
synced 2026-10-02 11:07:05 +00:00
features
This commit is contained in:
commit
852cba1840
252 files changed
+55050
No files matched your search
+144
@@ -0,0 +1,144 @@
|
||||
// The fixture behind the app, reachable from a test.
|
||||
//
|
||||
// Two specs need it now, so it lives here rather than in one of them: tests/external-changes.spec.ts
|
||||
// drives the watcher over this wire, and tests/bytes.spec.ts reads what the autosave actually put on
|
||||
// disk. Both of them are claims about the file, and a claim about the file needs the file.
|
||||
//
|
||||
// This is a shim, not a mock of the app: what is behind it is src/dev/mockIpc.ts, the same fixture
|
||||
// `pnpm dev` runs against, so a test here exercises every branch the packaged binary takes.
|
||||
|
||||
import { type Page } from "@playwright/test";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__disk: {
|
||||
/**
|
||||
* Changes the folder from outside the app and puts the resulting `watch-event`s on the bus.
|
||||
* Returns, per event, how many listeners actually received it, so a test can tell a working
|
||||
* subscription apart from a payload that fell on the floor.
|
||||
*/
|
||||
change(name: string, args: unknown[]): Promise<number[]>;
|
||||
/** Asks the fixture something. Changes nothing and emits nothing. */
|
||||
ask(name: string, args: unknown[]): Promise<unknown>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enough of Tauri's JavaScript side for the real `@tauri-apps/api` to run against: an `invoke` that
|
||||
* answers commands, the synchronous callback registry `transformCallback` needs, and the event
|
||||
* plugin's listen and unlisten. Deliberately not `@tauri-apps/api/mocks`, which cannot be reached
|
||||
* from an init script, and deliberately hand-rolled to the same contract rather than to a
|
||||
* convenient one.
|
||||
*
|
||||
* Runs at document start on every navigation, before any module of the app is evaluated, which is
|
||||
* what matters: `isTauri` in src/ipc.ts is computed once at import time.
|
||||
*/
|
||||
export function installTauriShim(): void {
|
||||
interface Backend {
|
||||
mockCall(command: string, args?: Record<string, unknown>): Promise<unknown>;
|
||||
external: Record<string, (...args: unknown[]) => unknown>;
|
||||
}
|
||||
|
||||
const listeners = new Map<string, Set<number>>();
|
||||
const callbacks = new Map<number, (data: unknown) => void>();
|
||||
let nextId = 1;
|
||||
|
||||
const registerCallback = (fn?: (data: unknown) => void, once = false): number => {
|
||||
const id = nextId;
|
||||
nextId += 1;
|
||||
callbacks.set(id, (data) => {
|
||||
if (once) callbacks.delete(id);
|
||||
fn?.(data);
|
||||
});
|
||||
return id;
|
||||
};
|
||||
|
||||
const unregisterCallback = (id: number): void => {
|
||||
callbacks.delete(id);
|
||||
};
|
||||
|
||||
const forget = (event: string, id: number): void => {
|
||||
listeners.get(event)?.delete(id);
|
||||
unregisterCallback(id);
|
||||
};
|
||||
|
||||
const emit = (event: string, payload: unknown): number => {
|
||||
let delivered = 0;
|
||||
for (const id of [...(listeners.get(event) ?? [])]) {
|
||||
const fn = callbacks.get(id);
|
||||
if (!fn) continue;
|
||||
fn({ event, id, payload });
|
||||
delivered += 1;
|
||||
}
|
||||
return delivered;
|
||||
};
|
||||
|
||||
// A variable specifier so this stays a runtime import of a Vite-served source file rather than
|
||||
// something the test's own compiler tries to resolve.
|
||||
const specifier = "/src/dev/mockIpc.ts";
|
||||
let loading: Promise<Backend> | null = null;
|
||||
const backend = (): Promise<Backend> => (loading ??= import(specifier) as Promise<Backend>);
|
||||
|
||||
const invoke = async (command: string, args?: Record<string, unknown>): Promise<unknown> => {
|
||||
const a = (args ?? {}) as Record<string, unknown>;
|
||||
if (command === "plugin:event|listen") {
|
||||
const event = a.event as string;
|
||||
const handler = a.handler as number;
|
||||
const set = listeners.get(event) ?? new Set<number>();
|
||||
set.add(handler);
|
||||
listeners.set(event, set);
|
||||
return handler;
|
||||
}
|
||||
if (command === "plugin:event|unlisten") {
|
||||
forget(a.event as string, a.eventId as number);
|
||||
return null;
|
||||
}
|
||||
// The window, dialog and opener commands have nothing to act on in a browser tab, and nothing
|
||||
// in this suite emits from the frontend. Answering rather than throwing keeps the app's own
|
||||
// startup (the close-requested handler, chiefly) from filling the console with rejections.
|
||||
if (command.startsWith("plugin:") || command.startsWith("core:")) return null;
|
||||
return (await backend()).mockCall(command, args);
|
||||
};
|
||||
|
||||
const internals = {
|
||||
invoke,
|
||||
transformCallback: registerCallback,
|
||||
unregisterCallback,
|
||||
runCallback: (id: number, data: unknown) => callbacks.get(id)?.(data),
|
||||
callbacks,
|
||||
metadata: {
|
||||
currentWindow: { label: "main" },
|
||||
currentWebview: { windowLabel: "main", label: "main" },
|
||||
},
|
||||
convertFileSrc: (path: string) => path,
|
||||
plugins: {},
|
||||
};
|
||||
|
||||
const global = window as unknown as Record<string, unknown>;
|
||||
global.__TAURI_INTERNALS__ = internals;
|
||||
global.__TAURI_EVENT_PLUGIN_INTERNALS__ = { unregisterListener: forget };
|
||||
|
||||
window.__disk = {
|
||||
async change(name, args) {
|
||||
const events = (await backend()).external[name](...args) as unknown[];
|
||||
// The literal, not the constant: this is one of the two ends being tied together.
|
||||
return events.map((event) => emit("watch-event", event));
|
||||
},
|
||||
async ask(name, args) {
|
||||
const answer = (await backend()).external[name](...args);
|
||||
return answer === undefined ? null : answer;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function change(page: Page, name: string, ...args: unknown[]): Promise<number[]> {
|
||||
return page.evaluate((call) => window.__disk.change(call.name, call.args), { name, args });
|
||||
}
|
||||
|
||||
export function ask<T>(page: Page, name: string, ...args: unknown[]): Promise<T> {
|
||||
return page.evaluate((call) => window.__disk.ask(call.name, call.args), {
|
||||
name,
|
||||
args,
|
||||
}) as Promise<T>;
|
||||
}
|
||||
Reference in new issue
Block a user