Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Capture and manage screenshots during test execution
.claude/skills/testdriverai-testdriver-screenshots/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 46% | 0% |
<!-- Generated from screenshots.mdx. DO NOT EDIT. -->
TestDriver can capture screenshots manually at any point during a test, or automatically before and after every command. Screenshots are saved to a structured directory for easy debugging.
Use testdriver.screenshot() to capture the current screen:
javascriptconst path = await testdriver.screenshot(); console.log('Saved to:', path); // .testdriver/screenshots/my-test/screenshot-1719849312345.png
javascriptawait testdriver.screenshot(filename?)
<ParamField path="filename" type="string"> Custom filename for the screenshot. .png is appended automatically if missing. If omitted, defaults to screenshot-<timestamp>.png. </ParamField>
Returns: Promise<string> — the absolute file path of the saved screenshot.
javascript// Default filename await testdriver.screenshot(); // → .testdriver/screenshots/my-test/screenshot-1719849312345.png // Custom filename await testdriver.screenshot('login-page'); // → .testdriver/screenshots/my-test/login-page.png // With .png extension await testdriver.screenshot('dashboard-loaded.png'); // → .testdriver/screenshots/my-test/dashboard-loaded.png
Enable automatic screenshots before and after every command:
javascriptconst testdriver = new TestDriver({ autoScreenshots: true, });
<ParamField path="autoScreenshots" type="boolean" default={false}> When true, captures a screenshot before and after every SDK command (click, type, find, scroll, hover, pressKeys, assert, exec, etc.). On error, an error-phase screenshot replaces the after-phase screenshot. </ParamField>
Auto-screenshots follow this naming convention:
<seq>-<action>-<phase>-L<line>-<description>.png| Part | Description | Example | |---|---|---| | seq | 3-digit zero-padded sequence number | 001 | | action | Command name | click, type, find | | phase | before, after, or error | before | | L<line> | Source line number from your test file | L42 | | description | Sanitized from command arguments (max 30 chars) | submit-button |
Examples:
001-find-before-L15-login-button.png
002-find-after-L15-login-button.png
003-click-before-L16-login-button.png
004-click-after-L16-login-button.png
005-type-before-L18-username-field.png
006-type-error-L18-username-field.png| Phase | When | Description | |---|---|---| | before | Before command executes | Captures the screen state before the action | | after | After successful command | Captures the result of the action | | error | After failed command | Captures the screen at the point of failure (replaces after) |
Screenshots are saved to:
<cwd>/.testdriver/screenshots/<testFileName>/Where <testFileName> is the test file name without its extension. For example, a test at tests/login.test.mjs saves screenshots to .testdriver/screenshots/login.test/.
The screenshot directory for each test file is automatically cleaned at the start of a test run. This happens once per process per test file to prevent concurrent tests from the same file from interfering with each other.
Elements have a saveDebugScreenshot() method for debugging element detection:
javascriptconst el = await testdriver.find('submit button'); // Save the screenshot that was used to detect this element const debugPath = await el.saveDebugScreenshot(); console.log('Debug screenshot:', debugPath); // → ./debug-screenshot-1719849312345.png // Custom path await el.saveDebugScreenshot('./my-debug.png');
This saves the screenshot that was captured during the find() call, which can be useful for understanding what the AI "saw" when locating the element.
javascriptimport { describe, it, beforeAll, afterAll } from 'vitest'; import TestDriver from 'testdriverai'; describe('Screenshot Example', () => { let testdriver; beforeAll(async () => { testdriver = new TestDriver({ autoScreenshots: true, // capture every step }); await testdriver.ready(); await testdriver.provision.chrome({ url: 'https://example.com' }); }); afterAll(async () => { await testdriver.disconnect(); }); it('captures the login flow', async () => { // Auto-screenshots capture before/after each command // Manual screenshot for a specific moment await testdriver.screenshot('initial-page-load'); const username = await testdriver.find('username input'); await username.click(); await testdriver.type('testuser@example.com'); await testdriver.screenshot('after-username-entry'); const password = await testdriver.find('password input'); await password.click(); await testdriver.type('password123'); await testdriver.find('login button').click(); await testdriver.screenshot('after-login-click'); }); });
After running, your screenshot directory will contain:
.testdriver/screenshots/login-flow.test/
├── initial-page-load.png
├── 001-find-before-L18-username-input.png
├── 002-find-after-L18-username-input.png
├── 003-click-before-L19-username-input.png
├── 004-click-after-L19-username-input.png
├── 005-type-before-L20-testuser-example-com.png
├── 006-type-after-L20-testuser-example-com.png
├── after-username-entry.png
├── 007-find-before-L24-password-input.png
├── ...| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-06 | fail→pass | 11,126 | 6,091 | -45% | 1 | 1 | 0% | 1,840 | 2,651 | +44% | 0 | 0 | — |
case-01 | fail→pass | 10,122 | 18,900 | +87% | 1 | 1 | 0% | 1,933 | 2,877 | +49% | 0 | 0 | — |
case-02 | fail→pass | 17,890 | 6,451 | -64% | 1 | 1 | 0% | 2,767 | 2,848 | +3% | 0 | 0 | — |
case-03 | fail→pass | 12,667 | 7,392 | -42% | 1 | 1 | 0% | 2,217 | 2,931 | +32% | 0 | 0 | — |
case-04 | pass→pass | 9,828 | 9,075 | -8% | 1 | 1 | 0% | 1,725 | 3,112 | +80% | 0 | 0 | — |
case-05 | pass→pass | 11,853 | 6,177 | -48% | 1 | 1 | 0% | 1,779 | 2,537 | +43% | 0 | 0 | — |
case-07 | pass→pass | 8,979 | 3,801 | -58% | 1 | 1 | 0% | 1,402 | 2,297 | +64% | 0 | 0 | — |
case-08 | pass→pass | 10,468 | 2,206 | -79% | 1 | 1 | 0% | 1,886 | 1,928 | +2% | 0 | 0 | — |
case-09 | fail→pass | 8,346 | 2,795 | -67% | 1 | 1 | 0% | 1,417 | 2,068 | +46% | 0 | 0 | — |
case-10 | fail→pass | 7,865 | 1,654 | -79% | 1 | 1 | 0% | 1,185 | 1,800 | +52% | 0 | 0 | — |
case-11 | fail→pass | 9,064 | 2,564 | -72% | 1 | 1 | 0% | 1,436 | 1,996 | +39% | 0 | 0 | — |
case-12 | pass→pass | 6,444 | 1,815 | -72% | 1 | 1 | 0% | 1,185 | 1,820 | +54% | 0 | 0 | — |
case-13 | pass→pass | 12,135 | 1,669 | -86% | 1 | 1 | 0% | 1,727 | 1,695 | -2% | 0 | 0 | — |
case-14 | pass→pass | 2,667 | 1,909 | -28% | 1 | 1 | 0% | 476 | 1,822 | +283% | 0 | 0 | — |
case-15 | fail→pass | 10,100 | 2,725 | -73% | 1 | 1 | 0% | 1,810 | 2,056 | +14% | 0 | 0 | — |
case-16 | pass→pass | 14,687 | 1,914 | -87% | 1 | 1 | 0% | 2,396 | 1,891 | -21% | 0 | 0 | — |
case-17 | fail→pass | 8,429 | 2,579 | -69% | 1 | 1 | 0% | 1,598 | 2,023 | +27% | 0 | 0 | — |
case-18 | fail→pass | 13,315 | 2,151 | -84% | 1 | 1 | 0% | 1,713 | 1,890 | +10% | 0 | 0 | — |
case-19 | fail→pass | 11,305 | 3,342 | -70% | 1 | 1 | 0% | 1,944 | 1,995 | +3% | 0 | 0 | — |
case-20 | fail→pass | 17,701 | 2,186 | -88% | 1 | 1 | 0% | 3,054 | 1,864 | -39% | 0 | 0 | — |
case-21 | fail→pass | 6,851 | 6,827 | -0% | 1 | 1 | 0% | 1,262 | 2,670 | +112% | 0 | 0 | — |
case-22 | pass→pass | 8,542 | 3,832 | -55% | 1 | 1 | 0% | 1,285 | 2,195 | +71% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +59 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.