ahbeng/NUSMods

View on GitHub
website/src/reducers/settings.test.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import produce from 'immer';
import { SettingsState } from 'types/reducers';

import * as actions from 'actions/settings';
import reducer from 'reducers/settings';
import {
  DARK_COLOR_SCHEME_PREFERENCE,
  LIGHT_COLOR_SCHEME_PREFERENCE,
  SYSTEM_COLOR_SCHEME_PREFERENCE,
} from 'types/settings';
import { initAction, rehydrateAction } from 'test-utils/redux';
import config, { RegPeriod } from 'config';

const initialState: SettingsState = {
  newStudent: false,
  faculty: '',
  colorScheme: SYSTEM_COLOR_SCHEME_PREFERENCE,
  hiddenInTimetable: [],
  modRegNotification: {
    enabled: true,
    semesterKey: config.getSemesterKey(),
    dismissed: [],
    scheduleType: 'Undergraduate',
  },
  moduleTableOrder: 'exam',
  loadDisqusManually: false,
  beta: false,
};
const settingsWithNewStudent: SettingsState = { ...initialState, newStudent: true };
const faculty = 'School of Computing';
const settingsWithFaculty: SettingsState = { ...initialState, faculty };
const settingsWithLightMode: SettingsState = {
  ...initialState,
  colorScheme: LIGHT_COLOR_SCHEME_PREFERENCE,
};
const settingsWithDarkMode: SettingsState = {
  ...initialState,
  colorScheme: DARK_COLOR_SCHEME_PREFERENCE,
};
const settingsWithDismissedNotifications: SettingsState = produce(initialState, (draft) => {
  draft.modRegNotification.dismissed = [
    { type: 'Select Courses', name: '1' },
    { type: 'Add / Swap Tutorials', name: '' },
    { type: 'Select Courses', name: '2' },
  ];
});

describe('settings', () => {
  test('settings should return initial state', () => {
    const nextState: SettingsState = reducer(undefined, initAction());
    expect(nextState).toEqual(initialState);
  });

  test('can select new student', () => {
    const action = actions.selectNewStudent(true);
    const nextState: SettingsState = reducer(initialState, action);
    expect(nextState).toEqual(settingsWithNewStudent);
  });

  test('can select faculty', () => {
    const action = actions.selectFaculty(faculty);
    const nextState: SettingsState = reducer(initialState, action);
    expect(nextState).toEqual(settingsWithFaculty);
  });

  test('can select color scheme', () => {
    const action = actions.selectColorScheme(DARK_COLOR_SCHEME_PREFERENCE);
    const nextState: SettingsState = reducer(initialState, action);
    expect(nextState).toEqual(settingsWithDarkMode);

    const action2 = actions.selectColorScheme(LIGHT_COLOR_SCHEME_PREFERENCE);
    const nextState2: SettingsState = reducer(initialState, action2);
    expect(nextState2).toEqual(settingsWithLightMode);

    const action3 = actions.selectColorScheme(SYSTEM_COLOR_SCHEME_PREFERENCE);
    const nextState3: SettingsState = reducer(nextState, action3);
    expect(nextState3).toEqual(initialState);
  });

  test('set module table order', () => {
    const state1 = reducer(initialState, actions.setModuleTableOrder('mc'));
    expect(state1.moduleTableOrder).toEqual('mc');

    const state2 = reducer(initialState, actions.setModuleTableOrder('code'));
    expect(state2.moduleTableOrder).toEqual('code');
  });
});

describe('modRegNotification settings', () => {
  test('clear out dismissed notifications when semester changes', () => {
    config.getSemesterKey = () => '2017/2018 Semester 2';

    const nextState: SettingsState = reducer(settingsWithDismissedNotifications, rehydrateAction());
    expect(nextState.modRegNotification).toMatchObject({
      semesterKey: '2017/2018 Semester 2',
      dismissed: [],
      enabled: true,
    });
  });

  test('not clear disabled when semester changes', () => {
    config.getSemesterKey = () => '2017/2018 Semester 2';
    const settingsState: SettingsState = {
      ...initialState,
      modRegNotification: {
        ...initialState.modRegNotification,
        enabled: false,
      },
    };

    const nextState: SettingsState = reducer(settingsState, rehydrateAction());
    expect(nextState.modRegNotification).toHaveProperty('enabled', false);
  });

  test('dismiss ModReg notification', () => {
    // Dismissing round that already exists shouldn't do anything
    expect(
      reducer(
        settingsWithDismissedNotifications,
        actions.dismissModregNotification({ type: 'Select Courses', name: '1' } as RegPeriod),
      ).modRegNotification.dismissed,
    ).toEqual(settingsWithDismissedNotifications.modRegNotification.dismissed);

    expect(
      reducer(
        settingsWithDismissedNotifications,
        actions.dismissModregNotification({ type: 'Add / Swap Tutorials', name: '' } as RegPeriod),
      ).modRegNotification.dismissed,
    ).toEqual(settingsWithDismissedNotifications.modRegNotification.dismissed);

    // Only add items that are unique
    expect(
      reducer(
        settingsWithDismissedNotifications,
        actions.dismissModregNotification({ type: 'Select Courses', name: '3' } as RegPeriod),
      ).modRegNotification.dismissed,
    ).toEqual([
      { type: 'Select Courses', name: '1' },
      { type: 'Add / Swap Tutorials', name: '' },
      { type: 'Select Courses', name: '2' },
      { type: 'Select Courses', name: '3' },
    ]);
  });

  test('dismiss/enable notifications should be opposites', () => {
    expect(
      reducer(
        reducer(
          initialState,
          actions.dismissModregNotification({ type: 'Select Courses', name: '1' } as RegPeriod),
        ),
        actions.enableModRegNotification({ type: 'Select Courses', name: '1' } as RegPeriod),
      ).modRegNotification.dismissed,
    ).toEqual([]);
  });

  test('toggle ModReg notification globally', () => {
    const state1 = reducer(initialState, actions.toggleModRegNotificationGlobally(true));
    expect(state1.modRegNotification.enabled).toEqual(true);

    const state2 = reducer(initialState, actions.toggleModRegNotificationGlobally(false));
    expect(state2.modRegNotification.enabled).toEqual(false);
  });

  test('set schedule type', () => {
    expect(
      reducer(initialState, actions.setModRegScheduleType('Graduate')).modRegNotification
        .scheduleType,
    ).toEqual('Graduate');
    expect(
      reducer(initialState, actions.setModRegScheduleType('Undergraduate')).modRegNotification
        .scheduleType,
    ).toEqual('Undergraduate');
  });
});

describe('beta testing state', () => {
  test('toggle should enable when beta prop does not exist', () => {
    const { beta, ...initialWithoutBeta } = initialState;
    const state = reducer(initialWithoutBeta, actions.toggleBetaTesting());
    expect(state.beta).toEqual(true);
  });

  test('toggle should enable when beta prop is false', () => {
    const state = reducer(initialState, actions.toggleBetaTesting());
    expect(state.beta).toEqual(true);
  });

  test('toggle should disable when beta prop is true', () => {
    const state = {
      ...initialState,
      beta: true,
    };

    const nextState = reducer(state, actions.toggleBetaTesting());
    expect(nextState.beta).toEqual(false);
  });
});