@sprucelabs/test-utils
Version:
Helpful utilities to make asserting more complicated conditions quick and easy! ⚡️
151 lines (150 loc) • 6.36 kB
JavaScript
import SpruceTestResolver, { TestLifecycleListeners, } from './SpruceTestResolver.js';
if (typeof it === 'undefined') {
//@ts-ignore
global.it = () => { };
}
let areLifecycleHooksInPlace = false;
//recursive function to get static method by name looping up through constructor chain
function resolveMethod(Target, name) {
if (Target[name]) {
return Target[name];
}
if (Target.constructor && Target.constructor !== Target) {
return resolveMethod(Target.constructor, name);
}
return null;
}
/** Hooks up before, after, etc. */
function hookupTestClassToJestLifecycle(Target) {
if (areLifecycleHooksInPlace) {
return;
}
areLifecycleHooksInPlace = true;
const hooks = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'];
hooks.forEach((hook) => {
// @ts-ignore
if (global[hook]) {
// @ts-ignore
global[hook](async () => {
SpruceTestResolver.resolveTestClass(Target);
if (hook === 'beforeEach') {
await TestLifecycleListeners.emitWillRunBeforeEach();
await runBeforeEach(Target);
await TestLifecycleListeners.emitDidRunBeforeEach();
}
else if (hook === 'afterEach') {
await TestLifecycleListeners.emitWillRunAfterEach();
await runAfterEach(Target);
await TestLifecycleListeners.emitDidRunAfterEach();
SpruceTestResolver.reset();
}
else if (hook === 'beforeAll') {
await TestLifecycleListeners.emitWillRunBeforeAll();
await runBeforeAll(Target);
await TestLifecycleListeners.emitDidRunBeforeAll();
SpruceTestResolver.reset();
}
else if (hook === 'afterAll') {
await TestLifecycleListeners.emitWillRunAfterAll();
await runAfterAll(Target);
await TestLifecycleListeners.emitDidRunAfterAll();
}
});
}
});
}
async function runBeforeAll(Target) {
await callStaticHook(Target, 'beforeAll');
}
async function runAfterAll(Target) {
await callStaticHook(Target, 'afterAll');
}
async function callStaticHook(Target, hook) {
var _a;
const cb = resolveMethod(Target, hook);
await ((_a = cb === null || cb === void 0 ? void 0 : cb.apply) === null || _a === void 0 ? void 0 : _a.call(cb, SpruceTestResolver.ActiveTestClass ? Target.constructor : Target));
}
async function runAfterEach(Target) {
var _a, _b, _c, _d, _e;
if (SpruceTestResolver.ActiveTestClass) {
const Resolved = SpruceTestResolver.resolveTestClass(Target);
await ((_a = Resolved.afterEach) === null || _a === void 0 ? void 0 : _a.apply(Resolved));
}
else if (Target.afterEach) {
await ((_c = (_b = Target.afterEach) === null || _b === void 0 ? void 0 : _b.apply) === null || _c === void 0 ? void 0 : _c.call(_b, Target));
}
else {
await ((_e = (_d = Target === null || Target === void 0 ? void 0 : Target.constructor.afterEach) === null || _d === void 0 ? void 0 : _d.apply) === null || _e === void 0 ? void 0 : _e.call(_d, Target.constructor));
}
}
async function runBeforeEach(Target) {
var _a, _b, _c, _d, _e;
if (SpruceTestResolver.ActiveTestClass) {
const Resolved = SpruceTestResolver.resolveTestClass(Target);
await ((_a = Resolved.beforeEach) === null || _a === void 0 ? void 0 : _a.apply(Resolved));
}
else if (Target.beforeEach) {
await ((_c = (_b = Target.beforeEach) === null || _b === void 0 ? void 0 : _b.apply) === null || _c === void 0 ? void 0 : _c.call(_b, Target));
}
else {
await ((_e = (_d = Target === null || Target === void 0 ? void 0 : Target.constructor.beforeEach) === null || _d === void 0 ? void 0 : _d.apply) === null || _e === void 0 ? void 0 : _e.call(_d, Target.constructor));
}
}
/** Test decorator */
export default function test(description, ...args) {
return function (Target, propertyKey, descriptor) {
hookupTestClassToJestLifecycle(Target);
// Make sure each test gets the spruce
it(description !== null && description !== void 0 ? description : propertyKey, async () => {
const Resolved = SpruceTestResolver.resolveTestClass(Target);
if (!Resolved[propertyKey]) {
throw new Error(`The test '${propertyKey}()' should NOT be static when tests run with suite()`);
}
const bound = descriptor.value.bind(Resolved);
//@ts-ignore
global.activeTest = {
file: Target.name,
test: propertyKey,
};
return bound(...args);
});
};
}
export function suite() {
return function (Target) {
SpruceTestResolver.ActiveTestClass = Target;
};
}
/** Only decorator */
test.only = (description, ...args) => {
return function (target, propertyKey, descriptor) {
// Lets attach before/after
hookupTestClassToJestLifecycle(target);
// Make sure each test gets the spruce
it.only(description !== null && description !== void 0 ? description : propertyKey, async () => {
const bound = descriptor.value.bind(SpruceTestResolver.resolveTestClass(target));
return bound(...args);
});
};
};
/** Todo decorator */
test.todo = (description, ..._args) => {
return function (target, propertyKey) {
// Lets attach before/after
hookupTestClassToJestLifecycle(target);
// Make sure each test gets the spruce
it.todo(description !== null && description !== void 0 ? description : propertyKey);
};
};
/** Skip decorator */
test.skip = (description, ...args) => {
return function (target, propertyKey, descriptor) {
// Lets attach before/after
hookupTestClassToJestLifecycle(target);
// Make sure each test gets the spruce
it.skip(description !== null && description !== void 0 ? description : propertyKey, async () => {
const bound = descriptor.value.bind(SpruceTestResolver.resolveTestClass(target));
return bound(...args);
});
};
};