Skip to content

Instantly share code, notes, and snippets.

@libetl
Created March 31, 2023 21:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save libetl/60eb8b5337f5ef11c622e83da993e619 to your computer and use it in GitHub Desktop.
Save libetl/60eb8b5337f5ef11c622e83da993e619 to your computer and use it in GitHub Desktop.
test-runner.ts
let currentSuiteName = "";
let testPromises: (() => Promise<any>)[] = [];
let beforeAllHooks: (() => void | Promise<void>)[] = [];
let afterAllHooks: (() => void | Promise<void>)[] = [];
let beforeEachHooks: (() => void)[] = [];
let afterEachHooks: (() => void)[] = [];
let testsInError: { [testName: string]: Error } = {};
export const describe = async (suiteName: string, callback: Function) => {
currentSuiteName = suiteName;
await new Promise((resolve) => {
const waitUntilNoPromise = setInterval(() => {
if (testPromises.length === 0) {
clearInterval(waitUntilNoPromise);
resolve(void 0);
}
}, 1000);
});
callback();
await testPromises.reduce(
(acc, other) => acc.then(() => other()),
Promise.resolve(void 0)
);
beforeAllHooks = [];
afterAllHooks = [];
beforeEachHooks = [];
afterEachHooks = [];
testPromises = [];
if (Object.entries(testsInError).length) {
console.log(testsInError);
testsInError = {};
}
};
export const beforeEach = (callback: () => void | Promise<void>) =>
beforeEachHooks.push(callback);
export const afterEach = (callback: () => void | Promise<void>) =>
afterEachHooks.push(callback);
export const beforeAll = (callback: () => void | Promise<void>) =>
beforeAllHooks.push(callback);
export const afterAll = (callback: () => void | Promise<void>) =>
afterAllHooks.push(callback);
export const it = async (testName: string, testCase: Function) => {
if (testPromises.length === 0) {
for (let beforeAllHook of beforeAllHooks)
testPromises.push(() => Promise.resolve(void 0).then(beforeAllHook));
for (let afterAllHook of afterAllHooks)
testPromises.push(() => Promise.resolve(void 0).then(afterAllHook));
}
const callback =
testCase.length === 1
? (resolve: Function) =>
testCase(() => {
for (let afterEachHook of afterEachHooks) afterEachHook();
return resolve();
})
: async (resolve: Function) => {
const result = await testCase();
for (let afterEachHook of afterEachHooks) afterEachHook();
return resolve(result);
};
testPromises.splice(beforeAllHooks.length, 0, () =>
new Promise((resolve, reject) => {
try {
for (let beforeEachHook of beforeEachHooks) beforeEachHook();
const result = callback(resolve);
if (result instanceof Promise) {
return result.catch((e) => {
for (let afterEachHook of afterEachHooks) afterEachHook();
return reject(e);
});
}
return result;
} catch (e) {
for (let afterEachHook of afterEachHooks) afterEachHook();
return reject(e);
}
}).catch((e) => {
const error = new Error(
`test-runner error at ${currentSuiteName} - ${testName} ; ${
e.message ?? ""
}`
);
error.stack = e;
testsInError[testName] = e;
return Promise.resolve(void 0);
})
);
};
export const mockImplementation = (callback: Function = () => {}) => {
let invocations: number = 0;
const watchedFunction = (...args: any[]) => {
invocations++;
return callback(...args);
};
watchedFunction.getInvocationsNumber = () => invocations;
return watchedFunction;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment