qtests
v4.2.2
Published
Node.js testing framework, Node.js stubbing, method stubbing, ESM testing, console mocking, environment management, ESM and TypeScript support, circuit breaker utilities, security validation, jest HTTP mocking, and auto test generation
Maintainers
Readme
qtests
A comprehensive Node.js toolkit covering the full testing lifecycle and production reliability in a single dependency. Stub methods, mock modules and HTTP, test security and performance, generate integration tests automatically, and ship circuit breakers, caching, and rate limiting — all with first-class ES Module and TypeScript support.
Latest Updates (v4.2.0 — April 2026):
npx qtests-generatenow writes integration test stubs undertests/integration/for every discovered source file — non-destructively- After scaffolding, a ready-to-paste AI agent prompt is printed with three clear instructions: prune stubs that don't map to real workflows, fill in the ones that do, and leave the runner alone
- Source discovery covers 11 common layouts out of the box:
src,lib,bin,scripts,utils,pages,app,routes,controllers,packages,api - Generator output is now compact (3 summary lines instead of one line per file)
- Fixed: old v1.x binary no longer shadows the current generator when
qerrorsis installed as a dependency
v4.0.0 — April 2026:
- Security testing module:
SecurityValidator,JoiSecurityValidator, andPenetrationTesterwith full TypeScript types - Circuit breaker API:
createCircuitBreaker(options),executeWithCircuitBreaker(fn, options),getCircuitBreakerStats(),resetCircuitBreaker(),CircuitStateenum - File system utilities:
safeExistsandsafeDeletefor safe file operations in tests - Mocking improvements:
restoreAll()andverifyCallCount()for cleaner test teardown - Dual commercial licensing: free for individual developers, paid tiers for teams and companies
- Structured run-results file emitted after every test run for CI artifact ingestion
Quick Start
npm install qtests --save-devEnvironment variables
qtests uses qerrors for AI-powered error analysis and debugging suggestions. Set one of the following in your environment (or a .env file) before running tests:
OPENAI_API_KEY=sk-... # OpenAI GPT models
# or
GEMINI_API_KEY=... # Google Gemini modelsqerrors degrades gracefully if neither key is set — errors are still logged, but without AI-generated suggestions. For local development you can omit both and everything will still work.
Generate tests for your project
Point qtests at your source code and it will discover your files and write integration test stubs for you:
npx qtests-generateThis scaffolds qtests-runner.mjs, config/jest.config.mjs, and setup files, then scans your project for source files across the common source directories (src, lib, bin, scripts, utils, pages, app, routes, controllers, packages, api) and writes a stub under tests/integration/ for each one — non-destructively, so existing test files are never overwritten.
After scaffolding, the generator prints a ready-to-paste AI agent prompt that tells your AI to delete stubs that don't map to real workflows, flesh out the ones that do, and leave the runner configuration alone.
# Preview what would be generated without writing any files
npx qtests-generate --dry-run
# Regenerate and overwrite existing stubs
npx qtests-generate --force
# Suppress the AI prompt (useful in CI)
QTESTS_SUPPRESS_PROMPT=1 npx qtests-generateqtests can scaffold its Jest runner/config into your project root via npx qtests-generate (non-destructive by default). The runner expects Jest to be installed in your project (as a devDependency).
Setup: (Jest: loaded globally via config/jest-setup.ts/config/jest-setup.cjs when you use npx qtests-generate; otherwise, put this at the top of each test file before other imports.)
// Enable automatic stubbing (CJS + ESM)
import 'qtests/setup';
// CommonJS:
// require('qtests/setup');
// Import with full type safety
import { stubMethod, mockConsole, testEnv } from 'qtests';
// Use with TypeScript intellisense
const restore = stubMethod(myObject, 'methodName', mockImplementation);Module format note:
qtests(the main API) is ESM-only. In CommonJS tests, useawait import('qtests')to access helpers likestubMethod. The setup entrypoint supports bothimport 'qtests/setup'andrequire('qtests/setup').
Features
Testing
- Auto Test Generation — scans 11 common source directories and writes
tests/integration/stubs for each source file; prints a ready-to-paste AI agent prompt to flesh them out (npx qtests-generate) - Method Stubbing — replace any object method and restore it automatically (
stubMethod,spyOnMethod) - Console Mocking — capture and assert on console output with Jest-compatible spies
- Module Stubs — drop-in replacements for axios and winston; register custom stubs for any module
- HTTP Testing — mock Express apps, chainable supertest-style requests, route test utilities
- Email Mocking — send and inspect emails in tests without an external mail service
- Browser Polyfills —
window,matchMedia,clipboard, and happy-dom for component testing in Node - Test Environment — safe backup and restore of
process.env; offline mode; test isolation helpers - Security Testing —
SecurityValidatorandJoiSecurityValidatorfor input validation, XSS, path traversal, and HTML sanitisation;PenetrationTesterfor automated attack-vector probing - Performance & Load Testing — built-in load runner, performance monitor, memory leak detector, memory pressure simulation
- Validation — schema-based input validation (Joi/Zod), streaming validation, HTML sanitisation middleware
Production Reliability
- Circuit Breaker —
createCircuitBreaker,executeWithCircuitBreaker, state machine withCircuitStateenum - Connection Pooling —
AdvancedConnectionPoolwith health monitoring and metrics - Caching —
CacheManager, local in-process cache, distributed cache adapters - Rate Limiting — token-bucket and flexible rate limiters ready for Express middleware
- Logging — structured Winston-based logging, decorators, convenience wrappers
Developer Experience
- Jest Scaffolding —
npx qtests-generatewrites runner,jest.config.mjs, and setup files non-destructively - Jest Config Factory —
createJestConfigfor standardised TypeScript-ESM, React, and monorepo configs - Error Handling —
handleError,handleAsyncError, typed fallbacks, and async wrappers - File System —
safeReadFile,safeWriteFile,safeExists,safeDelete,ensureDir - ESM + TypeScript — full ES Module loader hook, complete type definitions, intellisense throughout
Mock API (Runtime-Safe)
qtests exposes a small, extensible mocking API that works at runtime without rewriting paths or adding heavy frameworks.
Defaults registered by setup:
axios→ qtests stub (truthy, no network)winston→ qtests stub (no-op logger with format/transports)
Usage:
import qtests from 'qtests';
// Register a custom module mock
qtests.mock.module('external-service', () => ({
default: {
call: async () => ({ ok: true })
}
}));
// Now `require('external-service')` or `import ... from 'external-service'` returns the mock (CJS via require hook; ESM early via optional loader)Notes:
- Activation is runtime-safe: a single require hook returns registered mocks; previously loaded CJS modules are best-effort evicted from
require.cache. - ESM projects can optionally use the loader for earliest interception:
node --loader=qtests/loader.mjs your-app.mjs
- setup still runs first in Jest via
config/jest-setup.ts(TS) orconfig/jest-setup.cjs(JS-only) so defaults are active before imports.
Core Usage
Method Stubbing
import { stubMethod } from 'qtests';
const myObj = { greet: (name: string) => `Hello, ${name}!` };
// Stub the method
const restore = stubMethod(myObj, 'greet', () => 'Hi!');
console.log(myObj.greet('Brian')); // 'Hi!'
// Restore original
restore();
console.log(myObj.greet('Brian')); // 'Hello, Brian!'Console Mocking
import { mockConsole } from 'qtests';
const spy = mockConsole('log');
console.log('test message');
console.log(spy.mock.calls); // [['test message']]
spy.mockRestore(); // Restore original console.logEnvironment Management
import { testEnv } from 'qtests';
// Set test environment
testEnv.setTestEnv(); // Sets NODE_ENV=test, DEBUG=qtests:*
// Save and restore environment
const saved = testEnv.saveEnv();
process.env.TEST_VAR = 'modified';
testEnv.restoreEnv(saved); // TEST_VAR removed, original state restoredUnified Test Runner (API-Only)
- One command for everyone:
npm test. - One runner:
qtests-runner.mjsruns Jest via the programmatic APIrunCLI(no child processes, notsx). - Honors:
QTESTS_INBAND=1(serial) andQTESTS_FILE_WORKERS=<n>(max workers). - Always uses project config and
passWithNoTests, withcache=trueandcoverage=false. - Debugging: creates
DEBUG_TESTS.mdon failures; override withQTESTS_DEBUG_FILE=pathor suppress withQTESTS_SUPPRESS_DEBUG=1. - Security tests run automatically after Jest. Skip them for fast local iteration with
QTESTS_SKIP_SECURITY=true npm test.
Runner availability and generator behavior:
- Run
npx qtests-generateonce to scaffoldqtests-runner.mjsand Jest config files if missing:config/jest.config.mjs(ignoresdist/,build/)config/jest-require-polyfill.cjs(ensuresrequire(...)is available in ESM tests)config/jest-setup.ts(TS) orconfig/jest-setup.cjs(JS-only); both loadqtests/setupfirst and register Jest mocks foraxios/winston
- Use
--forceto overwrite existing scaffolded files. - Use
--update-pkg-scriptto setpackage.jsonscripts.testtonode qtests-runner.mjs. - Use
--auto-installto installts-jest+typescriptas devDependencies if missing.
Runner/Config Scaffolding
CLI Usage
# Scaffold runner + Jest config (non-destructive)
npx qtests-generate
# Preview planned writes
npx qtests-generate --dry-run
# Overwrite existing scaffolded files
npx qtests-generate --force
# Update package.json scripts.test to use the runner
npx qtests-generate --update-pkg-script
# Install ts-jest + typescript if missing
npx qtests-generate --auto-installCustom Module Stubs (Advanced)
When you need to stub a niche dependency (beyond the built-ins axios/winston) without changing qtests itself, register a custom stub in tests:
// Always load setup first so axios/winston are stubbed globally
import 'qtests/setup';
// Then register your ad-hoc stub(s)
import { registerModuleStub } from 'qtests/utils/customStubs';
registerModuleStub('external-service-client', {
ping: () => 'pong',
get: async () => ({ ok: true })
});
// Now this resolves to your in-memory stub even if the module is not installed
const client = require('external-service-client');
await client.get(); // { ok: true }Module Stubs
Axios Stub
// Automatic when using qtests/setup (for require()-based resolution)
import 'qtests/setup';
const axios = require('axios');
const response = await axios.get('/api');
// Returns: { data: {}, status: 200, statusText: 'OK', headers: {}, config: {} }
await axios.post('/api', data); // Enhanced response formatWinston Stub
// Automatic when using qtests/setup (for require()-based resolution)
import 'qtests/setup';
const winston = require('winston');
const logger = winston.createLogger();
logger.info('This produces no output'); // SilentCustom Module Stubs (Ad-Hoc)
When you need to stub a niche dependency (beyond the built-ins axios/winston) without changing qtests itself, register a custom stub in tests:
// Always load setup first so axios/winston are stubbed globally
import 'qtests/setup';
// Then register your ad-hoc stub(s)
import { registerModuleStub } from 'qtests/utils/customStubs';
registerModuleStub('external-service-client', {
ping: () => 'pong',
get: async () => ({ ok: true })
});
// Now this resolves to your in-memory stub even if the module is not installed
const client = require('external-service-client');
await client.get(); // { ok: true }Notes:
- Call
registerModuleStubBEFORE the first require/import of that module. - Use
unregisterModuleStub(id)andclearAllModuleStubs()for cleanup in afterEach. - Honors
QTESTS_SILENT=1|trueto reduce noise in CI logs.
Lightweight Test Runner
import { runTestSuite, createAssertions } from 'qtests';
const assert = createAssertions();
const tests = {
'basic test': () => {
assert.equals(1 + 1, 2);
assert.isTrue(true);
},
'async test': async () => {
const result = await Promise.resolve('done');
assert.equals(result, 'done');
}
};
runTestSuite('My Tests', tests);HTTP Testing
// For generated API tests, a local shim is scaffolded at:
// tests/generated-tests/utils/httpTest.ts (re-exports a JS shim)
// tests/generated-tests/utils/httpTest.shim.js (implementation with .send())
// You can also import the same helpers directly from qtests if preferred.
import { httpTest } from 'qtests/lib/envUtils.js';
// Create mock Express app
const app = httpTest.createMockApp();
app.get('/users', (req, res) => {
res.statusCode = 200;
res.end(JSON.stringify({ users: [] }));
});
// Test the app — chainable .send() supported; JSON is defaulted and parsed
const response = await httpTest.supertest(app)
.get('/users')
.expect(200)
.end();Email Testing
import { sendEmail } from 'qtests/lib/envUtils.js';
// Mock email sending
const result = await sendEmail.send({
to: '[email protected]',
subject: 'Welcome',
text: 'Welcome to our app!'
});
console.log(result.success); // true
console.log(sendEmail.getHistory()); // Array of sent emailsAdvanced Features
Error Handling Utilities
import { handleError, handleAsyncError } from 'qtests/lib/errorHandling.js';
// Synchronous error handling with logging
try {
riskyOperation();
} catch (error) {
handleError(error, 'operation-context', {
logToConsole: true,
includeStack: true,
fallbackMessage: 'Operation failed'
});
}
// Async error handling with fallback
const result = await handleAsyncError(
riskyAsyncOperation(),
'async-operation',
{ fallbackValue: null }
);
if (result === null) {
console.log('Operation failed but was handled gracefully');
}Circuit Breaker Pattern
import { createCircuitBreaker, executeWithCircuitBreaker, CircuitState } from 'qtests';
// Create a reusable breaker configured with thresholds
const breaker = createCircuitBreaker({
failureThreshold: 5,
resetTimeout: 60000,
timeout: 10000,
onStateChange: (state: CircuitState) => {
console.log('Circuit state changed:', state);
}
});
// Or wrap a one-off call without creating a named breaker
const result = await executeWithCircuitBreaker(
async () => externalService.process(userData),
{ timeout: 5000, failureThreshold: 3 }
);Connection Pool Health Monitoring
import { addHealthMonitoring, createHealthMonitoredPool } from 'qtests/lib/connectionPoolHealth.js';
// Add health monitoring to existing pool
const pool = createDatabasePool();
const monitor = addHealthMonitoring(pool, {
healthCheckInterval: 30000, // 30 seconds
unhealthyConnectionThreshold: 3,
enableDetailedLogging: true
});
// Listen to health events
monitor.on('health-check-completed', (status) => {
console.log(`Healthy: ${status.healthyConnections}/${status.totalConnections}`);
});
monitor.on('connection-unhealthy', (data) => {
alertingService.sendAlert('Database connection unhealthy', data);
});
// Start monitoring
monitor.startHealthMonitoring();Jest Configuration Factory
import { createJestConfig } from 'qtests/lib/jestConfigFactory.js';
// Standardized Jest configurations
const config = createJestConfig('typescript-esm', {
coverageDirectory: 'coverage',
collectCoverageFrom: ['src/**/*.ts'],
testEnvironment: 'node'
});
// For React projects
const reactConfig = createJestConfig('react-typescript', {
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
testEnvironment: 'jsdom'
});
// Write to jest.config.mjs
import { writeFileSync } from 'fs';
writeFileSync('jest.config.mjs', `export default ${JSON.stringify(config, null, 2)};`);Offline Mode
import { offlineMode } from 'qtests';
// Enable offline mode
offlineMode.setOfflineMode(true);
// Get stubbed axios automatically
const axios = offlineMode.getAxios();
await axios.get('/api/data'); // Returns {} instead of real requestIntegration with Jest
import { testHelpers } from 'qtests';
test('console output', async () => {
await testHelpers.withMockConsole('log', (spy) => {
console.log('test');
expect(spy.mock.calls[0][0]).toBe('test');
});
});API Reference
Core Methods
| Method | Description |
|--------|-------------|
| stubMethod(obj, methodName, replacement) | Replace object method with stub |
| mockConsole(method) | Mock console methods with spy |
| testEnv.setTestEnv() | Set standard test environment |
| testEnv.saveEnv() / restoreEnv() | Backup/restore environment |
| offlineMode.setOfflineMode(enabled) | Toggle offline mode |
| handleError(error, context, options) | Comprehensive error handling |
| handleAsyncError(promise, context, options) | Async error handling with fallback |
Scaffolding CLI
| Tool | Description |
|------|-------------|
| CLI: npx qtests-generate | Scaffold qtests-runner.mjs + Jest config (config/jest.config.mjs, config/jest-setup.ts or config/jest-setup.cjs, config/jest-require-polyfill.cjs) |
Test Runner
| Method | Description |
|--------|-------------|
| runTestSuite(name, tests) | Execute test suite |
| createAssertions() | Get assertion methods |
Error Handling & Performance
| Method | Description |
|--------|-------------|
| handleError(error, context, options?) | Handle and log errors with context |
| handleAsyncError(promise, context, options?) | Async error handling with fallback |
| createCircuitBreaker(options) | Create a circuit breaker instance |
| executeWithCircuitBreaker(fn, options) | Wrap a one-off call with circuit breaker protection |
| getCircuitBreakerStats(breaker) | Get failure count, state, and success rate |
| resetCircuitBreaker(breaker) | Reset breaker to CLOSED state |
| addHealthMonitoring(pool, options) | Add health monitoring to pools |
| createJestConfig(type, options) | Generate standardized Jest config |
Advanced Utilities
| Method | Description |
|--------|-------------|
| registerModuleStub(name, exports) | Register custom module stub |
| runTestSuites(suites, options) | Run multiple test suites |
| initializePolyfills() | Initialize browser polyfills |
| polyfillOrchestrator() | Manage polyfill lifecycle |
TypeScript Configuration
To run ESM tests, set "type": "module" in your project package.json (or use .mjs), and ensure your tsconfig.json supports Node ESM (NodeNext recommended):
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"ts-node": {
"esm": true
}
}Import Patterns
// Core utilities with full type safety
import qtests, { stubMethod, mockConsole, testEnv, mock } from 'qtests';
// Custom module stubs (no ".js" suffix in subpath imports)
import { registerModuleStub } from 'qtests/utils/customStubs';
// Module stubs (still available)
import { stubs } from 'qtests';
await stubs.axios.get('https://example.com');Browser Testing Polyfills
// For React/browser component testing
import {
initializePolyfills,
getWindow,
matchMedia,
clipboard
} from 'qtests';
// Set up browser environment
initializePolyfills();
// Now you have access to browser APIs in Node.js tests
const window = getWindow();
window.innerWidth = 1024;
const mediaQuery = matchMedia('(max-width: 768px)');
clipboard.writeText('test text');Philosophy
qtests is built around one idea: a team should be able to add a single dependency and cover the entire testing lifecycle without assembling a patchwork of separate libraries. That means unit tests with stubs and mocks, integration tests against real HTTP routes, security probing, performance benchmarking, and browser-environment component tests — all in one package.
The production reliability utilities (circuit breaker, connection pooling, caching, rate limiting) are included because testing those patterns well requires realistic implementations, not hollow mocks. Shipping them in qtests means you can test your resilience logic against the same code you run in production.
CLI Reference
qtests-generate (Scaffolder)
- Usage:
qtests-generate [--dry-run] [--force] [--update-pkg-script] [--auto-install] - Alias:
qtests-ts-generate - Purpose: Scaffolds
qtests-runner.mjsand Jest config files into the client project (INIT_CWD). - Options:
--dry-run: Print planned writes without modifying files--force: Overwrite existing scaffolded files--update-pkg-script: Setpackage.jsonscripts.testtonode qtests-runner.mjs--auto-install: Installts-jest+typescriptas devDependencies if missing-h, --help: Show help-v, --version: Show version
Examples:
qtests-generateqtests-generate --dry-runqtests-generate --forceqtests-generate --update-pkg-scriptqtests-generate --auto-install
Notes:
- This CLI scaffolds runner/config files; it does not generate tests.
qtests runner
- Usage:
qtests-ts-runner - Purpose: Discovers and runs tests in the project with a Jest-first strategy.
- Behavior:
- Discovers files matching
.test|.spec|_test|_specwith.js|.ts|.jsx|.tsx - Runs Jest via the programmatic API (
runCLI) (no child processes, notsx) - Runs tests in parallel batches (controlled by
QTESTS_INBAND,QTESTS_FILE_WORKERS,QTESTS_CONCURRENCY)
- Discovers files matching
- Notes:
qtests-runner.mjsis scaffolded into the client project byqtests-generate(or install-time scaffolding)- Always passes
--config config/jest.config.mjsand--passWithNoTests - Honors
QTESTS_SUPPRESS_DEBUG=1|trueto skip creatingDEBUG_TESTS.md - Honors
QTESTS_DEBUG_FILEto set a custom debug report path/name - Honors
QTESTS_SKIP_SECURITY=1|trueto skip the security test suite (useful for fast local iteration) - Records Jest argv to
runner-jest-args.jsonto aid debugging - If
ts-jest+typescriptare installed, the scaffolded Jest config enables TypeScript ESM transforms
Best Practices
1. Always Load Setup First
// Correct
import 'qtests/setup';
import myModule from './myModule.js';
// Wrong
import myModule from './myModule.js';
import 'qtests/setup';2. Clean Up After Tests
test('example', () => {
const restore = stubMethod(obj, 'method', stub);
const spy = mockConsole('log');
// ... test code ...
// Always restore
restore();
spy.mockRestore();
});3. Use Environment Helpers
import { testHelpers } from 'qtests';
test('environment test', async () => {
await testHelpers.withSavedEnv(async () => {
process.env.TEST_VAR = 'value';
// Environment automatically restored
});
});Testing Patterns & Organization
Test File Types
qtests supports multiple testing patterns depending on your needs:
| Pattern | When to Use | File Location |
|---------|-------------|---------------|
| Unit Tests | Testing individual functions/classes | src/module.test.ts or tests/unit/ |
| Integration Tests | Testing API routes and service interactions | tests/integration/ or tests/generated-tests/ |
| Manual Tests | Complex scenarios requiring custom setup | tests/manual-tests/ |
| Performance Tests | Benchmarking and load testing | tests/performance/ |
| End-to-End Tests | Full application workflows | tests/e2e/ |
Choosing Test Patterns
// Unit test - test individual functions
import 'qtests/setup';
import { calculateTotal } from './billing.js';
test('calculates total with tax', () => {
const total = calculateTotal(100, 0.1);
expect(total).toBe(110);
});
// Integration test - test API endpoints
import { createMockApp, supertest } from '../utils/httpTest.js';
import billingRoutes from './billingRoutes.js';
describe('POST /api/billing/calculate', () => {
it('should calculate total with discounts', async () => {
const app = createMockApp();
app.use('/api/billing', billingRoutes);
const response = await supertest(app)
.post('/api/billing/calculate')
.send({ amount: 100, discount: 0.2 })
.expect(200);
expect(response.body.total).toBe(80);
});
});Test Environment Setup
// Global test setup (setupTests.ts)
import 'qtests/setup';
import { testEnv } from 'qtests';
// Set up test environment before all tests
beforeAll(() => {
testEnv.setTestEnv();
});
// Clean up after all tests
afterAll(() => {
testEnv.restoreEnv();
});Troubleshooting
| Issue | Solution |
|-------|----------|
| Stubs not working (CommonJS) | Ensure require('qtests/setup') is called first |
| Stubs not working (ES Modules) | Ensure import 'qtests/setup' is called first |
| TypeScript import errors | Add "type": "module" to package.json and update tsconfig.json |
| ES Module syntax errors | Ensure "module": "ES2020" in tsconfig.json |
| Console pollution | Use mockConsole() to capture output |
| Environment leaks | Use testHelpers.withSavedEnv() for isolation |
| Module not found for advanced features | Use qtests subpath exports without a .js suffix (e.g. qtests/lib/errorHandling) |
| CLI not found | Use npx qtests-generate (alias: qtests-ts-generate) or install globally |
| File extension errors | For qtests subpath imports, omit the .js suffix (e.g. qtests/utils/customStubs) |
| generateKey returns empty string | Fixed in latest version - now correctly returns test keys like "test-api-key-user" |
| Circuit breaker not opening | Check error threshold settings and ensure proper error handling |
| Health monitoring not working | Ensure pool.start() is called before adding health monitoring |
| Performance tests timing out | Increase timeout in Jest config or reduce test duration |
| Custom module stubs not loading | Call registerModuleStub() before importing the target module |
Enterprise Integration
CI/CD Pipeline Integration
# GitHub Actions example
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Generate tests
run: npx qtests-generate --force --update-pkg-script
- name: Run tests
run: npm test
- name: Performance tests
run: npm run test:performance
- name: Upload coverage
uses: codecov/codecov-action@v3# Jenkins Pipeline example
pipeline {
agent any
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Generate Tests') {
steps {
sh 'npx qtests-generate --force'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Performance') {
steps {
sh 'npm run test:scalability'
}
}
}
}Large Codebase Strategies
// jest.config.mjs for monorepos
export default {
projects: [
{
displayName: 'frontend',
testMatch: ['<rootDir>/packages/frontend/**/*.test.ts'],
setupFilesAfterEnv: ['<rootDir>/packages/frontend/setupTests.ts'],
moduleNameMapper: {
'^@shared/(.*)$': '<rootDir>/packages/shared/$1'
}
},
{
displayName: 'backend',
testMatch: ['<rootDir>/packages/backend/**/*.test.ts'],
setupFilesAfterEnv: ['<rootDir>/packages/backend/setupTests.ts']
},
{
displayName: 'generated-tests',
testMatch: ['<rootDir>/tests/generated-tests/**/*.test.ts'],
testTimeout: 30000 // Longer timeout for integration tests
}
]
};# Scripts for large projects
# package.json
{
"scripts": {
"test:unit": "jest --testPathPattern=packages/*/src/**/*.test.ts",
"test:integration": "jest --testPathPattern=tests/generated-tests",
"test:performance": "jest --testPathPattern=tests/performance",
"test:all": "npm run test:unit && npm run test:integration && npm run test:performance",
"test:watch": "jest --watch --testPathPattern=packages",
"test:coverage": "jest --coverage --coverageReporters=text-lcov | coveralls"
}
}Team Adoption Guidelines
- Start Small: Begin with unit tests for new features
- Gradual Expansion: Add integration tests for critical API endpoints
- Performance Baselines: Establish performance benchmarks early
- Code Review: Require test coverage in pull requests
- Documentation: Maintain test patterns in team wikis
Monitoring & Alerting
// tests/monitoring/setup.js
import { addHealthMonitoring } from 'qtests/lib/connectionPoolHealth.js';
import { createCircuitBreaker } from 'qtests/lib/circuitBreaker.js';
// Global health monitoring for test environments
if (process.env.NODE_ENV === 'test') {
const pool = global.databasePool;
const monitor = addHealthMonitoring(pool, {
healthCheckInterval: 15000,
unhealthyConnectionThreshold: 2
});
monitor.on('health-check-completed', (status) => {
if (status.unhealthyConnections > 0) {
console.warn(`Test database has ${status.unhealthyConnections} unhealthy connections`);
}
});
}Additional Resources
Configuration Examples
- Jest Configuration Factory - Standardized configs for different project types
- Test Setup Patterns - Reusable test environment setups
- Error Handling Patterns - Comprehensive error handling examples
Advanced Features
- Connection Pool Health - Detailed health monitoring guide
- Performance Testing - Performance testing utilities and examples
Community & Support
- Issue Templates - Standardized issue reporting
- API Documentation - Complete API reference and examples
- Advanced Features - Error handling, performance testing, circuit breakers
- Enterprise Integration - CI/CD patterns and production deployment
- Troubleshooting - Common issues and solutions
License
Dual license — see LICENSE and COMMERCIAL_LICENSE.md for details.
Free for individual developers. Teams and companies require a paid Commercial License (Startup $99/yr, Team $499/yr, Business $1,999/yr). Open source projects may qualify for the free tier — see the Open Source Exception in LICENSE.
Contributing
Contributions welcome! Please feel free to submit issues and pull requests.
