Test utilities for Digital Defiance Express Suite projects.
Part of Express Suite
npm install @digitaldefiance/express-suite-test-utils
# or
yarn add @digitaldefiance/express-suite-test-utilsTest helpers and mocks are available via separate /testing entry points:
// node-express-suite test helpers
import {
createApplicationMock,
setupTestEnv
} from '@digitaldefiance/node-express-suite/testing';
// node-ecies-lib test mocks
import { mockBackendMember } from '@digitaldefiance/node-ecies-lib/testing';
// ecies-lib test mocks
import { mockFrontendMember } from '@digitaldefiance/ecies-lib/testing';
// Use in your tests
beforeAll(async () => {
await setupTestEnv();
});Note: All /testing entry points require @faker-js/faker as a peer dependency:
npm install -D @faker-js/faker
# or
yarn add -D @faker-js/fakerCustom Jest matcher for testing error types with optional validation:
import '@digitaldefiance/express-suite-test-utils';
class CustomError extends Error {
constructor(public code: number) {
super('Custom error');
}
}
// Basic usage
expect(() => {
throw new CustomError(404);
}).toThrowType(CustomError);
// With validator
expect(() => {
throw new CustomError(404);
}).toThrowType(CustomError, (error) => {
expect(error.code).toBe(404);
});import { ErrorClass } from '@digitaldefiance/express-suite-test-utils';
function testError<E extends Error>(ErrorType: ErrorClass<E>) {
// Use ErrorType constructor
}Mock console methods in tests:
import { withConsoleMocks, spyContains } from '@digitaldefiance/express-suite-test-utils';
it('should log message', async () => {
await withConsoleMocks({ mute: true }, async (spies) => {
console.log('test message');
expect(spies.log).toHaveBeenCalledWith('test message');
expect(spyContains(spies.log, 'test', 'message')).toBe(true);
});
});Mock fs.writeSync for testing direct console output:
import { withDirectLogMocks, directLogContains, getDirectLogMessages } from '@digitaldefiance/express-suite-test-utils';
import * as fs from 'fs';
// Important: Mock fs module at module level before importing
jest.mock('fs', () => ({
...jest.requireActual('fs'),
writeSync: jest.fn(),
}));
it('should capture direct writes to stdout', async () => {
await withDirectLogMocks({ mute: true }, async (spies) => {
const buffer = Buffer.from('hello world\n', 'utf8');
fs.writeSync(1, buffer); // stdout
expect(directLogContains(spies.writeSync, 1, 'hello', 'world')).toBe(true);
expect(getDirectLogMessages(spies.writeSync, 1)).toEqual(['hello world\n']);
});
});In-memory MongoDB testing utilities using mongodb-memory-server:
import { connectMemoryDB, disconnectMemoryDB, clearMemoryDB } from '@digitaldefiance/express-suite-test-utils';
import { User } from './models/user';
describe('User model', () => {
beforeAll(async () => {
await connectMemoryDB();
});
afterAll(async () => {
await disconnectMemoryDB();
});
afterEach(async () => {
await clearMemoryDB();
});
it('should validate user schema', async () => {
const user = new User({ username: 'test', email: 'test@example.com' });
await user.validate(); // Real Mongoose validation!
await expect(async () => {
const invalid = new User({ username: 'ab' }); // too short
await invalid.validate();
}).rejects.toThrow();
});
});Note: Requires mongoose as a peer dependency and mongodb-memory-server as a dependency (already included).
This package provides comprehensive testing utilities for Express Suite projects, including custom Jest matchers, console mocks, database helpers, and more.
Custom Matchers: toThrowType for type-safe error testing
Console Mocks: Mock and spy on console methods
Direct Log Mocks: Mock fs.writeSync for stdout/stderr testing
Database Helpers: MongoDB Memory Server integration
React Mocks: Mock React components and hooks
import '@digitaldefiance/express-suite-test-utils';
class CustomError extends Error {
constructor(public code: number) {
super('Custom error');
}
}
describe('Error Testing', () => {
it('should throw specific error type', () => {
expect(() => {
throw new CustomError(404);
}).toThrowType(CustomError);
});
it('should validate error properties', () => {
expect(() => {
throw new CustomError(404);
}).toThrowType(CustomError, (error) => {
expect(error.code).toBe(404);
});
});
});import { withConsoleMocks, spyContains } from '@digitaldefiance/express-suite-test-utils';
describe('Console Output', () => {
it('should capture console.log', async () => {
await withConsoleMocks({ mute: true }, async (spies) => {
console.log('test message');
expect(spies.log).toHaveBeenCalledWith('test message');
expect(spyContains(spies.log, 'test', 'message')).toBe(true);
});
});
it('should capture console.error', async () => {
await withConsoleMocks({ mute: true }, async (spies) => {
console.error('error message');
expect(spies.error).toHaveBeenCalledWith('error message');
});
});
});import { withDirectLogMocks, directLogContains, getDirectLogMessages } from '@digitaldefiance/express-suite-test-utils';
import * as fs from 'fs';
// Mock fs at module level
jest.mock('fs', () => ({
...jest.requireActual('fs'),
writeSync: jest.fn(),
}));
describe('Direct Logging', () => {
it('should capture stdout writes', async () => {
await withDirectLogMocks({ mute: true }, async (spies) => {
const buffer = Buffer.from('hello world\n', 'utf8');
fs.writeSync(1, buffer); // stdout
expect(directLogContains(spies.writeSync, 1, 'hello', 'world')).toBe(true);
expect(getDirectLogMessages(spies.writeSync, 1)).toEqual(['hello world\n']);
});
});
});import { connectMemoryDB, disconnectMemoryDB, clearMemoryDB } from '@digitaldefiance/express-suite-test-utils';
import { User } from './models/user';
describe('Database Tests', () => {
beforeAll(async () => {
await connectMemoryDB();
});
afterAll(async () => {
await disconnectMemoryDB();
});
afterEach(async () => {
await clearMemoryDB();
});
it('should validate user schema', async () => {
const user = new User({
username: 'test',
email: 'test@example.com'
});
await user.validate(); // Real Mongoose validation!
await user.save();
const found = await User.findOne({ username: 'test' });
expect(found).toBeDefined();
});
it('should reject invalid data', async () => {
const invalid = new User({ username: 'ab' }); // too short
await expect(invalid.validate()).rejects.toThrow();
});
});- Always clean up after tests (disconnect DB, restore mocks)
- Use memory database for fast, isolated tests
- Mock external dependencies to avoid side effects
- Test error conditions with
toThrowTypematcher - Capture console output when testing logging behavior
These utilities are designed to work seamlessly with all Express Suite packages:
import { connectMemoryDB, disconnectMemoryDB } from '@digitaldefiance/express-suite-test-utils';
import { Application } from '@digitaldefiance/node-express-suite';
import { UserService } from '@digitaldefiance/node-express-suite';
describe('Integration Tests', () => {
let app: Application;
beforeAll(async () => {
await connectMemoryDB();
app = new Application({
mongoUri: global.__MONGO_URI__,
jwtSecret: 'test-secret'
});
});
afterAll(async () => {
await app.stop();
await disconnectMemoryDB();
});
it('should create and find user', async () => {
const userService = new UserService(app);
const user = await userService.create({
username: 'alice',
email: 'alice@example.com'
});
const found = await userService.findByUsername('alice');
expect(found).toBeDefined();
});
});MIT
- Fix mongoose to use @digitaldefiance/mongoose-types
- Fix direct-log mocks to work with non-configurable fs.writeSync in newer Node.js versions
- Add comprehensive mongoose memory database testing utilities
- Fix memory mongoose connectMemoryDB
- Add mongoose memory helpers
- Add directLog mocks
- Add react mocks
- Add secp256k to BSON mock
- Add BSON mock
- Add jest global declaration for toThrowType
- Add LocalStorageMock
- Bugfix release, fixing lack of js files in tarball
- Initial Release