Skip to content

Commit e73b6bd

Browse files
koki-developclaude
andcommitted
test: add MarkdownEditor table specs covering round-trip, shortcut, keyboard, and cell-guard
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8209b8e commit e73b6bd

5 files changed

Lines changed: 2468 additions & 7 deletions

File tree

src/components/molecules/MarkdownEditor/AGENTS.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ These are cross-cutting trade-offs that are not localized in any single file. Th
5757

5858
Specs live next to their target as `*.spec.ts` / `*.spec.tsx`. Shared helpers in `__tests__/utils.tsx` — go through them so every test starts from the production-shaped editor.
5959

60-
| Shape | Example | When to use |
61-
| -------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62-
| Pure `$`-helper | `codeBlock.spec.ts` | Pure structural / tree-walk helpers. Wrap with `createTestHeadlessEditor()` — no React, no DOM mount. |
63-
| Transformer round-trip | `transformers.spec.ts`, `transformers.quote.spec.ts` | Import/export through `MARKDOWN_TRANSFORMERS`. `$setMarkdown` + `$readMarkdown` on a headless editor. |
64-
| Plugin keyboard contract | `QuoteExitPlugin.spec.tsx` | A plugin gated on a key press. `renderTestEditor({plugins: <YourPlugin />})` + `dispatchKeyDown(editor, "Backspace")`. The helper wraps the dispatch in a discrete `editor.update` so the listener's mutations commit synchronously (default dispatch defers to a microtask). |
65-
| Live-typing → rendered DOM | `markdownShortcuts.spec.tsx` | "Type chars → DOM mutates" (shortcuts, converters). `renderTestEditor` with the plugin and its transformer set, then `await user.click(textbox); await user.keyboard(...)`. Use real `userEvent` from `vitest/browser` (CDP events — composition / `beforeinput` / selection behave like a real keystroke). |
66-
| Mount-time initial value | `MarkdownEditor.spec.tsx` | "Open an existing task body" path. `renderTestEditor({initialValue: "..."})` runs the production `buildInitialConfig` initializer end-to-end. |
60+
| Shape | Example | When to use |
61+
| -------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62+
| Pure `$`-helper | `codeBlock.spec.ts` | Pure structural / tree-walk helpers. Wrap with `createTestHeadlessEditor()` — no React, no DOM mount. |
63+
| Transformer round-trip | `transformers.spec.ts`, `transformers.quote.spec.ts`, `transformers.table.spec.ts` | Import/export through `MARKDOWN_TRANSFORMERS`. `$setMarkdown` + `$readMarkdown` on a headless editor. |
64+
| Plugin keyboard contract | `QuoteExitPlugin.spec.tsx`, `TableKeyboardPlugin.spec.tsx` | A plugin gated on a key press. `renderTestEditor({plugins: <YourPlugin />})` + `dispatchKeyDown(editor, "Backspace")`. The helper wraps the dispatch in a discrete `editor.update` so the listener's mutations commit synchronously (default dispatch defers to a microtask). Pair with `<TablePlugin>` when the plugin under test depends on TableNode behaviors. |
65+
| Live-typing → rendered DOM | `markdownShortcuts.spec.tsx`, `tableShortcuts.spec.tsx` | "Type chars → DOM mutates" (shortcuts, converters). `renderTestEditor` with the plugin and its transformer set, then `await user.click(textbox); await user.keyboard(...)`. Use real `userEvent` from `vitest/browser` (CDP events — composition / `beforeinput` / selection behave like a real keystroke). The MarkdownShortcutPlugin only fires its element transformers when the LAST char typed is a space (or on Enter via `triggerOnEnter: true`); the trigger char shape determines which commit branch runs (e.g. TABLE's `$seedHeaderColumn` vs `$seedBodyRow`). |
66+
| Node-transform safety net | `NoListInTablePlugin.spec.tsx` | A plugin whose contract is "if a node lands here in a forbidden shape, rewrite it" (no key press, no typing). Programmatically build the forbidden shape inside `editor.update({discrete: true})`; the plugin's `registerNodeTransform` callback fires on commit and Lexical re-fires until no dirty matching nodes remain — assert the post-transform shape directly. |
67+
| Mount-time initial value | `MarkdownEditor.spec.tsx` | "Open an existing task body" path. `renderTestEditor({initialValue: "..."})` runs the production `buildInitialConfig` initializer end-to-end. |
6768

6869
**Assert against the structural triple**`editorRoot.children` length + `firstElementChild.tagName` + `firstElementChild.textContent` — rather than `toBeInTheDocument()` / `toBeVisible()` alone. The matchers pass even when an extra paragraph renders alongside the expected one; the triple pins the rendered shape exactly without freezing theme classes or Lexical-internal attributes (`dir`, `data-lexical-text`, ...) that an `innerHTML` snapshot would lock down.
6970

0 commit comments

Comments
 (0)