Vim Clipboard Sync — Manual Regression Checklist
Caution
This checklist covers the regression test for epic #2043 (Vim Clipboard Sync Fix).
Background
tauri- is now host-aware:
Tauri host (installed
.app): clipboard I/O routes through@tauri-apps/plugin-clipboard-manager(Rust → NSPasteboard). This is the plugin leg.Browser /
dev:mock: clipboard I/O routes throughnavigator.clipboard. This is the fallback leg.
Installed Tauri builds refresh from the clipboard on Tauri's native window-focus event, with a low-frequency native-plugin polling backstop for macOS activation paths that do not deliver a focus event. Browser builds use the DOM window focus event and never poll the clipboard. Editor focusin only re-asserts the Vim register binding and performs no clipboard read, because a WebKit clipboard read on editor focus can open macOS's native Paste-permission menu.
An automated e2e spec (e2e/) exercises the fallback leg. The plugin leg requires a human verifier with a freshly installed text app.
Part A — Plugin leg (installed .app)
Run these steps against a freshly installed text app built from the fixed source (post-#2046).
A1 — Yank → external paste
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | Open a generated text app (e.g. modmsg.app). Vim mode must be enabled in Settings → Editor. | App opens normally. | |
| 2 | Click the editor, press i, type hello plugin leg, press Escape. | Text is visible in the editor. | |
| 3 | Press gg to jump to line 1, then press yy to yank the line. | No visible error; cursor stays on line 1. | |
| 4 | Switch to another app (e.g. TextEdit or Notes). | App switch completes. | |
| 5 | Press Cmd+V to paste. | The yanked text hello plugin leg appears. |
A2 — External copy → vim paste
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | In an external app (TextEdit, Notes, etc.), type or select external content. Copy it with Cmd+C. | Clipboard holds external content. Confirm via pbpaste in Terminal if needed. | |
| 2 | Switch back to the text app. | Window regains focus. (The focus event triggers clipboard sync into the vim register.) | |
| 3 | In the editor in vim normal mode, press p to paste. | external content appears in the editor. |
Verifier note: run pbpaste in Terminal after each yank step and record the raw output in the PR/issue comment to confirm NSPasteboard received the text.
Part B — Fallback leg (dev:mock browser)
Run these steps against pnpm dev:mock (port 1421, no Tauri host — navigator.clipboard path).
The automated e2e spec (
e2e/) covers the same flow under WebKit headless where clipboard permissions allow it. These manual steps complement the spec for environments where headless clipboard access is blocked.vim- clipboard- sync. spec. ts
B1 — Yank → external paste (browser fallback)
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | Run pnpm dev:mock and open http: in a browser. | App loads. | |
| 2 | Click the editor, press i, type hello fallback leg, press Escape. | Text visible in editor. | |
| 3 | Press gg then yy. | No error. | |
| 4 | Open the browser DevTools console and run: await navigator.clipboard.readText(). | Returns hello fallback leg. |
B2 — External copy → vim paste (browser fallback)
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | In the browser DevTools console, run: await navigator.clipboard.writeText('external fallback'). | No error. | |
| 2 | Click back to the editor. In vim normal mode, press p. | external fallback appears in the editor. (Note: the sync-from-clipboard fires on window focus — clicking back counts as a focus event.) |
Part C — Lifecycle race / self-healing guard rail (epic #2913)
This part covers the intermittent "yank stops copying to the clipboard until I relaunch the app" bug. Root cause: vim-clipboard.ts was a module-level singleton with no ownership, and multiple concurrent editor instances (main editor, archive editor, external-file-editor tabs) all shared it. A non-owning instance's teardownVimClipboard() on unmount/re-render could detach the binding from the still-focused editor, which never re-installed it.
The fix makes the singleton ownership-aware (single-owner, last-setup-wins; teardown is a no-op unless the caller is the current owner) and self-healing (re-asserts the binding on window focus + editor focusin — identity-only, zero clipboard I/O — plus a low-frequency interval backstop).
Run against an installed
.app(plugin leg) for the authoritative verdict. Vim mode + Clipboard Sync must both be on (Settings → Editor / Vim).
C1 — Yank survives multi-editor churn
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | Open a text app. In the main editor, type some text and yank a line (yy); paste into an external app (Cmd+V). | Yanked text pastes. | |
| 2 | Open an external file in the external-file-editor (a second editor instance), then close that tab / switch focus back to the main editor. | Focus returns to the main editor. | |
| 3 | In the main editor, yank a different line (yy) and paste into an external app. | The new line pastes — yank still copies to the clipboard (pre-fix: this silently pasted the old/wrong text or nothing). | |
| 4 | Change any editor/vim setting (forces an editor rebuild), then yank again and paste. | Yank still copies to the clipboard. |
C2 — Self-heal after drift
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | With vim + Clipboard Sync on, switch to another app and back (window blur → focus). | On regaining focus the binding is re-asserted (and the external clipboard is synced in for p). | |
| 2 | Yank a line and paste into an external app. | Yanked text pastes. No relaunch ever required. |
Part D — Installed macOS external refresh (#5019)
Run this part against a freshly installed .app, not dev:mock. Keep Vim mode and Clipboard Sync enabled. Use distinct strings in each cycle so an old register value cannot look like a pass.
D1 — External ownership refresh and focus-menu guard
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | In the Vim editor, create a line containing zudo yank 1, press Escape, then yy. Switch to TextEdit and press Cmd+V. | TextEdit receives zudo yank 1. | |
| 2 | In TextEdit, copy the distinct text textedit copy 1, then switch back to the installed app and wait 2.5 seconds. | The app regains focus without showing the native Paste-permission menu; the polling backstop has had time to run even if macOS omitted both focus signals. | |
| 3 | Without using Cmd+V, press p in Vim normal mode. | Vim inserts textedit copy 1, not zudo yank 1. | |
| 4 | Click between the editor, preview, and editor again several times. | Merely focusing the editor never shows the native Paste-permission menu. |
D2 — Refresh survives editor lifecycle changes
| Step | Action | Expected result | Pass / Fail |
|---|---|---|---|
| 1 | Open an external-file-editor tab, focus its editor, then close the tab and return to the main Vim editor. In TextEdit copy textedit after tab, return to the app, and press p. | Vim inserts textedit after tab; the closed editor did not leave a stale or duplicate listener. | |
| 2 | Change an editor or Vim setting that rebuilds/reconfigures the editor. In TextEdit copy textedit after rebuild, return to the app, and press p. | Vim inserts textedit after rebuild without relaunching. | |
| 3 | Repeat a full app blur → focus cycle with textedit after blur, then press p. | Vim inserts textedit after blur. | |
| 4 | Immediately after returning from TextEdit, yank a new Vim line before an earlier clipboard read could reasonably finish, then paste into TextEdit. | The new yank remains authoritative; a stale async read does not overwrite it. |
Pass criteria
All rows in Parts A and B (the original eight), Part C, and Part D must show Pass for the fix to be considered verified. Record any Fail rows with the actual observed behavior in the relevant issue. Post Part D evidence to #2916, but keep that tracker open until its integrated confirmation sub-issue passes.
Automation coverage
| What | Where | Leg covered |
|---|---|---|
| Unit tests (adapter contract, native/DOM focus, stale-read guards, ownership/guard rail) | tauri- | Both legs (mocked) |
| E2E spec (browser, WebKit) | e2e/ | Fallback (navigator.clipboard); guard-rail focus-cycle regression |
| This manual checklist (Part A) | Human + installed .app | Plugin (@tauri-apps/plugin-clipboard-manager) |
| This manual checklist (Part B) | Human + dev:mock | Fallback (navigator.clipboard) |