-
-
Notifications
You must be signed in to change notification settings - Fork 764
Expand file tree
/
Copy patheditor.ts
More file actions
133 lines (121 loc) · 4 KB
/
Copy patheditor.ts
File metadata and controls
133 lines (121 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { expect, vi } from "vite-plus/test";
import type { Locator } from "vite-plus/test/browser/context";
import { userEvent } from "./context.js";
import { EDITOR_SELECTOR } from "./const.js";
/** Fixed pause for animations/debounces the editor relies on. */
export function sleep(ms: number) {
return new Promise<void>((resolve) => setTimeout(resolve, ms));
}
/** Resolves once `selector` is attached to the DOM, returning the element. */
export function waitForSelector(
selector: string,
options?: { timeout?: number },
): Promise<HTMLElement> {
return vi.waitFor(
() => {
const element = document.querySelector<HTMLElement>(selector);
if (!element) {
throw new Error(`Selector not found: ${selector}`);
}
return element;
},
{ timeout: options?.timeout ?? 5000 },
);
}
/** Resolves once `selector` is no longer in the DOM. */
export function waitForSelectorDetached(
selector: string,
options?: { timeout?: number },
): Promise<void> {
return vi.waitFor(
() => {
if (document.querySelector(selector)) {
throw new Error(`Selector still attached: ${selector}`);
}
},
{ timeout: options?.timeout ?? 5000 },
);
}
export async function focusOnEditor() {
const editor = await waitForSelector(EDITOR_SELECTOR);
await userEvent.click(editor);
}
export async function waitForSelectorInEditor(selector: string) {
await waitForSelector(`${EDITOR_SELECTOR} ${selector}`, { timeout: 1000 });
}
export async function waitForTextInEditor(text: string) {
await vi.waitFor(
() => {
const editor = document.querySelector(EDITOR_SELECTOR);
if (!editor || !editor.textContent?.includes(text)) {
throw new Error(`Text not found in editor: ${text}`);
}
},
{ timeout: 1000 },
);
}
/**
* Returns the editor's ProseMirror document as JSON. The test runs inside the
* browser, so we read the global the editor exposes directly (no
* `page.evaluate` round-trip needed).
*/
export function getDoc() {
return (window as any).ProseMirror.getJSON();
}
export function removeAttFromDoc(doc: any, att: string) {
if (typeof doc !== "object" || doc === null) {
return;
}
if (Object.keys(doc).includes(att)) {
delete doc[att];
}
Object.keys(doc).forEach((key) => removeAttFromDoc(doc[key], att));
return doc;
}
/**
* Asserts the editor document matches a stored JSON snapshot. The path is
* resolved relative to the running test file, so snapshots live in a
* `__snapshots__/` dir next to each test. Documents are browser-independent,
* so a single snapshot is shared across the chromium/firefox/webkit instances.
*/
export async function compareDocToSnapshot(name: string) {
const doc = JSON.stringify(getDoc(), null, 2);
await expect(doc).toMatchFileSnapshot(`./__snapshots__/${name}.json`);
}
// Vite Plus ships the browser matchers' `expect.element` augmentation against
// the bare `vitest` module, but its own `expect` is typed from an internal
// module, so the augmentation doesn't attach. Type the accessor locally.
type ElementMatchers = {
toMatchScreenshot(
name?: string,
options?: {
timeout?: number;
screenshotOptions?: {
mask?: ReadonlyArray<Element | Locator>;
maskColor?: string;
scale?: "css" | "device";
};
comparatorOptions?: {
threshold?: number;
allowedMismatchedPixels?: number;
allowedMismatchedPixelRatio?: number;
};
},
): Promise<void>;
toBeVisible(): Promise<void>;
not: { toBeVisible(): Promise<void> };
};
type ElementExpect = (
element: Element | null,
options?: { timeout?: number },
) => ElementMatchers;
export const expectElement = (expect as unknown as { element: ElementExpect })
.element;
/**
* Visual regression snapshot of the whole page (captures the editor plus any
* portalled menus/toolbars). Vitest names baselines per browser + platform
* automatically.
*/
export async function matchPageScreenshot(name: string) {
await expectElement(document.body).toMatchScreenshot(name);
}