3
\$\begingroup\$

I'm trying to understand conception of creating unit tests for the frontend applications.

I have created higher order reducer:

// @flow

type action = {
    type: string,
    payload?: any
};

/**
 * Async Reducer Factory to reduce duplicated code in async reducers.
 * Higher Order Reducer.
 *
 * @param {String} name - Reducer name.
 * @returns {Function}
 */
export const asyncReducerFactory = (name: String) => {
    return (
        state = { data: null, isLoading: false, error: null },
        action: action
    ) => {
        switch (action.type) {
            case `FETCH_${name}_STARTED`:
                return { data: null, isLoading: true, error: null };
            case `FETCH_${name}_SUCCESS`:
                return { data: action.payload, isLoading: false, error: null };
            case `FETCH_${name}_ERROR`:
                return { data: null, isLoading: false, error: action.payload };
            default:
                return state;
        }
    };
};

Tests:

import { asyncReducerFactory } from "./factories";

describe("Test async reducers factory", () => {
    const factory = asyncReducerFactory("TEST");

    it("should create reducer", () => {
        expect(factory).not.toBe(null);
    });

    it("should start fetching", () => {
        expect(factory({}, { type: "FETCH_TEST_STARTED" })).toEqual({
            data: null,
            isLoading: true,
            error: null
        });
    });

    it("should end fetching with success", () => {
        expect(
            factory({}, { type: "FETCH_TEST_SUCCESS", payload: "success" })
        ).toEqual({
            data: "success",
            isLoading: false,
            error: null
        });
    });

    it("should end fetching with error", () => {
        expect(
            factory({}, { type: "FETCH_TEST_ERROR", payload: "error" })
        ).toEqual({
            data: null,
            isLoading: false,
            error: "error"
        });
    });

    it("should return default state", () => {
        expect(factory({}, { type: "DIFFERENT" })).toEqual({});
    });
});

I would really appreciate, if you could let me know:

  1. if i'm using flow correctly?
  2. if my tests are reliable?
  3. how could i make it more generic?
\$\endgroup\$
0
\$\begingroup\$

I have very minimal flow experience, but the action definition looks right. You may also be able to define a state type for this reducer.

It's pretty generic right now, so I'm not sure I would push it much more. Maybe it should be called fetchReducerFactory, just to keep the terminology consistent.

The tests look good. By "reliable", you probably mean "good." They are readable and look to provide good coverage for the code and branches.

  • You may want to test that the default state is correct.
  • You may want to test that unknown actions do nothing to the state.

NOTE: The following comment is pretty minor, but wanted to bring it up. The way the code is structured, the tests make sense. But there are implicit cases that work because of the code structure. Let me explain:

You expect FETCH_TEST_SUCCESS to do 3 things: (1) clear the isLoading flag (2) set data to the payload, and (3) set error to null. These three behaviors are wrapped together in one test. And, the only data that is actually changed by the reducer in this test is the data property; isLoading and error are not changed. So, for this test, you could make sure all values are changed by passing in a different state:

expect(
       factory({ data: null, isLoading: true, error: 3 }, 
               { type: "FETCH_TEST_SUCCESS", payload: "success" })
       ).toEqual({
         data: "success",
         isLoading: false,
         error: null
  });

This will guard against code changes later where someone refactors. Or, you could just have three small tests, each that test single property mutations. Again, small potatoes.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.