Use when writing, debugging, or maintaining Playwright e2e tests for Positron -- new test files, test cases, flaky-test fixes, test infrastructure, or performance/metric tests.
76
93%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Provides specialized knowledge and patterns for writing correct, reliable Playwright e2e tests that follow Positron's established conventions and avoid common mistakes.
Prefer the smallest test that confidently protects the intended user-visible behavior. Do not add additional scenarios or assertions simply because they are easy to write -- extra setup, incidental checks, and duplicate assertions add maintenance cost and flake surface without adding confidence.
A good e2e test:
Load this skill when:
Before writing anything, open an existing test in test/e2e/tests/<feature>/ for the area you're working on and skim it. The reference docs below tell you how to verify a method and why a pattern exists; the existing tests show you what a correct test actually looks like, including the flake-avoiding details that live in no doc, such as which panes overlap the view under test, how cell/output values render (numeric grid cells come back as strings, for instance), and which tags a suite in that area carries. Copy the closest neighbor's structure, then adjust it. Use the reference docs to confirm each method name against source and to understand the gotchas.
Every test file MUST follow this structure:
import { test, expect, tags } from '../_test.setup';
// REQUIRED: Each test file needs a unique suiteId
test.use({
suiteId: __filename
});
test.describe('Feature Name', {
tag: [tags.WEB, tags.WIN, tags.CRITICAL, tags.FEATURE_TAG]
}, () => {
test.beforeEach(async ({ app }) => {
// Optional setup for each test
});
test.afterEach(async ({ app, hotKeys }) => {
// Cleanup after each test
await hotKeys.closeAllEditors();
});
test('Test description', async ({ app, python }) => {
// Test implementation
});
});MANDATORY REQUIREMENTS:
../_test.setup - NOT from @playwright/test. Import only what the file uses: test and tags always, expect only if you write raw assertions (a file whose assertions all go through POM methods doesn't import expect, and an unused import fails lint).suiteId: __filename - Required for app isolation| Fixture | Use Case |
|---|---|
app | Access workbench page objects: app.workbench.console, etc. |
page | Direct Playwright page access: page.getByLabel(...) |
python | Auto-start Python interpreter before test |
r | Auto-start R interpreter before test |
sessions | Manual session management: await sessions.start('python') |
executeCode | Execute code: await executeCode('Python', 'print("hi")'); |
openFile | Open file: await openFile('workspaces/test/file.py'); |
hotKeys | Keyboard shortcuts: await hotKeys.closeAllEditors(); |
settings | Change settings: await settings.set({ 'key': value }); |
See references/fixtures.md for complete fixture documentation.
UI interactions go through app.workbench.* page objects, not raw locators. Before writing any interaction: check for an existing method, then consider adding a reusable one, and only fall back to a raw locator when neither fits -- see references/common-mistakes.md #15 for the full workflow, and references/page-objects.md for usage idioms and "Finding the Exact Source" for looking up the exact signature in test/e2e/pages/*.ts. Never guess or paraphrase a method name -- copy it from the source file.
Standard Playwright web-first assertions apply, with the project's 15s default timeout covering most checks -- don't add { timeout } reflexively. See references/assertions.md for choosing between toPass, expect.poll, and plain web-first assertions, selector priority, and what makes an assertion worth adding versus redundant.
Tag every test.describe via the tag array. Available tags are the FeatureTags (what the test covers) and PlatformTags (where it runs) enums in test/e2e/infra/test-runner/test-tags.ts. A test with no platform tag runs only on Linux/Electron; add tags.WEB / tags.WIN to broaden. See references/test-structure.md for the full tagging and annotation model.
Performance/metric tests live in a performance/ subdirectory under their feature directory (e.g. tests/data-explorer/performance/, tests/console/performance/). They use metric.* timing wrappers (e.g. metric.console.executeCode, metric.dataExplorer.loadData) and must capture only the user-observable action, not test scaffolding.
Recipe: All setup (focus, staging code, pre-checks) happens before the timer. Inside the timer: only the bare trigger (e.g. page.keyboard.press('Enter')) and the wait for completion.
Why not use POM submit methods inside the timer? Many POM methods hide fixed delays. For example, sendEnterKey() contains a waitForTimeout(500) and a focus() call, so wrapping it inside a metric inflates every measurement by ~600ms of synthetic noise. Before using any POM method inside a timer, check its source for waitForTimeout, artificial focus calls, or retry loops. For the trigger keypress, prefer page.keyboard.press() directly.
All performance/metric tests must include tags.PERFORMANCE in their tag list.
Critical (will break tests):
../_test.setup, not @playwright/testsuiteId - must have test.use({ suiteId: __filename })tags.WEB, tags.WIN for cross-platformQuality issues:
4. Timeout overrides added reflexively - the 15s default covers most UI checks; only override for a known-slow (or known-fast) operation
5. No test.step() - wrap complex multi-action sequences for better reports
6. Fixed waits - page.waitForTimeout(...) instead of a web-first assertion, expect.poll, toPass, or a POM wait helper
See references/common-mistakes.md for detailed gotchas with code examples.
# Run specific test file
npx playwright test <test-name>.test.ts --project e2e-electron
# Run all tests in a category
npx playwright test test/e2e/tests/<category>/
# Run with specific tags
npx playwright test --grep @:critical
# Run in headed mode (see browser)
npx playwright test --headed
# Run with debug mode
npx playwright test --debug
# Show test report
npx playwright show-reportFor detailed information, read the bundled reference docs:
references/test-setup.md - How to configure the local machine environment to run testsreferences/test-structure.md - Complete test file structure and organizationreferences/fixtures.md - All available fixtures and their usagereferences/page-objects.md - Page object usage idioms (curated, not exhaustive)references/assertions.md - Retry-mechanism choice and selector priority (Positron-specific; standard Playwright assertions assumed)references/common-mistakes.md - Positron-specific gotchas to avoidpage, sessions, etc. fresh per testapp.workbench.*test/e2e/tests/<feature>/ for patternstest/e2e/pages/ for available methodstest/e2e/tests/_test.setup.ts for fixture definitions--debug flag to step through tests interactivelytest-health directly for a quick read on known failure patterns -- see ../e2e-failure-analyzer/scripts/README.md for the test-key format and how to call e2e-query-history.js. For a full guided root-cause dig through the evidence, suggest the user run /triage-e2e-test (manual-only, not something to invoke on their behalf).b87c504
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.