Skip to content

Commit 1212ab3

Browse files
committed
test(notes): pin the read-only lock to the real editor
The teleprompter suite stubs @tiptap/react wholesale, so its read-only assertions pin the props handed to Tiptap rather than what Tiptap does with them. useEditor honours `editable` at creation and then pins every later option pass to the editor own isEditable, which leaves setEditable as the single path carrying a mirror toggle. Losing it - to a refactor or a Tiptap upgrade - would leave every mocked assertion green with a mirrored note still editable, the exact bug this branch fixes. NotesWindow.editable.test.tsx drives the real editor through a mirror toggle and reads contenteditable back off the DOM; removing the setEditable effect fails it. The constructor option stays pinned at the mocked boundary, since React flushes the effect before a test can observe the first paint - the comment there now says so rather than claiming the mock proves creation-time behaviour. Also stop the playback-label test from rendering isPlaying with formatting still enabled, a state NotesWindow cannot produce.
1 parent 54ba303 commit 1212ab3

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

src/components/launch/NotesToolbar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ describe("NotesToolbar teleprompter controls", () => {
147147

148148
rerender(
149149
<I18nProvider>
150-
<NotesToolbar {...createProps({ isPlaying: true })} />
150+
<NotesToolbar {...createProps({ isPlaying: true, formattingDisabled: true })} />
151151
</I18nProvider>,
152152
);
153153
expect(screen.getByRole("button", { name: "Pause auto-scroll" })).not.toHaveAttribute(
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import "@testing-library/jest-dom";
2+
import { render, screen } from "@testing-library/react";
3+
import userEvent from "@testing-library/user-event";
4+
import { beforeEach, describe, expect, it, vi } from "vitest";
5+
import { I18nProvider } from "@/contexts/I18nContext";
6+
import { NotesWindow } from "./NotesWindow";
7+
8+
// The sibling suite stubs `@tiptap/react`, so nothing in it can show that the real note ever
9+
// stops accepting edits. `useEditor` honours `editable` only when it CREATES the editor and
10+
// pins every later option pass to the editor's own `isEditable`, which makes `setEditable` the
11+
// one path that carries a mirror toggle — and losing it, to a refactor or a Tiptap upgrade,
12+
// leaves every mocked assertion green. So this one drives the real editor and reads
13+
// `contenteditable` back off the DOM. (The constructor option stays pinned at the mocked
14+
// boundary: React flushes the effect before a test can observe the first paint.)
15+
vi.mock("@/components/ui/tooltip", () => ({
16+
Tooltip: ({ children }: { children: React.ReactNode }) => children,
17+
}));
18+
19+
beforeEach(() => {
20+
localStorage.clear();
21+
});
22+
23+
function noteBody(): HTMLElement {
24+
const body = document.querySelector<HTMLElement>(".tiptap");
25+
if (!body) {
26+
throw new Error("the editor never mounted");
27+
}
28+
29+
return body;
30+
}
31+
32+
describe("NotesWindow read-only wiring against the real editor", () => {
33+
it("stops and resumes accepting edits with the mirror", async () => {
34+
const user = userEvent.setup();
35+
render(
36+
<I18nProvider>
37+
<NotesWindow />
38+
</I18nProvider>,
39+
);
40+
const mirror = screen.getByRole("button", { name: "Mirror horizontally" });
41+
42+
expect(noteBody()).toHaveAttribute("contenteditable", "true");
43+
44+
await user.click(mirror);
45+
expect(noteBody()).toHaveAttribute("contenteditable", "false");
46+
47+
await user.click(mirror);
48+
expect(noteBody()).toHaveAttribute("contenteditable", "true");
49+
});
50+
});

src/components/launch/NotesWindow.test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,10 @@ describe("NotesWindow teleprompter mode", () => {
312312
);
313313
render(<NotesWindow />);
314314

315-
// The editor must be CREATED read-only — an effect-only lock would leave the first
316-
// painted frame editable.
315+
// `useEditor` is stubbed here, so this pins the option we hand Tiptap rather than what
316+
// Tiptap does with it: the editor must be CREATED read-only, because an effect-only lock
317+
// would leave the first painted frame editable. That the real editor honours it — and
318+
// keeps honouring the effect afterwards — is covered in NotesWindow.editable.test.tsx.
317319
expect(tiptapState.options?.editable).toBe(false);
318320
expect(setEditable).toHaveBeenLastCalledWith(false, false);
319321
expect(setEditable).not.toHaveBeenCalledWith(true, false);

0 commit comments

Comments
 (0)