with one click
e2e-testing
Use when working with e2e tests.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Use when working with e2e tests.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | e2e-testing |
| description | Use when working with e2e tests. |
🧠 Continuous Improvement: If you discover new patterns, common pitfalls, or efficient ways to run/debug tests while working in this domain, please update this file to capture that knowledge for future agents.
This project uses WebdriverIO with the wdio-obsidian-service for end-to-end testing. Tests run a real instance of Obsidian with the Anker plugin installed.
test/specs/**/*.e2e.ts (The actual test files)test/vaults/ (Markdown files and assets used during tests)wdio.conf.mtsThis command rebuilds the plugin and runs the full suite against the latest Obsidian version.
npm run test:e2e:latest
You usually need to build the plugin first so the test uses the latest code.
npm run build && npx wdio run wdio.conf.mts --spec test/specs/card-errors.e2e.ts
Standard .click() often fails in Obsidian due to custom UI layers or non-standard listeners.
Problem: element not interactable or click intercepted.
Solution: Use JS execution to force the click.
const btn = await $(".my-button");
// Avoid: await btn.click();
await browser.execute((el) => el.click(), btn);
You can run code inside the Obsidian process using executeObsidian.
await browser.executeObsidian(async (app) => {
// This runs inside Obsidian's renderer process
const file = app.vault.getAbstractFileByPath("flashcards/my-card.md");
await app.workspace.getLeaf().openFile(file);
});
Always verify the exact Command ID in src/main.ts. Anker commands usually start with anker:.
// Good
await browser.executeObsidianCommand("anker:open-failed-cards");
Obsidian is heavily asynchronous (file system, metadata cache, UI animations).
browser.pause(5000) unless absolutely necessary.waitForExist, waitForDisplayed, or waitUntil.Example: Waiting for a modal
const modal = await $(".modal");
await modal.waitForDisplayed({ timeout: 5000 });
Some Obsidian modals use hidden file inputs (display: none). WebDriverIO cannot interact with them directly.
Use browser.execute to temporarily make the input visible before setValue.
await browser.execute((sel: string) => {
const input = document.querySelector(sel) as HTMLInputElement | null;
if (input) input.style.display = "block";
}, ".my-hidden-file-input");
const fileInput = $(".my-hidden-file-input");
await fileInput.setValue(remotePath);
Tests share the same vault folder (test/vaults). Ensure you clean up or reset state in beforeEach.
beforeEach(async () => {
// Reset contents of a file to a known clean state
await browser.executeObsidian(async (app) => {
const file = app.vault.getAbstractFileByPath("flashcards/test-card.md");
await app.vault.modify(file, "Initial clean content");
});
});
If a test opens a modal, ensure it is closed in afterEach to avoid stacked modals and timeouts.
afterEach(async () => {
await browser.execute(() => {
const buttons = document.querySelectorAll(
".modal-container .modal-close-button",
);
buttons.forEach((btn) => (btn as HTMLElement).click());
});
await browser.pause(200);
});
anker:open-failed-cards).app.vault.create doesn't mean the cache is ready instantly. If your test depends on frontmatter readings immediately after creation, you might hit a race condition.templates/ folder in beforeEach to avoid blocking tests.any.awaited.