@watershed-labs/replay
v0.0.1
Published
Step-buffer DOM replay package
Readme
@watershed-labs/replay
Step-buffer DOM replay for failed Selenium tests
Part of the Watershed testing ecosystem.
Overview
@watershed-labs/replay wraps a Selenium WebDriver and captures a state snapshot
after every test step. On failure the last N snapshots are written to a
self-contained .html viewer. On a passing test the buffer is discarded — nothing
is ever written to disk.
What gets captured per step:
| Signal | Source |
| --------------------------------- | ----------------------------------------------------- |
| DOM snapshot | document.documentElement.outerHTML with CSS inlined |
| Console errors/warnings | console.error + console.warn hook |
| Network failures | HTTP 4xx/5xx via fetch + XHR patch + CDP |
| Watched endpoints | User-defined URLs captured regardless of status |
| localStorage + sessionStorage | Captured fresh each step |
| Cookies | driver.manage().getCookies() — includes HttpOnly |
| Redux state | window.__WS_REDUX__ or common fallbacks |
Performance model — style collection is passive, driven by CDP
Network.responseReceived events the browser fires during normal page operation.
The test never waits for capture work. The sliding window (maxSteps: 10 default)
means memory usage is bounded regardless of scenario length.
Steps only — Before/After hooks are not captured. The buffer tells the story of what the UI did during the test steps themselves.
Installation
npm install @watershed-labs/replayUsage
With Cucumber (attachReplay)
Drop it into support/hooks.js alongside your existing driver setup:
import { Builder } from 'selenium-webdriver';
import { attachReplay } from '@watershed-labs/replay';
Before(async function () {
this.driver = attachReplay(this, await new Builder().forBrowser('chrome').build(), {
maxSteps: 10,
watchedEndpoints: ['/api/checkout', '/api/auth/login'],
outputDir: 'reports/replay'
});
});attachReplay handles everything:
- Wraps the driver and stores it in
world._replay - Labels each captured step with the Cucumber step text via
BeforeStep - Flushes the buffer after each passed step
- Locks and writes
reports/replay/<slug>-<id>.htmlon failure - Discards the buffer silently on pass
- Calls
driver.quit()in its ownAfterhook — remove any existing quit call
Direct usage (ReplayWrapper)
For non-Cucumber runners or custom setups:
import { ReplayWrapper } from '@watershed-labs/replay';
import { Builder } from 'selenium-webdriver';
const driver = new ReplayWrapper(await new Builder().forBrowser('chrome').build(), {
maxSteps: 10,
watchedEndpoints: ['/api/orders']
});
// Use exactly like the raw driver
await driver.navigate().to('https://example.com');
await driver.findElement(By.id('q')).sendKeys('watershed');
// On failure
const html = driver.buildReplay({ scenario: 'My test', feature: 'Search' });
writeFileSync('reports/replay/my-test.html', html, 'utf8');
// On pass
driver.clearReplay();
await driver.quit();Redux state capture (optional)
Register your store once — in your app bootstrap or a Before hook that
executes a script in the browser:
await driver.executeScript('window.__WS_REDUX__ = window.myReduxStore');If window.__WS_REDUX__ is not set the package also tries
window.__REDUX_STORE__ and window.store, then skips silently.
The viewer
Output is a single .html file. Open it from file:// — no server required,
no network requests made.
┌──────────────────────────────────────────────────────────────┐
│ Topbar — scenario · feature · step N of M · ◀ ▶ │
├────────────────────┬─────────────────────────────────────────┤
│ Step timeline │ DOM snapshot (iframe) │
│ │ │
│ ● Given I open… │ Inspect Element works here. │
│ ● When I type… │ Scripts are blocked. │
│ ◆ API /checkout │ External CDN resources not loaded. │
│ ✕ When I click… ├─────────────────────────────────────────┤
│ │ Console │ Network │ Storage │ Redux │
└────────────────────┴─────────────────────────────────────────┘Step indicators:
| Indicator | Meaning |
| --------- | -------------------------------- |
| ● grey | no signals |
| ● amber | console errors/warnings |
| ● red | network 4xx/5xx |
| ◆ blue | watched endpoint captured |
| ✕ red | step active when the test failed |
Data tabs — each tab shows data for the selected step only:
- Console — level · timestamp · message
- Network — method · URL · status; errors in red, watched endpoints in blue
- Storage —
localStorage,sessionStorage, cookies — diff vs previous step - Redux — store diff vs previous step (hidden if Redux not detected)
Keyboard shortcuts:
| Key | Action |
| --------------- | ---------------------------------------------- |
| ← / h | previous step |
| → / l | next step |
| Home | first buffered step |
| End | failed step |
| 1 2 3 4 | switch Console / Network / Storage / Redux tab |
API
| Export | Description |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| attachReplay(world, driver, options?) | Cucumber integration helper. Wraps the driver, registers all hooks, handles write-on-fail / discard-on-pass. Returns the wrapped driver. |
| ReplayWrapper | WebDriver proxy. Intercepts actions, manages the step-buffer, exposes buildReplay() and clearReplay(). |
| StepBuffer | Low-level sliding-window buffer. push / release / lock / clear. |
Options
| Option | Type | Default | Description |
| ------------------ | ---------- | ------------------ | ---------------------------------------------------------------- |
| maxSteps | number | 10 | Sliding window size. Only the last N steps are kept at any time. |
| watchedEndpoints | string[] | [] | URL substrings to capture regardless of HTTP status. |
| captureRedux | boolean | true | Attempt Redux store capture. |
| outputDir | string | 'reports/replay' | Output directory. Created automatically. |
Dependencies
selenium-webdriver— peer dependency, already present in the Watershed monorepo
No additional production dependencies.
Parallel safety
Each Selenium worker holds its own in-memory buffer. Workers are isolated
processes — buffers are never shared. Output filenames include a 6-char ID
derived from testCaseStartedId, guaranteeing uniqueness across workers and
across Scenario Outline example rows that share the same scenario name.
reports/replay/
search-for-watershed-a3f2c1.html
search-for-selenium-b91cd4.htmlLicence
MIT — part of the Watershed ecosystem.
