Jest E2E Testing Framework
A powerful Jest + Puppeteer E2E testing framework with built-in device automation, data builders, and CLI.
🚀 Features
- Easy Setup: Get started with E2E testing in minutes
- Device Automation: Built-in browser automation with simple API
- Data Builders: Flexible test data generation with inheritance
- CLI Tool: Comprehensive command-line interface
- Step Logging: Real-time test step tracking
- Single Test Enforcement: One test per file for better organization
- ES6 Module Support: Modern JavaScript syntax
- Headless & Visible Modes: Perfect for CI/CD and local development
📦 Installation
Global Installation (Recommended)
npm install -g jest-e2e@latest
Project Installation
npm install jest-e2e@latest
npx jest-e2e --help
🏃♂️ Quick Start
1. Install and Initialize
mkdir my-e2e-tests
cd my-e2e-tests
npm init -y
npm install jest-e2e@latest
# Just run it - auto-initializes with examples on first run
npx jest-e2e
2. That's it! 🎉
The framework automatically:
- ✅ Detects it's your first run
- ✅ Updates your
package.json
with ES module support and Jest configuration - ✅ Adds helpful npm scripts (
npm run jest-e2e
,npm run jest-e2e:visible
, etc.) - ✅ Creates
__tests__/
,databuilders/
, andconfig/
directories - ✅ Copies example tests and configuration files
- ✅ Sets up global access to Jest E2E functions
- ✅ Installs required dependencies automatically
- ✅ Runs the example tests to show you it works
3. Use the New npm Scripts
After initialization, you can use these convenient scripts:
# Run all E2E tests (headless)
npm run jest-e2e
# Run with visible browser for debugging
npm run jest-e2e:visible
# Run in watch mode
npm run jest-e2e:watch
# Or use the CLI directly with more options
npx jest-e2e --repl
4. Customize for Your App
Edit the example tests in __tests__/
:
// __tests__/my-login-test-e2e.js
test('User can login successfully', async () => {
const { device } = await E2ESetup();
const { userEmail, userPassword } = getTestData();
await device.navigate('https://your-app.com/login'); // 👈 Change URL
await device.fill('#email', userEmail); // 👈 Update selectors
await device.fill('#password', userPassword);
await device.click('#login-button');
await device.waitForSelector('.dashboard');
expect(await device.getInnerText('.welcome')).toContain('Welcome');
});
🎯 CLI Usage
jest-e2e [test_name] [options]
Options
--useLocalBrowser true
- Run with visible browser--repl
- Keep browser open after test completion--debug
- Enable debug mode--watch
- Watch mode for development--verbose
- Detailed output--timeout <ms>
- Custom timeout (default: 30000)--slowmo <ms>
- Add delay between actions--screenshot
- Take screenshots on failure--silent
- No step logging--help
- Show help
Examples
# Run all tests in headless mode
jest-e2e
# Run specific test with visible browser
jest-e2e login-success --useLocalBrowser true
# Debug mode with step logging
jest-e2e payment-flow --debug --verbose
# Keep browser open for inspection
jest-e2e checkout-process --repl
# Slow motion for demonstrations
jest-e2e user-journey --slowmo 500 --useLocalBrowser true
🔧 API Reference
E2ESetup()
Main setup function that configures test environment with data builders and devices:
const { getTestData, getDevices } = E2ESetup({
databuilder: AgentTestDataBuilder(),
devices: {
device: createChromeE2EApi({}),
},
});
// Use in your tests
const { device } = getDevices();
const { userEmail, userPassword } = getTestData();
Device API
Built-in browser automation methods:
// Navigation
await device.navigate(url);
await device.goBack();
await device.refresh();
// Interactions
await device.click(selector);
await device.fill(selector, value);
await device.select(selector, value);
await device.hover(selector);
// Waiting
await device.waitForSelector(selector);
await device.waitForTimeout(ms);
// Information
const text = await device.getInnerText(selector);
const value = await device.getValue(selector);
const isVisible = await device.isVisible(selector);
Data Builders
Generate test data with inheritance:
// Import in your test files
import { AgentTestDataBuilder } from '../databuilders/agent-test-data-builder.js';
// Get test data (available globally in tests)
const { userEmail, userPassword } = getTestData();
// Custom data builder
export function myCustomDataBuilder() {
return {
...baseDataBuilder(),
customField: 'custom value',
genImp() { return 'custom-implementation'; },
getVersion() { return '1.0.0'; }
};
}
Step Logging
Track test progress (available globally):
logStep('Navigating to login page');
logStep('Filling user credentials');
logStep('Submitting login form');
📁 Project Structure
After running npx jest-e2e
for the first time, your project will have:
your-project/
├── __tests__/ # Your E2E tests (auto-created with examples)
│ ├── example-login-success-e2e.js
│ ├── example-login-invalid-e2e.js
│ └── example-form-validation-e2e.js
├── databuilders/ # Test data builders (auto-created)
│ ├── base-data-builder.js
│ └── agent-test-data-builder.js
├── config/ # Configuration files (auto-created)
│ └── test-setup.js # Global Jest E2E setup
├── jest-puppeteer.config.js # Puppeteer configuration (auto-created)
└── package.json # Updated with ES modules & Jest config
Auto-Generated Files: The framework automatically creates all necessary files:
- Example Tests: Three example tests showing different patterns
- Data Builders: Base and example data builders for test data generation
- Configuration: Jest setup and Puppeteer configuration
- Package Configuration: Your package.json gets updated with proper ES module and Jest settings
🏗️ Custom Configuration
Automatic Package.json Updates
When you run npx jest-e2e
for the first time, the framework automatically updates your package.json
with:
{
"type": "module", // Enables ES6 imports
"scripts": {
"test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest",
"jest-e2e": "jest-e2e", // Convenient E2E scripts
"jest-e2e:visible": "jest-e2e --useLocalBrowser true",
"jest-e2e:watch": "jest-e2e --watch"
},
"jest": { // Jest configuration for E2E
"preset": "jest-puppeteer",
"testMatch": ["**/*-e2e.js"],
"testTimeout": 30000,
"setupFilesAfterEnv": ["./config/test-setup.js"]
},
"devDependencies": { // Required testing dependencies
"jest": "^29.7.0",
"puppeteer": "^24.9.0",
"jest-puppeteer": "^11.0.0"
}
}
This automatic configuration eliminates the need for manual setup and ensures everything works out of the box!
Custom Puppeteer Configuration
Create jest-puppeteer.config.js
:
export default {
launch: {
headless: process.env.CI === 'true',
defaultViewport: { width: 1280, height: 720 },
args: ['--no-sandbox', '--disable-setuid-sandbox']
},
server: {
command: 'npm start',
port: 3000,
launchTimeout: 10000
}
};
🎯 Writing Tests
Basic Test Structure
Since Jest E2E functions are globally available, you can write tests without imports:
/* eslint-disable no-undef */
"use strict";
// Import your specific data builders
import { AgentTestDataBuilder } from '../databuilders/agent-test-data-builder.js';
const { getTestData, getDevices } = E2ESetup({
databuilder: AgentTestDataBuilder(),
devices: {
device: createChromeE2EApi({}),
},
});
test("User can complete checkout", async () => {
const { device } = getDevices();
const { userEmail, userPassword } = getTestData();
logStep('Navigate to login page');
await device.navigate("https://your-app.com/login");
logStep('Fill login credentials');
await device.type("#email", userEmail);
await device.type("#password", userPassword);
logStep('Submit login form');
await device.click("#login-button");
// Verify success
await device.expect("body").toContain("Dashboard");
});
Single Test Rule
Each test file must contain exactly one test function:
// ✅ Good - one test per file
test('User can complete checkout', async () => {
// test implementation
});
// ❌ Bad - multiple tests in one file
test('Test 1', async () => {});
test('Test 2', async () => {}); // This will throw an error
Test File Naming
Use -e2e.js
suffix for test files:
login-success-e2e.js
user-registration-e2e.js
payment-flow-e2e.js
Data Builder Pattern
// databuilders/user-data-builder.js
export function userDataBuilder() {
return {
...baseDataBuilder(), // Available globally
userEmail: 'test@example.com',
userPassword: 'password123',
userFullName: 'Test User',
genImp() {
return 'user-builder-v1';
},
getVersion() {
return '1.0.0';
}
};
}
🎯 Best Practices
1. Use Descriptive Test Names
test('User can login with valid credentials and access dashboard', async () => {
// test implementation
});
2. Implement Page Object Pattern
class LoginPage {
constructor(device) {
this.device = device;
}
async login(email, password) {
await this.device.type('#email', email);
await this.device.type('#password', password);
await this.device.click('#login-button');
}
}
3. Use Step Logging
test('Complete user journey', async () => {
const { device } = await E2ESetup();
logStep('Navigate to homepage');
await device.navigate('https://example.com');
logStep('Click sign up button');
await device.click('#signup');
logStep('Fill registration form');
// form filling...
});
🐛 Debugging
Visual Debugging
# Run with visible browser
jest-e2e my-test --useLocalBrowser true
# Keep browser open for inspection
jest-e2e my-test --repl
# Slow motion for better visibility
jest-e2e my-test --slowmo 1000 --useLocalBrowser true
Debug Mode
# Enable debug output
jest-e2e my-test --debug --verbose
Screenshots
# Take screenshots on failure
jest-e2e my-test --screenshot
📊 CI/CD Integration
GitHub Actions
name: E2E Tests
on: [push, pull_request]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npx jest-e2e --silent
GitLab CI
e2e_tests:
image: node:18
script:
- npm install
- npx jest-e2e --silent
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
📄 License
MIT License - see LICENSE file for details.
🆘 Support
Made with ❤️ for the testing community