14. Test reducer

In this section we will start to see the benefit of using redux in making out testing simpler as we separate out the concerns of updating state with those of rendering views in a component.

1. Fix broken EventComponent test

We need to fix our broken tests every time we add a new dependency to a component or thing under test it will need to be provided to the tests environment.

  • Fix the test by providing a fake Store . There are more syntactically simpler ways to deal with this type of faking boiler plate but for now I would like to make it verbose and explicit what we are doing in these tests.

src/app/event/container/event/event.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { Store } from '@ngrx/store';
import { NO_ERRORS_SCHEMA } from '@angular/compiler/src/core';
import { HttpClient } from '@angular/common/http';

import { EventComponent } from './event.component';
import { EventService } from '../../services/event.service';

describe('EventComponent', () => {
  let component: EventComponent;
  let fixture: ComponentFixture<EventComponent>;
  let service: EventService;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: HttpClient, useValue: null },
        {
          provide: EventService,
          useValue: {
            getAttendees: () => {}
          }
        },
        {
          provide: Store,
          useValue: {
            pipe: () => {}
          }
        }
      ],
      declarations: [EventComponent],
      schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(EventComponent);
    component = fixture.componentInstance;
    service = TestBed.get(EventService);
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should have a list of attendees set', () => {
    const fakeAttendees = [{ name: 'FAKE_NAME', attending: false, guests: 0 }];

    jest
      .spyOn(service, 'getAttendees')
      .mockImplementation(() => of(fakeAttendees));

    component.ngOnInit();

    component.attendees$.subscribe(attendees => {
      expect(attendees).toEqual(fakeAttendees);
    });
  });
});

2. Test a reducer

Reducers are so simple to test as they are pure functions. We just need to call the reducer function and pass in a fake piece of state and an action and then check the new state slice returns.

  • Create a spinner.reducer.spec.ts file to the state folder.

  • Add a test to check we return the state passed in if the cases do not match any action types.

src/app/state/spinner/reducer.spec.ts
import { reducer } from './spinner.reducer';

describe('Reducer: Spinner', () => {
  it('should have initial state of isOn false', () => {
    const expected = { isOn: false };
    const action = { type: 'foo' } as any;
    expect(reducer(undefined, action)).toEqual(expected);
  });
});
  • Add another test to check we return new state with the isOn flag set to true when we pass in a startSpinner action.

src/app/state/spinner/reducer.spec.ts
import { reducer } from './spinner.reducer';

describe('Reducer: Spinner', () => {
  it('should have initial state of isOn false', () => {
    const expected = { isOn: false };
    const action = { type: 'foo' } as any;
    expect(reducer(undefined, action)).toEqual(expected);
  });

  it('should have a isOn set to true', () => {
    const state = { isOn: false };
    const action = { type: 'startSpinner' };
    const expected = { isOn: true };
    expect(reducer(state, action)).toEqual(expected);
  });
});

Last updated