I'm writing a little testing tool for Jest (just to learn). It is called assertTruthy(msg, fn, args)
, expects a message, a function and arguments and should pass if the thing that is returned when the function is invoked with the arguments is truthy and fail if its not.
I would like to add it to Jest, so that you could call it without importing it in every environment.
describe('someFn()', () => {
// like 'it', 'describe' and 'expect' it should just be available here
it('is a function', () => {
expect(typeop someFN).toEqual('Function');
});
assertTruthy('it should return true', someFn, 3, 4);
});
I know Jest has setupFiles
and setupFilesAfterEnv
but I can't figure out how to use them to achieve this.
How do you add commands to Jest?
PS: On a single project basis (in CRA) I managed to do this like this:
// in src/setupFiles.js
const assertTruthy = // function definition ...
global.assertTruthy = assertTruthy
This is often useful if you want to set up some global state that will be used by many tests. For instance: const globalDatabase = makeGlobalDatabase(); beforeAll(() => { // this clears the database and adds some testing data. // Jest waits for this promise to resolve before running tests. return globalDatabase.
Jest is a JavaScript test runner, that is, a JavaScript library for creating, running, and structuring tests. Jest ships as an NPM package, you can install it in any JavaScript project. Jest is one of the most popular test runner these days, and the default choice for React projects.
beforeEach(fn) #Runs a function before each of the tests in this file runs. If the function returns a promise, Jest waits for that promise to resolve before running the test. This is often useful if you want to reset some global state that will be used by many tests.
In order to add global functions to jest, you need to define setupFiles
in your configuration and attach that function to the global object in the setup file:
module.exports = {
// ...
setupFiles: ['<rootDir>/setupFile.js'],
// ...
};
so if you want to do something very similar to it
, I would suggest you do something like this:
// /setupFile.js
// in order to change an existing function (not youre case):
global.it = function(description, fn) { /* ... */ };
// this is how you define a new function globally
global.assertTruthy = (message, func, ...args) => {
return global.it(message, () => {
expect(func(...args)).toBeTruthy();
});
// optional: implementing the same interface as `jest.It`
jest.It
Here's an example from the Airbnb library airbnb/jest-wrap
where they wrapped the describe function. If you want to implement the jest.It
interface, you'll also need to implement assertTruthy.todo
, assertTruthy.skip
, assertTruthy.only
, & assertTruthy.each
(check out the it
interface). todo
and skip
are pretty easy since you want to do exactly the same as the original ones.
For each
& only
, we need to change the it
function inside our implementation. A simple way to support only
is by using a closure and passing the correct it
function from the closure's inpu. each
can be a little more complex to implement.
// /setupFile.js
// normaly, use the jest `it` function
global.assertTruthy = assertTruthyCreator(it);
// bypass for todo and skip
global.assertTruthy.todo = global.it.todo;
global.assertTruthy.skip = global.it.skip;
// only calls the same function but uses `only` internaly
global.assertTruthy.only = assertTruthyCreator(it.only);
// special case which needs special implementation
// see usage below
global.assertTruthy.each = assertTruthyCreator(it.each, true);
function assertTruthyCreator(itFunc, withTable) {
if (withTable) {
return (message, func, ...args) => {
return itFunc(args)(message, (...caseArgs) => {
expect(func(...caseArgs)).toBeTruthy();
});
};
}
return (message, func, ...args) => {
return itFunc(message, () => {
expect(func(...args)).toBeTruthy();
});
};
}
// usage:
assertTruthy.each(
'add numbers',
(a, b) => a + b,
[2, 4],
[4, 5],
[7, 9]);
If you're using typescript for writing jest test, the first thing you'll need to do is declare
your new function somewhere:
interface IGenericFunction {
(...args: any[]): any;
}
declare const assertTruthy: (message: string, func: IGenericFunction, ...args: any[]) => any;
With javascript, you can skip that step.
After that, just use it like you use describe
and it
:
const funcToTest = (a: number, b: number) => a + b;
describe("Test Suite", () => {
assertTruthy('this ran with assertTruthy', funcToTest, 5, 3);
test("another test", () => {
// ...
});
});
and jest will treat this as any other it
function
node_module
dependencyIf you want to create a library from this, you can basically just pass a node_modules
path to the setupFiles
array.
For example, with this repository, you can do as follows:
npm install --save-dev @kibibit/jest-utils
module.exports = {
// ...
setupFiles: ['node_modules/@kibibit/jest-utils/lib/jest-utils.js'],
// ...
};
and it should work the same as importing it locally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With