--- name: obsidian-plugin-verify description: >- Verify an Obsidian plugin with Node unit tests, typecheck, production build, and Selenium E2E against real Obsidian. Use for test:e2e harnesses, Cloud VM Obsidian install, data-testid health checks, or /obsidian-plugin-verify. --- # Verify an Obsidian plugin Prove behavior on three rungs: Node tests of pure modules, a production bundle, then a real Obsidian window. This skill owns the command loop. Hub [definition of done](../obsidian-plugin/SKILL.md) is the pass/fail bar. Ship must not tag a release that fails it. ```bash npm test # node --experimental-strip-types --test tests/*.mjs npm run typecheck # tsc --noEmit npm run build # esbuild production → main.js npm run test:e2e # build, then node --test e2e/*.test.mjs (long timeout) ``` Node 22+ is required for strip-types. CI should use Node 22. ## Unit tests Put cases in `tests/*.mjs`. Import `../src/....ts` directly. Do not mock `obsidian` to test parsing. Cover: - Parsers and markdown writers - Path safety and injection - Settings merge / migrate - Source contracts Selenium depends on (hooks present, banned APIs absent). The assertion list is [obsidian-plugin-ui/references/guidelines-checklist.md](../obsidian-plugin-ui/references/guidelines-checklist.md). - Workflow shape so CI cannot silently stop being a required check When you add a `data-testid`, add a source `assert.match` in the same change. ## Production bundle `npm run build` must write repo-root `main.js`. The e2e vault copier and the GitHub Release both read that path. Decide whether `main.js` is committed: - **Committed:** clone-and-sideload works; after a local build you do not intend to ship, `git checkout -- main.js` - **Release-only:** gitignore `main.js`, attach it on the GitHub Release, and document that in `AGENTS.md` so agents stop restoring a file that is not tracked ## Selenium health check `e2e/health-check.test.mjs` (or equivalent) launches Obsidian, attaches ChromeDriver to CDP, and drives the plugin through `data-testid` hooks. Harness shape: [references/selenium-harness.md](references/selenium-harness.md). Drive notes by vault path, commands by palette query or `executeCommandById`, settings by `openTabById("")`. Read notices in one `executeScript` over `.notice` nodes. Obsidian recycles those nodes, so `findElements` then read is racy. ### Skip vs fail Return a skip reason when `SKIP_E2E=1`, Obsidian is missing, or there is no X display. Skipping is allowed only after you tried to install and launch Obsidian. Record the skip reason in the PR. A skipped suite is not a pass. HTML mockups do not substitute for E2E. ### Keep coverage honest If you change a user-visible path, add or update an e2e assertion for that path. Leaving the health check stale after a UI change is a bug. ## Computer-use Do not use the computer-use agent as the primary health check. It is slower and non-deterministic on a path Selenium already covers. Use it only to debug a failed `npm run test:e2e` after looking at e2e screenshots. ## Cloud agents Portable Cloud VM contract (copy into `AGENTS.md`): [references/cloud-agents.md](references/cloud-agents.md). If the target repo already has `AGENTS.md`, follow that first.