Skip to content

Instantly share code, notes, and snippets.

@jeffsoup
Created October 3, 2017 22:11
Show Gist options
  • Save jeffsoup/9a994b8bda8e40b263b5898c92c38cb7 to your computer and use it in GitHub Desktop.
Save jeffsoup/9a994b8bda8e40b263b5898c92c38cb7 to your computer and use it in GitHub Desktop.
Seasoned Unit Testing Standards

Unit Testing Requirements

Pull Requests with new development will be rejected if there no unit tests

Code Coverage Expectations

All new development should have 100% coverage. If something cannot have a test created for it please note why you cannot create the test in the code and pass the work onto whomever you think should create the test (if possible).

Unused Code

Delete it and all associated unit tests. We don't want dead or orphaned code in the application.

When Mocking Data

  • Save mock data as a function not as an object
  • Wrap data in function, pass as an anonymous object

Snapshot Testing

  • Useful for small components
  • Use in additional to standard unit tests

Code Style

( Need content here )

Testing action creators

  • If an action creator is returning a plain object, we want to test if the correct action creator was called and compare that the returning object is equal to expected action.

    Action example:

    export function hideDialog() {
        return {
            type: Types.HIDE_DIALOG,
            value: { isOpen: false }
        };
    }
    
    //test for hideDialog action:
    describe('hideDialog action', () => {
        it('should return the correct hide dialog action', () => {
            const expectedAction = {
                type: Types.HIDE_DIALOG,
                value: { isOpen: false }
            };
            expect(actions.hideDialog()).toEqual(expectedAction);
        });
    });
  • If an action creator is returning a dispatch function, we would need to mock the dispatch function. Since there is a function that already does the work, import testThunkAction from actionTestUtil.js to the test file. The testThunkAction receives mainly 2 parameters:

    • action to test
    • the expected action as an object, wrapped in brackets. If the action dispatch more than one action, it should be defined in an array.

    Example with only one action to dispatch:

    export function showMessagesList() {
        return dispatch => {
            dispatch({
                type: Types.SHOW_MESSAGES_LIST,
                value: { visible: true, show: true, interaction: true }
            });
        };
    
    // test for showMessagesList
    describe('showMessageList', () => {
        it('should return the correct showMessageList action', () => {
            const expectedAction = {
                type: Types.SHOW_MESSAGES_LIST,
                value: { visible: true, show: true, interaction: true }
            };
            testThunkAction(actions.showMessagesList, [expectedAction]);
        });
    });

    Example with 2 actions to dispatch:

    export function openMessage(openMessage) {
        return dispatch => {
            dispatch({
                type: Types.HIDDEN_MESSAGE_COMPOSE,
                value: { visible: false }
            });
    
            dispatch({
                type: Types.OPEN_MESSAGE,
                openMessage,
            });
        };
    }
    
    // test for openMessage
    describe('openMessage action', () => {
        it('should dispatch the correct open message action', () => {
            const mockOpenMessage = {};
    
            const expectedActions = [
                {
                    type: Types.HIDDEN_MESSAGE_COMPOSE,
                    value: { visible: false }
                },
                {
                    type: Types.OPEN_MESSAGE,
                    openMessage: mockOpenMessage
                }
            ];
    
            testThunkAction(() => actions.openMessage(mockOpenMessage), expectedActions);
        });
    });
  • For async action creators, mock the API call by importing these two libraries:

    • axios
    • axios-mock-adapter

    The API response should be mocked too since we are only testing that the action creator is been called correctly and the right action is returned.

    Example for mocking API calls in async action creators:

    import Axios from 'axios';
    import MockAdapter from 'axios-mock-adapter';
    
    export function loginUser(data) {
        return dispatch => {
            const result = Axios.post(`${URLs.LOGIN}?userFetchMask=3072`, data);
            result.then(({ data }) => {
                dispatch({
                    type: Types.LOGIN_USER,
                    user: data
                });
            });
            return result;
        };
    }
    
    //test for loginUser
    describe('loginUser action', () => {
        let mock;
        const mockUserData = {};
        const mockUserResponseData = {};
        beforeEach(() => {
            mock = new MockAdapter(Axios);
            mock.onPost(`${URLs.LOGIN}?userFetchMask=3072`, mockUserData).reply(200, mockUserResponseData);
        });
    
        afterEach(() => {
            mock.restore();
        });
    
        it('should dispatch the login user action after posting the user login information to the server', () => {
            const expectedAction = {
                type: Types.LOGIN_USER,
                user: mockUserResponseData
            };
            const dispatch = jest.fn();
            let thunk = actions.loginUser(mockUserData);
            thunk(dispatch)
                .then(() => expect(dispatch).toHaveBeenLastCalledWith(expectedAction));
        });
    });

Naming Conventions

( Need content here for a logical naming convention related to everything with testing: test itself, wrapper function, mock, mock-data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment