Sunday, 6 November 2016

Nesting unit tests in karma/jasmine with a higher order function

Unit tests are incredibly important, but sometimes test suites become difficult to read because the tests are not properly nested and now you are seeing 600 tests in a single line; Nesting them can also be quite tedious; Even though karma and jasmine nests test cases together with the same name, redefining a list of 'groups' in each test can be a bit difficult to maintain. We can solve this problem with a higher-order-function that accepts the entire grouping as an array.

The higher order function

The code for the higher order function (which we will call 'hofDescribe' from now on) is nothing too large or difficult, let's take a look:
/app/test/index.js
const hofDescribe = (groups, test) => {
  groups.reverse().reduce((previousTest, group) => (
    () => describe(`.${group}`, previousTest)
  ), test)();
};

export default hofDescribe;
hofDescribe take in an array of groups and the test (a function that returns a 'describe' block). It then nests the describes from the bottom up (from the deepest nested node/describe to the top root node/describe). It starts by reversing the array to have the bottom node first and passes the test given to hofDescribe as the test for the bottom node, and then returns a new describe to each parent until it reaches the top.

Putting it to use

Using hofDescribe is simple, lets 'test' three files and create a small test hiearchy. We will be testing one React component and two redux reducers.
/app/test/reducers/layout/size.js
import hofDescribe from 'test';

hofDescribe(['REDUCERS', 'Layout', 'Size'], () => describe('{ app.layout.size }', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
/app/test/reducers/layout/color.js
import hofDescribe from 'test';

hofDescribe(['REDUCERS', 'Layout', 'Color'], () => describe('{ app.layout.color }', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
/app/test/components/layout/shared/link.jsx
import hofDescribe from 'test';

hofDescribe(['COMPONENTS', 'Account'], () => describe('<Avatar />', () => {
  it('Does something', () => {});
  it('Does something else even better', () => {});
}));
The output from a test suite like this would give you a proper structured tree that makes much more sense:
.COMPONENTS
  .Account
    <Avatar />
      ✓ Does something
      ✓ Does something else even better

.REDUCERS
  .Layout
    .Color
      { app.layout.color }
        ✓ Does something
        ✓ Does something else even better
    .Size
      { app.layout.size }
        ✓ Does something
        ✓ Does something else even better

No comments:

Post a Comment