[Documentation on Matchers] https://facebook.github.io/jest/docs/en/expect.html
to be or not to be, that is the question _ Not: reverses the assertion _ toBe: that two values are equivalent using strict equality (checks reference/identity) _ toEqual: that two values are equivalent by looking at the values (if it walks like a duck, it's a duck). For two different arrays with the same value, toBe fails and toEqual succeeds. _ toContain: checks that a value exists in an array * toHaveLength: checks the length of an array. Like toContain, it is more readable than using toEqual and toBe combined with array methods.
You can install locally or globally.
- fast
- simple to write and execute
- used to test correctness
- written by developers
- the tool for doing TDD/BDD
Auto update! --watch
It only runs the tests that it has to run.
.spec.js
or .test.js
)can:
includes coverage reports // as you're writing code, you have watch. When you want to see coverage, you run Jest with --coverage
__tests__
folder will be run automaticallyany file that ends in .spec.js
or .test.js
will be executed automatically
highly sensitive to small changes
This is where more than one expect in a test makes sense:
does not verify interaction between components
import renderer from 'react-test-renderer'
import { TheComponent } from './TheComponent'
import renderer from 'react-test-renderer';
import { TheComponent } from '/TheComponent';
const tree = renderer.create(<TheComponent>);
expect(tree.JSON()).toMatchSnapShot();
to update snapshot: jest TheComponent -u
or --update
, but ain't nobody got time for that
yarn test -u
)fast and semi-automatic
catches regressions that could be missed by humans
works with any library that generates HTML components (Angular, Vue, React)
better than no tests at all to protect applications from regressions
easy to override, save new snapshot
protects only against regression
easy to break, smallest change will fail test suite
adds more files to the repository
waste of time to have them while actively making changes to components Probably want to wait until you get to the version you're committing to
describe
and it
beforeEach: runs before the tests, good for setup code
beforeAll: runs once before the first test
skipping tests: 'it.skip()' // if it's the snapshot test you want to skip Example:
it.skip('checks that it is an array', () => {
const numbers = [1, 2, 3];
const expected = 'array';
const actual = Array.isArray(numbers);
expect(actual).toBe(true);
})
![Imgur](https://i.imgur.com/YXyLOQw.png)
isolating is used to pick the tests you want to run: it.only()
// if you're working on a test and you have suite of 400 tests but you're only working to fix one, so you only want to run that one.
Example:
it.only('checks that it is an array', () => {
const numbers = [1, 2, 3];
const expected = 'array';
const actual = Array.isArray(numbers);
expect(actual).toBe(true);
});
describe.only()
or describe.skip()
describe.skip('default', () => {
it('run the tests', () => {});
});
techniques
done()
callback that is passed to the testdescribe
(use async and await) Preferred and cleanest syntaxit('async using callback', done => {
setTimeout(done, 4000);
});
it('async using promises', () => {
return new Promise( resolve => setTimeout(resolve, 3000) )
});
it('async with async/await', async () => {
await new Promise(resolve => setTimeout(resolve, 2000));
})
Note: Notice there's not a return for the async/await. Still Jest knows that before it can run any code, it needs to wait for that to resolve.
a duplicate of a unit of code that has no implementation
has the same API (method names, return value type and shape must be returned) of the original unit, but has no side effects
prevent side effects
reduce dependencies
isolate tests to simplify testing
add mocks to a __mocks__
folder, next to the mocked module
to mock npm modules, just name your mock the same as the module and it will be loaded automatically
node_modules
folder because it needs to be next to whatever it's mockingto mock local files:
__mocks__
folder at the same level of the file to mockjest.mock('path to code file to be mocked');
Spies are functions that provide information about how they are used.
counts functions calls
records arguments passed to it when it is called
we can return fake values in order to test specific scenarios
to create - spies
: const jamesBond = jest.fn()
; This creates a noop
function.
passing a function as the first argument, wraps that function into a spy
that then keeps track of useful information.
Most test runners will check for errors.
If it's not throwing an error, it looks like it's passing
Some frameworks tell you it's a pending test - that you have the code but haven't done anything with it
What we have in those cases is some kind of coding standards and people who check, linters and things like that (if you don't want to buy into Typescript or Flow)
CLI section of docs: https://facebook.github.io/jest/docs/en/cli.html You'll find some good stuff in there.
No. I think they use it so they can identify at a quick glance. Like software can look at this and knows that anything that ends with this will be a test. I don't know what the name of that is.
Jest uses textRegex to detect test files:
├── **tests**
│ └── component.spec.js # test
│ └── anything # test
├── package.json # not test
├── foo.test.js # test
├── bar.spec.jsx # test
└── component.js # not test)
import React from 'react';
import renderer from 'react-test-renderer';
import App from './App';
describe('snapshot demo', () => {
describe('saves the snapshot', () => {
})
}) // Test suite failed - Your test suite must contain at least one test
describe('snapshot demo', () => {
describe('saves the snapshot', () => {
it('should work', () => {
})
})
}) // Passes
describe('snapshot demo', () => {
describe('saves the snapshot', () => {
it('should work', () => {
const tree = renderer.create(<App />);
expect(tree.toJSON()).toMatchSnapShot();
})
})
}) // 1 snapshot written in 1 test suite
// If you change the App.js and run again,
// it fails and tells you what changes there are between the two snapshots
Instead of having it test on every change, you can run yarn test -u
const utilities = require('.../index');
describe('default', () => {
it('run the tests', () => {});
});
describe('add function', () => {
// teardown
afterAll(() => {
console.log('after all ran');
});
// setup
beforeEach(() => {
console.log('before each ran');
});
it('should add two numbers', () => {
// arrange
const add = utilities.add;
//act
const seven = add(3,4);
const four = add(0, 4);
const minusThree = add(1, -4);
//assert
expect(seven).toBe(7);
expect(four).toBe(4);
expect(minusThree).toBe(-3);
});
it('checks identity', () => {
const numbers = [1, 2, 3];
//const actual = [1,2,3]
const actual = numbers;
expect(numbers).toBe(actual);
})
it('checks that it is an array', () => {
const numbers = [1, 2, 3];
const expected = 'array';
const actual = Array.isArray(numbers)
expect(numbers).toBe(true)
})
})
See the numbers
right here? That I'm resetting them? That's a good example of that.
I could have const numbers = [1,2,3]
but then during the execution inside the test, I'm making changes to it
Better example:
it('can push items to the numbers array', () => {
numbers.push(4)
})
But that's the case, when you want to reset or set the value you want each test to always have the same unique value. If you want something that executes so you can reset the environment before each test because each test should have a pristine environment to run in.
I think when you have too many, you won't see all of the descriptions
I'm using the regular command prompt. But I'm cheating.
You could. I don't see a lot of that, but you could. It's just a function that will execute code.
function makeThing(args) {
return {
args: args
}
}
Say you have 100 tests in here. (You shouldn't, you should have a smaller test suite. Because if you have 100 tests, it means you're testing something that's probably doing a lot.) But if you do and you're using ... let's go back to the example of when I was using numbers at the beginning. If you're down here on line #425 and the before is all the way up on line #10, you have to scroll all the way up to see where that variable comes from.
const numbers = makeNumbersArray(5);
So now when you see numbers, you know where it's coming from so you can navigate to where it's being generated instead of it just appearing in your test.But all the libraries have it because people know about them and they know that this stuff(beforeEach) are used for setups and this(afterAll) used to clean up at the end. Maybe you have timeouts or things in memory and you're testing, you're using those there. So at the end of running all the tests, you want to say hey, eliminate this timeout or this event that you just created. So all of that clean-up code you do it on the afters. Some of those you want to leave to have all of the tests. Some of them you want to clean up right after each test. That's why we have afterEach and afterAll.
I don't think I've seen people taking advantage of that you can pass a parameter. I don't see a good use case for that, to pass parameters in here.
Because if I wanted to make this the default return from the arrow function I would use parantheses instead of curly braces. As soon as I use curly braces, I am saying this is now the body and if I want to return something, I have to use the return keyword.
(in reference to it('async with promises', () => { return new Promise(resolve => setTimeout(resolve, 2000))})
)
it('async with promise', () => (newPromise(resolve => setTimeout(resolve, 2000))))