Files
frontend-app-learner-dashboard/src/data/redux/app/selectors/currentList.test.js
Maxwell Frank 731fbe2e2e refactor: course filters (#303)
Co-authored-by: Maxwell Frank <mfrank@2u.com>
2024-03-28 12:50:59 -04:00

186 lines
7.5 KiB
JavaScript

import { keyStore } from 'utils';
import { FilterKeys, SortKeys } from 'data/constants/app';
import simpleSelectors from './simpleSelectors';
import * as module from './currentList';
jest.mock('./simpleSelectors', () => ({
__esModule: true,
default: {
courseData: jest.fn(),
pageNumber: jest.fn(),
},
}));
const {
sortFn,
courseFilters,
transforms,
courseFilterFn,
currentList,
visibleList,
} = module;
const moduleKeys = keyStore(module);
const testDate = '2000-10-10';
const testString = 'test-STRING';
describe('courseList selector module', () => {
describe('utilities', () => {
describe('sortFn', () => {
it('performs comparison sort after running both values through transform', () => {
const transform = ({ val }) => val;
expect(sortFn(transform, { reverse: false })({ val: 2 }, { val: 1 })).toEqual(1);
expect(sortFn(transform, { reverse: false })({ val: 1 }, { val: 1 })).toEqual(0);
expect(sortFn(transform, { reverse: false })({ val: 1 }, { val: 2 })).toEqual(-1);
expect(sortFn(transform, { reverse: true })({ val: 2 }, { val: 1 })).toEqual(-1);
expect(sortFn(transform, { reverse: true })({ val: 1 }, { val: 1 })).toEqual(0);
expect(sortFn(transform, { reverse: true })({ val: 1 }, { val: 2 })).toEqual(1);
});
});
describe('courseFilters', () => {
let filterFn;
test('notEnrolled returns true iff course is not enrolled', () => {
filterFn = courseFilters[FilterKeys.notEnrolled];
expect(filterFn({ enrollment: { isEnrolled: true } })).toEqual(false);
expect(filterFn({ enrollment: { isEnrolled: false } })).toEqual(true);
});
test('done returns true iff learner has finished course', () => {
filterFn = courseFilters[FilterKeys.done];
expect(filterFn({ courseRun: null })).toEqual(false);
expect(filterFn({ courseRun: { isArchived: true } })).toEqual(true);
expect(filterFn({ courseRun: { isArchived: false } })).toEqual(false);
});
test('upgraded returns true if learner is verified', () => {
filterFn = courseFilters[FilterKeys.upgraded];
expect(filterFn({ enrollment: { isVerified: true } })).toEqual(true);
expect(filterFn({ enrollment: { isVerified: false } })).toEqual(false);
});
test('inProgress returns true iff learner has started course', () => {
filterFn = courseFilters[FilterKeys.inProgress];
expect(filterFn({ enrollment: { hasStarted: true } })).toEqual(true);
expect(filterFn({ enrollment: { hasStarted: false } })).toEqual(false);
});
test('notStarted returns true iff learner has not started course', () => {
filterFn = courseFilters[FilterKeys.notStarted];
expect(filterFn({ enrollment: { hasStarted: true } })).toEqual(false);
expect(filterFn({ enrollment: { hasStarted: false } })).toEqual(true);
});
});
describe('transforms', () => {
test('enrolled transform returns date transform of enrollment.lastEnrolled', () => {
const data = { enrollment: { lastEnrolled: testDate } };
expect(transforms[SortKeys.enrolled](data)).toEqual(new Date(testDate));
});
test('title transform returns lowercase transform of course.courseName', () => {
const data = { course: { courseName: testString } };
expect(transforms[SortKeys.title](data)).toEqual(testString.toLowerCase());
});
});
describe('courseFilterFn', () => {
it('returns always-true filter if filter list is empty', () => {
expect(courseFilterFn([])()).toEqual(true);
});
it('takes filters and then course, and returns true if course matches all filters', () => {
const filters = [FilterKeys.inProgress, FilterKeys.upgraded];
const inProgressSpy = jest.spyOn(courseFilters, FilterKeys.inProgress);
const upgradedSpy = jest.spyOn(courseFilters, FilterKeys.upgraded);
inProgressSpy.mockImplementation(v => v > 3);
upgradedSpy.mockImplementation(v => v > 5);
expect(courseFilterFn(filters)(6)).toEqual(true);
expect(courseFilterFn(filters)(5)).toEqual(false);
upgradedSpy.mockImplementation(v => v > 2);
expect(courseFilterFn(filters)(3)).toEqual(false);
inProgressSpy.mockRestore();
upgradedSpy.mockRestore();
});
});
describe('currentList selector', () => {
it('returns passed courses filtered and sorted', () => {
const sortSpy = jest.spyOn(module, moduleKeys.sortFn);
const filterSpy = jest.spyOn(module, moduleKeys.courseFilterFn);
filterSpy.mockReturnValue(({ val }) => val > 0);
sortSpy.mockReturnValue((v1, v2) => {
const [a, b] = [v1, v2].map(({ val }) => val);
if (a === b) { return 0; }
return (a > b) ? 1 : -1;
});
const testCourses = {
empty: { val: 0 },
v1: { val: 1 },
v2: { val: 2 },
v3: { val: 3 },
};
const {
empty,
v1,
v2,
v3,
} = testCourses;
let sortBy = SortKeys.enrolled;
const testFilters = [1, 2, 3];
expect(currentList(
[empty, v2, v1, empty, empty, v3, empty],
{ sortBy, filters: testFilters },
)).toEqual([v1, v2, v3]);
expect(sortSpy).toHaveBeenCalledWith(transforms[sortBy], { reverse: true });
expect(filterSpy).toHaveBeenCalledWith(testFilters);
sortSpy.mockClear();
sortBy = SortKeys.title;
expect(currentList(
[empty, v2, v1, empty, empty, v3, empty],
{ sortBy, filters: testFilters },
)).toEqual([v1, v2, v3]);
expect(sortSpy).toHaveBeenCalledWith(transforms[sortBy], { reverse: false });
expect(filterSpy).toHaveBeenCalledWith(testFilters);
sortSpy.mockRestore();
filterSpy.mockRestore();
});
});
});
describe('visibleList selector', () => {
let listSpy;
let out;
const pageSize = 2;
const pageNumber = 3;
const testState = { some: 'state' };
const sortBy = SortKeys.enrolled;
const testFilters = [1, 2, 3];
const testCourseData = { test: 'course-data' };
const testList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
beforeEach(() => {
listSpy = jest.spyOn(module, moduleKeys.currentList);
listSpy.mockReturnValue(testList);
simpleSelectors.courseData.mockReturnValue(testCourseData);
simpleSelectors.pageNumber.mockReturnValue(pageNumber);
out = visibleList(testState, { sortBy, filters: testFilters, pageSize });
});
afterEach(() => {
listSpy.mockRestore();
});
it('loads currentList from courseData values and passed sortBy and filters values', () => {
expect(simpleSelectors.courseData).toHaveBeenCalledWith(testState);
expect(simpleSelectors.pageNumber).toHaveBeenCalledWith(testState);
expect(listSpy).toHaveBeenCalledWith(
Object.values(testCourseData),
{ sortBy, filters: testFilters },
);
});
it('returns visible page based on passed page size and stored pageNumber', () => {
// page 3, 2 per page. [0 1] [2 3] [4 5] ...
expect(out.visibleList).toEqual([testList[4], testList[5]]);
});
it('returns number of pages based on page size and list length', () => {
expect(out.numPages).toEqual(6);
});
it('disable pagination if page size is 0', () => {
out = visibleList(testState, { sortBy, filters: testFilters, pageSize: 0 });
expect(out.visible).toEqual(testList);
expect(out.numPages).toEqual(1);
});
});
});