Jest

From bibbleWiki
Jump to navigation Jump to search

Introduction

This is a page to introduce Jest. Facebook employs a lot of the people who develop jest and can be and is used for test in other frameworks.

Choices

Popular tools for testing are Enzyme and Jasmine/Mocha. Jest is built on top of Jasmine/Mocha. Jest works with or without React and has a great assertion library.

Why Not Enzyme

This has over 200+ issues open and 26 of these are bugs. Jest is recommended by the react team.

Jest vs Mocha

Jest and Mocha both run tests sync and async but jest also has the following features.

  • Spies (stubbing methods to spy)
  • Snapshot testing
  • Module mocking (stubbing objects)

Getting Started

Naming Test

 __tests__/*.js
 *.spec.js
 *.test.js

Example Test in Jest

Describe is the suite, it is the test

 describe("The question list ", ()=> {
     it ("should display a list of items", ()=> {
         expect(2+2).toEqual(4);
     })

     it ("should display a list of items", ()=> {
         expect(2+4).toEqual(6);
     })

 })

Setup and Teardown

This can be done using

 BeforeEach BeforeAll

 beforeAll(()=>{
    console.log("Hello");
 });

and AfterEach AfterAll

 afterAll(()=>{
    console.log("Hello");
 });

Note does not matter what order you write them in.

Skipping and Isolating Tests

Add keyword only to include tests

    it.only ("should display a list of items", ()=> {
        expect(2+2).toEqual(4);
    })

Add keyword skip to exlude tests

    it.skip ("should display a list of items", ()=> {
        expect(2+2).toEqual(4);
    })

Async Tests

it('async test 1', done=> {
    setTimeout(done, 100)
});
it('async test 2',()=> {
    return new Promise(
        resolve => setTimeout(resolve,100)
    );
});
it('async test 1', async ()=>
    await delay(100)
);

Mocking

Create directory __mocking__ at the same level as node_modules

Here is an example for mocking fetch package isomorphic-fetch

 let __value = 42;
 const isomorphicFetch = jest.fn( ()=> __value);
 isomorphicFetch.__setValue = v => __value = v;
 export default  isomorphicFetch;

And the test case. We import the function to be mocked from out __mocks__/isomorphic-fetch.js

import { handleFetchQuestion } from './fetch-question-saga';
import fetch from 'isomorphic-fetch';

 describe("Fetch question s saga", ()=>{
 
     beforeAll( () => {
         fetch.__setValue([{question_id:42}] );
     }); 
 
     it ("should fetch the question saga", async ()=> {
         const gen = handleFetchQuestion({question_id:42});
         const { value } = await gen.next(); 

         expect(value).toEqual( [{question_id:42}] )
         expect(fetch).toHaveBeenCalledWith('/api/questions/42');
     });
 });

Redux and Testing mapStateToProps

You can easily test the map from state to props. e.g.

import { mapStateToProps } from '../QuestionDetail';

it("should map the state to props correctly", () => {

   // Sample App State with sampleQuestion being object in state
   const sampleQuestion {
       question_id:42,
       body: "Space is big"
   };

   const appState = {
       questions: [sampleQuestion]
   };
   
   // Sample Props
   const ownProps = {
       question:42
   });

   const componentState = mapStateToProps(appState, ownProps)
   expect(componentState).toEqual(sampleQuestion);
}


Sample test with state

Bit of a lot of code but here goes

Create component to test

import React from 'react';

export default class extends React.Component {
    constructor)(...args) {
        super(...args);
        this.state = {
            count: -1
        }
    }

    async comonentDidMount () {
        let { count } = await NotificationService.GetNotification();
        this.setState( {
            count
        });
    }

    render() {
       return (
           <section className="mt-3 mb-2">
               <div className="notifications">
                   {this.state.count != -1 ? '${this.state.count} Notifications Awaiting!' : 'Loading...'}
               </div>
           </section>
       )
    }
}

Create a Service

export default {
    async GetNoitifications() {
        console.warning("REAL NOTIFICATION SERVICE!");
        await delay(1000);
        return { count: 42 };
    }
}

Test Case

import NotificationsViewer from '../NotificationsViewer';
import renderer from 'react-test-renderer';
import React from 'react';
import delay from 'redux-saga';

// NOTE Local module you need to pass in url of notification service
jest.mock('../../services/NotificationService');

// NOTE 2 this needs to be a require and needs to be after the jest. Making it
// an import will fail

const notificationService = require('../../services/NotificationService').default; 

  
describe("The notification viewer", () => {

   beforeAll( ()=> {
     notificationService.__setCount(5);
   });

   it("should display the correct number of notifications", async()=> {

       const tree = renderer
           .create(
               <NoticationsViewer/>
            )
       await delay();
       const instance = tree.root;

       // find by className the component
       const component = instance.findByProps( { className: 'notificiations' });  

       const text = component.children[0];
       export(text).toEqual("5 Notifications");

   });
});

Mocked Service src\services\__mocks__\NotificationService.js

let count = 0;
export default {

    __setCount(__count) {
        count = _count;
    },
    async GetNotifications() {
        console.warn("Good Job! Using Mock");
    }
}


Matchers in Jest

These can be found [1]

Some of them for quick reference.

expect(value)
expect.extend(matchers)
expect.anything()
expect.any(constructor)
expect.arrayContaining(array)
expect.assertions(number)
expect.hasAssertions()
expect.not.arrayContaining(array)
expect.not.objectContaining(object)
expect.not.stringContaining(string)
expect.not.stringMatching(string | regexp)
expect.objectContaining(object)
expect.stringContaining(string)
expect.stringMatching(string | regexp)
expect.addSnapshotSerializer(serializer)