[[development-unit-tests]] === Unit Testing We use unit tests to make sure that individual software units of {kib} perform as they were designed to. [float] === Current Frameworks {kib} is migrating unit testing from `Mocha` to `Jest`. Legacy unit tests still exist in `Mocha` but all new unit tests should be written in `Jest`. [float] ==== Mocha (legacy) Mocha tests are contained in `__tests__` directories. *Running Mocha Unit Tests* ["source","shell"] ----------- yarn test:mocha ----------- [float] ==== Jest Jest tests are stored in the same directory as source code files with the `.test.{js,ts,tsx}` suffix. *Running Jest Unit Tests* ["source","shell"] ----------- yarn test:jest ----------- [float] ===== Writing Jest Unit Tests In order to write those tests there are two main things you need to be aware of. The first one is the different between `jest.mock` and `jest.doMock` and the second one our `jest mocks file pattern`. As we are running `js` and `ts` test files with `babel-jest` both techniques are needed specially for the tests implemented on Typescript in order to benefit from the auto-inference types feature. [float] ===== Jest.mock vs Jest.doMock Both methods are essentially the same on their roots however the `jest.mock` calls will get hoisted to the top of the file and can only reference variables prefixed with `mock`. On the other hand, `jest.doMock` won't be hoisted and can reference pretty much any variable we want, however we have to assure those referenced variables are instantiated at the time we need them which lead us to the next section where we'll talk about our jest mock files pattern. [float] ===== Jest Mock Files Pattern Specially on typescript it is pretty common to have in unit tests `jest.doMock` calls which reference for example imported types. Any error will thrown from doing that however the test will fail. The reason behind that is because despite the `jest.doMock` isn't being hoisted by `babel-jest` the import with the types we are referencing will be hoisted to the top and at the time we'll call the function that variable would not be defined. In order to prevent that we develop a protocol that should be followed: - Each module could provide a standard mock in `mymodule.mock.ts` in case there are other tests that could benefit from using definitions here. This file would not have any `jest.mock` calls, just dummy objects. - Each test defines its mocks in `mymodule.test.mocks.ts`. This file could import relevant mocks from the generalised module's mocks file `(*.mock.ts)` and call `jest.mock` for each of them. If there is any relevant dummy mock objects to generalise (and to be used by other tests), the dummy objects could be defined directly on this file. - Each test would import its mocks from the test mocks file mymodule.test.mocks.ts. `mymodule.test.ts` has an import like: `import * as Mocks from './mymodule.test.mocks'`, `import { mockX } from './mymodule.test.mocks'` or just `import './mymodule.test.mocks'` if there isn't anything exported to be used.