@embedunit/core
v0.5.0
Published
Tiny test runner core for embedded JavaScript runtimes
Maintainers
Readme
@embedunit/core
Test runner core for embedded JavaScript runtimes. Provides a Jest/JUnit-style API (describe, it, hooks) designed to run inside engines, SDKs, and other non-Node environments.
Installation
npm install @embedunit/coreBasic Usage
import { describe, it, runTests } from '@embedunit/core';
describe('Calculator', () => {
it('adds numbers', () => {
if (1 + 2 !== 3) throw new Error('Addition failed');
});
it('multiplies numbers', () => {
if (2 * 3 !== 6) throw new Error('Multiplication failed');
});
});
// Run all registered tests
const results = await runTests();
console.log(results.summary); // { total: 2, passed: 2, failed: 0, ... }Key Exports
Test DSL
describe(name, fn, timeout?)- Create a test suiteit(name, fn, timeout?)/test(name, fn, timeout?)- Define a test casebeforeAll(fn)- Run once before all tests in suitebeforeEach(fn)- Run before each testafterEach(fn)- Run after each testafterAll(fn)- Run once after all tests in suite
Runner
runTests(options?)- Execute tests and return resultsgetTestList(options?)- Get list of registered tests without running
Configuration
setConfig(config)- Update global configurationgetConfig()- Get current configurationresetConfig()- Reset to defaults
Lifecycle Hooks
describe('Database tests', () => {
let db;
beforeAll(async () => {
db = await connectToDatabase();
});
afterAll(async () => {
await db.close();
});
beforeEach(() => {
db.beginTransaction();
});
afterEach(() => {
db.rollback();
});
it('queries data', async () => {
const result = await db.query('SELECT 1');
// assertions...
});
});Timeout Configuration
Global Default
import { setConfig } from '@embedunit/core';
setConfig({
defaultTimeout: 10000, // 10 seconds for all tests
hookTimeout: 5000 // 5 seconds for hooks
});Per-Suite Timeout
describe('Slow tests', () => {
// All tests in this suite get 30s timeout
}, 30000);Per-Test Timeout
it('long running test', async () => {
await someLongOperation();
}, 60000); // 60 second timeoutSkip and Only
Skipping Tests
describe.skip('Broken feature', () => {
it('will not run', () => {});
});
it.skip('temporarily disabled', () => {});
// Aliases
xdescribe('also skipped', () => {});
xit('also skipped', () => {});Focusing Tests
describe.only('Only this suite runs', () => {
it('will run', () => {});
});
it.only('only this test runs', () => {});
// Aliases
fdescribe('focused suite', () => {});
fit('focused test', () => {});Parameterized Tests
Array of Arrays
it.each([
[1, 1, 2],
[1, 2, 3],
[2, 2, 4]
])('adds %d + %d to equal %d', (a, b, expected) => {
if (a + b !== expected) throw new Error('Failed');
});Array of Objects
it.each([
{ input: 'hello', expected: 5 },
{ input: 'world', expected: 5 }
])('$input has length $expected', ({ input, expected }) => {
if (input.length !== expected) throw new Error('Failed');
});With describe.each
describe.each([
['admin', true],
['guest', false]
])('User role: %s', (role, canDelete) => {
it('has correct permissions', () => {
// test using role and canDelete
});
});Filtering Tests
By Suite/Test Name
const results = await runTests({
only: { suite: 'Calculator' }
});
// Multiple suites
const results = await runTests({
only: { suites: ['Calculator', 'Parser'] }
});By Pattern (grep)
const results = await runTests({
grep: /should.*correctly/
});By Tags
describe('@integration Database', () => {
it('@slow queries large dataset', () => {});
});
// Run only integration tests
await runTests({ tags: ['integration'] });
// Exclude slow tests
await runTests({ excludeTags: ['slow'] });Custom Filter
const results = await runTests({
filter: (suite, test) => suite.includes('critical')
});Run Options
const results = await runTests({
bail: true, // Stop on first failure
includePassed: true, // Include passed tests in results
includeSkipped: true, // Include skipped tests in results
verboseErrors: true, // Full error details with stack traces
onEvent: (event) => {
// Handle test events: start, pass, fail, skip, complete
console.log(event.type, event.test);
}
});Result Structure
interface TestRunResult {
summary: {
total: number;
passed: number;
failed: number;
skipped: number;
duration: number;
success: boolean;
};
failures: Array<{
suite: string;
test: string;
error: { message: string; file?: string; line?: number };
duration: number;
}>;
passed?: Array<{ suite: string; test: string; duration: number }>;
skipped?: Array<{ suite: string; test: string }>;
}Extended DSL
Conditional test helpers for platform-specific tests:
import { itIf, describeIf, platform, env } from '@embedunit/core';
// Run test only in browser
itIf(platform.isBrowser)('uses localStorage', () => {});
// Run suite only when env var is set
describeIf(env('CI'))('CI-only tests', () => {});
// Skip test based on condition
itSkipIf(platform.isNode)('browser-only feature', () => {});