@impulselab/testing
v0.0.11
Published
E2E testing library with Puppeteer for browser automation
Readme
Impulse Testing
E2E testing library that records user interactions and replays them as automated tests
Impulse Testing is a modern E2E testing library built on Puppeteer that allows you to record real user interactions in your browser and automatically replay them as tests. No coding required for test creation! Just click, type, and interact naturally with your application.
Key Features
- 📹 Interactive Recording: Record user interactions as YAML stories in a visible browser
- 🔄 Automated Replay: Execute stories headlessly for fast, reliable testing
- 📸 Visual Regression: Screenshot comparison with pixel-perfect diff detection
- 🎯 Smart Selectors: Automatic generation of stable CSS selectors for elements
- 💻 CLI Interface: Intuitive interactive shell for story management
- 🚀 CI/CD Ready: Non-interactive mode designed for continuous integration
- ⚡ Zero Config: Interactive onboarding with auto-detection of project types
Quick Start
1. Initialize Your Project
Run Impulse Testing for the first time to set up your project:
npx @impulselab/testing --initThe interactive onboarding will:
- Create the
.testing/directory structure - Generate a
config.ymlwith your project settings - Auto-detect your framework (Next.js, Vite, etc.)
- Configure lifecycle commands for starting/stopping your application
2. Record Your First Story
Create a new test by recording your interactions:
npx @impulselab/testing --newThen:
- Enter a name for your story (e.g., "User Login Flow")
- Confirm or edit the auto-generated ID (e.g.,
user-login-flow) - Enter your application's start URL (default:
http://localhost:3000) - A browser window will open—interact with your app naturally
- Click "Take Snapshot" to capture screenshots at key moments
- Click "Stop Recording" when done
Your interactions are saved as a reusable YAML story in .testing/stories/{story-id}/story.yml.
3. Run Tests
Interactive Mode (Local Development)
npx @impulselab/testingSelect a story from the list and watch it execute. If screenshots differ, you'll see a visual diff and can choose to accept or reject changes.
CI Mode (Automated Testing)
npx @impulselab/testing --ciRuns all stories headlessly with automatic failure on screenshot mismatches. Perfect for CI/CD pipelines.
CLI Commands
Default Mode (Interactive)
npx @impulselab/testingOpens an interactive shell where you can:
- Browse and select existing stories
- Create new stories
- Execute tests with visual feedback
Recording Mode
npx @impulselab/testing --newDirectly starts the story creation flow, skipping the interactive menu.
CI/CD Mode
npx @impulselab/testing --ciRuns all stories in non-interactive mode:
- No user prompts
- Auto-fails on screenshot mismatches
- Proper exit codes (0 = pass, 1 = fail)
Run Specific Stories
# Run a single story
npx @impulselab/testing --story user-login
# Run multiple stories
npx @impulselab/testing --story login --story checkout --story profile
# Run specific stories in CI mode
npx @impulselab/testing --ci --story login --story checkoutHelp and Version
npx @impulselab/testing --help
npx @impulselab/testing --versionConfiguration
Config File Structure
Impulse Testing uses .testing/config.yml to manage your test environment:
lifecycle:
start:
- command: "npm run dev"
keepAlive: true # Keep process running during tests
- command: "npm run db:start"
timeout: 10000 # 10 seconds to for database startup
stop:
- command: "npm run db:stop"
timeout: 10000
screenshots:
diffThreshold: 0.001 # Percentage of pixels allowed to differ (0-100), we recommand using the smaller number possibleConfiguration Options
lifecycle.start: Commands to start your application
command: Shell command to executekeepAlive: Iftrue, process stays running; iffalse, waits for completiontimeout: Maximum time to wait (milliseconds)
lifecycle.stop: Commands to stop your application and clean up resources
screenshots.diffThreshold: Tolerance for pixel differences
0: Pixel-perfect matching (strictest)0.001: Allow 0.001% of pixels to differ (recommended)- Higher values: More tolerant of minor rendering differences
Story Structure
Stories are stored as YAML files in .testing/stories/{story-id}/story.yml:
id: user-login-flow
name: User Login Flow
start:
url: http://localhost:3000
resolution:
width: 1920
height: 1080
pixelRatio: 1
deviceScaleFactor: 1
actions:
- type: click
selector: "#login-button"
- type: input
selector: "#email"
value: "[email protected]"
- type: input
selector: "#password"
value: "password123"
- type: click
selector: "#submit-button"
- type: screenshot
name: "1760513305222-zd1kqk.png"Available Action Types
Navigation Actions
navigate: Navigate to a URLgoBack: Browser back buttongoForward: Browser forward buttonreload: Reload current page
Interaction Actions
click: Click an elementinput: Type text into an input fieldselect: Select dropdown optioncheck: Check a checkbox or radio buttonuncheck: Uncheck a checkboxhover: Hover over an elementfocus: Focus an elementblur: Remove focus from an element
Scrolling Actions
scroll: Scroll the pagescrollIntoView: Scroll element into viewport
Wait Actions
wait: Wait for specified millisecondswaitForSelector: Wait for element to appearwaitForNavigation: Wait for page navigation
Advanced Actions
uploadFile: Upload files to file inputsexecuteScript: Execute custom JavaScriptscreenshot: Capture and compare screenshot
Selector Strategy
Impulse Testing automatically generates stable CSS selectors using this priority:
- ID attribute (
#unique-id) - Most stable and preferred - Test attributes (
[data-testid="value"],[data-test="value"]) - Recommended for test stability - Complex selectors - Auto-generated using classes and structure
Best Practice: Add data-testid attributes to important elements for more reliable tests.
Workflow
Recording Workflow
- Start Recording: Run
npx @impulselab/testing --new - Provide Metadata: Enter story name, ID, and start URL
- Interact Naturally: Click, type, and navigate as a real user would
- Capture Snapshots: Click "Take Snapshot" button at key moments to capture visual states
- Stop Recording: Click "Stop Recording" when your user flow is complete
- Story Saved: Actions and screenshots are automatically saved to
.testing/stories/
Testing Workflow
Local Development
- Run Interactive Mode:
npx @impulselab/testing - Select Story: Choose from the list of available stories
- Watch Execution: See each action execute in real-time
- Review Results: If screenshots differ:
- VS Code diff viewer opens automatically
- Choose to accept new screenshot or keep baseline
- Test passes only if you accept changes
CI/CD Pipeline
- Add to Pipeline: Add
npx @impulselab/testing --cito your CI config - Automatic Execution: All stories run headlessly without user interaction
- Screenshot Validation: Any pixel differences cause test failure
- Exit Codes:
0= All tests passed1= One or more tests failed
Example GitHub Actions:
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npx @impulselab/testing --ciScreenshot Comparison
Visual Regression Testing
When a story includes screenshot actions, Impulse Testing automatically:
- Captures the current viewport as a PNG image
- Compares pixel-by-pixel with the baseline screenshot
- Calculates the percentage of different pixels
- Applies Threshold: Uses
diffThresholdfrom config (default 0.1%)
Resolution Modes
Interactive Mode (Local)
When differences are detected:
- Opens VS Code diff viewer showing side-by-side comparison
- Presents CLI prompt with two options:
- Keep old screenshot (fail test): Baseline unchanged, test marked as failed
- Accept new screenshot (update baseline): Baseline updated, test passes
- User navigates with arrow keys and confirms with Enter
CI Mode (Automated)
When differences are detected:
- Automatically keeps old screenshot
- Marks test as failed
- No user interaction required
- No baseline updates
Project Structure
.testing/ # All test-related files
├── config.yml # Main configuration file
├── stories/ # Test stories organized by ID
│ ├── user-login-flow/
│ │ └── story.yml # Story actions and metadata
│ ├── checkout-process/
│ │ └── story.yml
│ └── ...
├── screenshots/ # Reference screenshots for comparison
│ ├── user-login-flow/
│ │ ├── 0.png
│ │ ├── 1.png
│ │ └── ...
│ └── ...
└── temp/ # Temporary files (mismatched screenshots, errors)
├── error-1234567890.png # Diagnostic screenshots on failures
└── ...Important Files:
config.yml: Application lifecycle, screenshot settings, output optionsstories/{id}/story.yml: Recorded actions and test metadatascreenshots/{id}/*.png: Baseline images for visual regression testing
Development
Building from Source
# Clone repository
git clone https://github.com/impulse-studio/testing.git
cd testing
# Install dependencies
pnpm install
# Build TypeScript
pnpm build
# Run in development mode (uses demo/ directory)
pnpm devDevelopment Scripts
# Format code with Biome
pnpm format
# Type checking and linting
pnpm checks
# Run built CLI
pnpm startProject Scripts
pnpm build: Compile TypeScript todist/pnpm dev: Run CLI in development mode againstdemo/directorypnpm format: Auto-format code using Biomepnpm checks: Run TypeScript compiler and Biome linter (no emitting)
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
License
See LICENSE for details
Built with: Puppeteer • TypeScript • Zod • Commander.js • Inquirer by Impulse Lab
