Files
frontend-app-gradebook/src/data/selectors/index.test.js
Bilal Qamar ccb7865100 feat: updated frontend-build & frontend-platform major versions (#374)
* feat: bumped frontend-platform to v6

* chore: bumped jest to v29

* fix: updated snapshots for failing tests

* refactor: updated frontend-build, updated snapshots

* feat: updated build and platform major versions, along with edx packages

* refactor: updated index.test to resolve failing test

* refactor: major version upgrade for react-unit-test-utils

* refactor: updated package-lock
2024-08-02 16:35:00 +05:00

507 lines
19 KiB
JavaScript

/* eslint-disable import/no-named-as-default-member, import/no-named-as-default */
import * as filterConstants from '../constants/filters';
import selectors from '.';
import * as moduleSelectors from '.';
import { minGrade, maxGrade } from './grades';
jest.mock('data/services/lms', () => ({
urls: {
gradeCsvUrl: jest.fn(
(...args) => ({ gradeCsvUrl: { args } }),
),
interventionExportCsvUrl: jest.fn(
(...args) => ({ interventionExportCsvUrl: { args } }),
),
},
}));
const mockFn = (key) => jest.fn((state) => ({ [key]: state }));
const mockMetaFn = (key) => jest.fn((...args) => ({ [key]: { args } }));
const testState = { a: 'test', state: 'of', random: 'data' };
const testVal = 'bananas';
describe('root selectors', () => {
const testCourseId = 'OxfordX+Time+Travel';
const mockAssignmentType = 'Homework';
const mockAssignmentLabel = 'HW 42';
beforeEach(() => {
selectors.app.courseId = jest.fn(() => testCourseId);
});
describe('editModalPossibleGrade', () => {
const selector = moduleSelectors.editModalPossibleGrade;
const grade1 = '42';
const grade2 = '3.14';
it('returns app.modalState.adjustedGradePossible if set', () => {
selectors.app.modalState.adjustedGradePossible = jest.fn(() => grade1);
selectors.grades.gradeOriginalPossibleGraded = jest.fn(() => grade2);
expect(selector(testState)).toEqual(grade1);
});
it('returns grades.gradeOriginalPossibleGraded if not overridden in modal', () => {
selectors.app.modalState.adjustedGradePossible = jest.fn(() => null);
selectors.grades.gradeOriginalPossibleGraded = jest.fn(() => grade2);
expect(selector(testState)).toEqual(grade2);
});
});
describe('filterBadgeConfig', () => {
let config;
const filterName = 'seasoning';
const filters = ['withSalt', 'withGarlic'];
const badgeValues = moduleSelectors.filterBadgeValues;
const { isDefault } = selectors.filters;
const oldConfig = filterConstants.filterConfig;
beforeEach(() => {
selectors.filters.isDefault = jest.fn();
});
afterEach(() => {
moduleSelectors.filterBadgeValues = badgeValues;
selectors.filters.isDefault = isDefault;
filterConstants.filterConfig = oldConfig;
});
describe('range filter (filterOrder in config)', () => {
const values = [3.14, 42];
const valueFn = () => values;
const testConfig = {
fake: 'config',
fields: 'for tests',
filterOrder: filters,
};
beforeEach(() => {
moduleSelectors.filterBadgeValues = { [filterName]: valueFn };
});
describe('if both are default values', () => {
beforeEach(() => {
filterConstants.filterConfig[filterName] = testConfig;
selectors.filters.isDefault.mockReturnValue(true);
config = selectors.root.filterBadgeConfig(testState, filterName);
});
it('returns isDefault: true, string value, and remaining filterConfig', () => {
const { filterOrder, ...rest } = testConfig;
expect(config).toEqual({
isDefault: true,
value: `${values[0]} - ${values[1]}`,
...rest,
});
});
});
describe('if neither/only 1 are default values', () => {
describe.each([
['neither', () => false],
['only filter1', (v) => v === filters[0]],
['only filter2', (v) => v === filters[1]],
], '%1 is default', (label, isDefaultFn) => {
beforeEach(() => {
filterConstants.filterConfig[filterName] = testConfig;
config = selectors.root.filterBadgeConfig(testState, filterName);
});
it('returns isDefault: false, string value, and remaining filterConfig', () => {
selectors.filters.isDefault.mockImplementation(isDefaultFn);
const { filterOrder, ...rest } = testConfig;
expect(config).toEqual({
isDefault: false,
value: `${values[0]} - ${values[1]}`,
...rest,
});
});
});
});
});
describe('single-value filter', () => {
const value = 3.14;
const valueFn = () => value;
const testConfig = {
fake: 'config',
fields: 'for tests',
};
beforeEach(() => {
filterConstants.filterConfig[filterName] = testConfig;
moduleSelectors.filterBadgeValues = { [filterName]: valueFn };
});
describe('if is default', () => {
beforeEach(() => {
selectors.filters.isDefault.mockReturnValue(true);
config = selectors.root.filterBadgeConfig(testState, filterName);
});
it('returns isDefault: true, string value, and filterConfig values', () => {
expect(config).toEqual({
isDefault: true,
value,
...testConfig,
});
});
});
describe('if is not default', () => {
beforeEach(() => {
selectors.filters.isDefault.mockReturnValue(false);
config = selectors.root.filterBadgeConfig(testState, filterName);
});
it('returns isDefault: true, string value, and filterConfig values', () => {
expect(config).toEqual({
isDefault: false,
value,
...testConfig,
});
});
});
});
});
describe('filterBadgeValues', () => {
const mockSelector = (obj, name, key) => (
jest.spyOn(obj, name).mockImplementation(state => state[key])
);
describe('assignment', () => {
let mock;
const selector = moduleSelectors.filterBadgeValues.assignment;
beforeEach(() => {
mock = mockSelector(selectors.filters, 'selectedAssignmentLabel', 'value');
});
afterEach(() => {
mock.mockRestore();
});
it('returns selectedAssignmentLabel if there is one selected', () => {
expect(selector({ value: testVal })).toEqual(testVal);
});
it('returns empty string if no assignment is selected', () => {
expect(selector({ value: null })).toEqual('');
});
});
describe('assignmentType', () => {
it('returns assignmentType filter', () => {
expect(
moduleSelectors.filterBadgeValues.assignmentType,
).toEqual(selectors.filters.assignmentType);
});
});
describe('includeCourseRoleMembers', () => {
it('returns includeCourseRoleMembers filter', () => {
expect(
moduleSelectors.filterBadgeValues.includeCourseRoleMembers,
).toEqual(selectors.filters.includeCourseRoleMembers);
});
});
describe('cohort', () => {
let mock;
const selector = moduleSelectors.filterBadgeValues.cohort;
beforeEach(() => {
mock = mockSelector(moduleSelectors, 'selectedCohortEntry', 'entry');
});
afterEach(() => {
mock.mockRestore();
});
it('returns selectedCohortEntry name if one is selected', () => {
expect(selector({ entry: { name: testVal } })).toEqual(testVal);
});
it('returns empty string if no cohort selected', () => {
expect(selector({ entry: undefined })).toEqual('');
});
});
describe('track', () => {
let mock;
const selector = moduleSelectors.filterBadgeValues.track;
beforeEach(() => {
mock = mockSelector(moduleSelectors, 'selectedTrackEntry', 'entry');
});
afterEach(() => {
mock.mockRestore();
});
it('returns selectedTrackEntry name if one is selected', () => {
expect(selector({ entry: { name: testVal } })).toEqual(testVal);
});
it('returns empty string if no track selected', () => {
expect(selector({ entry: undefined })).toEqual('');
});
});
describe('assignmentGrade', () => {
const selector = moduleSelectors.filterBadgeValues.assignmentGrade;
it('returns [filters.assignmentGradeMin, filters.assignmentGradeMax]', () => {
jest.spyOn(selectors.filters, 'assignmentGradeMin').mockImplementation(
state => ({ assignmentGradeMin: state }),
);
jest.spyOn(selectors.filters, 'assignmentGradeMax').mockImplementation(
state => ({ assignmentGradeMax: state }),
);
expect(selector(testState)).toEqual([
selectors.filters.assignmentGradeMin(testState),
selectors.filters.assignmentGradeMax(testState),
]);
});
});
describe('courseGrade', () => {
const selector = moduleSelectors.filterBadgeValues.courseGrade;
it('returns [filters.courseGradeMin, filters.courseGradeMax]', () => {
jest.spyOn(selectors.filters, 'courseGradeMin').mockImplementation(
state => ({ courseGradeMin: state }),
);
jest.spyOn(selectors.filters, 'courseGradeMax').mockImplementation(
state => ({ courseGradeMax: state }),
);
expect(selector(testState)).toEqual([
selectors.filters.courseGradeMin(testState),
selectors.filters.courseGradeMax(testState),
]);
});
});
});
describe('formattedGradeLimits', () => {
const selector = moduleSelectors.formattedGradeLimits;
const mockAssgn = (assignmentGradeMax, assignmentGradeMin) => {
selectors.app.assignmentGradeLimits = jest.fn(() => ({
assignmentGradeMax,
assignmentGradeMin,
}));
};
const mockCourse = (courseGradeMax, courseGradeMin) => {
selectors.app.courseGradeLimits = jest.fn(() => ({ courseGradeMax, courseGradeMin }));
};
const mockId = (id) => {
selectors.filters.selectedAssignmentId = jest.fn(() => id);
};
const grade1 = '42';
const grade2 = '3.14';
it('returns an object of nullable assignmentGrades if assignment is not set', () => {
mockId(undefined);
mockAssgn(grade1, grade2);
mockCourse(grade1, grade2);
expect(selector(testState)).toEqual({
assignmentGradeMax: null,
assignmentGradeMin: null,
courseGradeMax: '42',
courseGradeMin: '3.14',
});
});
it('returns null for each extreme iff they are equal their default', () => {
mockId('an ID!');
mockAssgn(maxGrade, grade1);
mockCourse(grade2, minGrade);
expect(selector(testState)).toEqual({
assignmentGradeMax: null,
assignmentGradeMin: grade1,
courseGradeMax: grade2,
courseGradeMin: null,
});
mockAssgn(grade2, minGrade);
mockCourse(maxGrade, grade1);
expect(selector(testState)).toEqual({
assignmentGradeMax: grade2,
assignmentGradeMin: null,
courseGradeMax: null,
courseGradeMin: grade1,
});
});
});
describe('getHeadings', () => {
const selector = moduleSelectors.getHeadings;
beforeEach(() => {
selectors.grades.headingMapper = jest.fn(
(type, label) => (breakdown) => ({ headingMapper: { type, label, breakdown } }),
);
selectors.filters.assignmentType = jest.fn();
selectors.filters.selectedAssignmentLabel = jest.fn();
selectors.grades.getExampleSectionBreakdown = mockFn('getExampleSectionBreakdown');
});
describe('no assignmentType or label selected', () => {
it('maps selected filters into getExampleSectionBreakdown', () => {
selectors.filters.assignmentType.mockReturnValue(undefined);
selectors.filters.selectedAssignmentLabel.mockReturnValue(undefined);
expect(selector(testState)).toEqual({
headingMapper: {
type: 'All',
label: 'All',
breakdown: { getExampleSectionBreakdown: testState },
},
});
});
});
describe('assignmentType and label selected', () => {
it('maps selected filters into getExampleSectionBreakdown', () => {
selectors.filters.assignmentType.mockReturnValue(mockAssignmentType);
selectors.filters.selectedAssignmentLabel.mockReturnValue(mockAssignmentLabel);
expect(selector(testState)).toEqual({
headingMapper: {
type: mockAssignmentType,
label: mockAssignmentLabel,
breakdown: { getExampleSectionBreakdown: testState },
},
});
});
});
});
describe('gradeExportUrl', () => {
const selector = moduleSelectors.gradeExportUrl;
let lmsApiServiceArgs;
beforeEach(() => {
selectors.filters.includeCourseRoleMembers = jest.fn();
lmsApiServiceArgs = moduleSelectors.lmsApiServiceArgs;
moduleSelectors.lmsApiServiceArgs = jest.fn(state => ({ lmsArgs: state }));
});
afterEach(() => {
moduleSelectors.lmsApiServiceArgs = lmsApiServiceArgs;
});
it('calls the API service with the right args', () => {
expect(selector(testState)).toEqual({
gradeCsvUrl: {
args: [{ lmsArgs: testState }],
},
});
});
});
describe('interventionExportUrl', () => {
it('calls the API service with the right args', () => {
const { lmsApiServiceArgs } = moduleSelectors;
selectors.filters.includeCourseRoleMembers = jest.fn();
moduleSelectors.lmsApiServiceArgs = jest.fn(state => ({ lmsArgs: state }));
expect(
moduleSelectors.interventionExportUrl(testState),
).toEqual({
interventionExportCsvUrl: {
args: [{ lmsArgs: testState }],
},
});
moduleSelectors.lmsApiServiceArgs = lmsApiServiceArgs;
});
});
describe('lmsApiServiceArgs', () => {
it('gathers formatted data from state for various lms api service calls', () => {
selectors.cohorts.getCohortNameById = mockFn('getCohortNameById');
selectors.filters.selectedAssignmentId = mockFn('selectedAssignmentId');
selectors.filters.assignmentType = mockFn('assignmentType');
selectors.filters.cohort = mockFn('cohort');
selectors.filters.track = mockFn('track');
selectors.filters.assignmentGradeMax = mockFn('assignmentGradeMax');
selectors.filters.assignmentGradeMin = mockFn('assignmentGradeMin');
selectors.filters.courseGradeMax = mockFn('courseGradeMax');
selectors.filters.courseGradeMin = mockFn('courseGradeMin');
selectors.filters.excludedCourseRoles = mockFn('excludedCourseRoles');
selectors.grades.formatMaxAssignmentGrade = mockMetaFn('formatMaxAssignmentGrade');
selectors.grades.formatMinAssignmentGrade = mockMetaFn('formatMinAssignmentGrade');
selectors.grades.formatMinCourseGrade = mockFn('formatMinCourseGrade');
selectors.grades.formatMaxCourseGrade = mockFn('formatMaxCourseGrade');
const assignmentId = { selectedAssignmentId: testState };
expect(moduleSelectors.lmsApiServiceArgs(testState)).toEqual({
cohort: { getCohortNameById: testState },
track: { track: testState },
assignment: assignmentId,
assignmentType: { assignmentType: testState },
assignmentGradeMin: {
formatMinAssignmentGrade: {
args: [{ assignmentGradeMin: testState }, { assignmentId }],
},
},
assignmentGradeMax: {
formatMaxAssignmentGrade: {
args: [{ assignmentGradeMax: testState }, { assignmentId }],
},
},
courseGradeMin: {
formatMinCourseGrade: { courseGradeMin: testState },
},
courseGradeMax: {
formatMaxCourseGrade: { courseGradeMax: testState },
},
excludedCourseRoles: { excludedCourseRoles: testState },
});
});
});
describe('localFilters', () => {
const id = 'assignmentID';
const includeCourseRoleMembers = 'Banana';
const formattedGradeLimits = ({ some: 'limits' });
const oldFormattedGradeLimits = moduleSelectors.formattedGradeLimits;
const selector = moduleSelectors.localFilters;
beforeEach(() => {
moduleSelectors.formattedGradeLimits = jest.fn(() => formattedGradeLimits);
selectors.filters.selectedAssignmentId = jest.fn(() => id);
selectors.filters.includeCourseRoleMembers = jest.fn(() => includeCourseRoleMembers);
});
afterEach(() => {
moduleSelectors.formattedGradeLimits = oldFormattedGradeLimits;
});
describe('searchValue is set', () => {
const searchText = 'Who dis?';
beforeEach(() => {
selectors.app.searchValue = jest.fn(() => searchText);
});
it('returns all local filter values, formatted for fetchGrades', () => {
expect(selector(testState)).toEqual({
assignment: id,
includeCourseRoleMembers,
...formattedGradeLimits,
searchText,
});
});
});
describe('searchValue is not set (is empty string)', () => {
beforeEach(() => {
selectors.app.searchValue = jest.fn(() => '');
});
it('returns all local filter values except searchText, formatted for fetchGrades', () => {
expect(selector(testState)).toEqual({
assignment: id,
includeCourseRoleMembers,
...formattedGradeLimits,
});
});
});
});
describe('selectedCohortEntry', () => {
it('returns the selected cohort entry object', () => {
const cohorts = [
{ id: 11, name: 'C-a' },
{ id: 22, name: 'C-b' },
{ id: 33, name: 'C-c' },
];
selectors.cohorts.allCohorts = jest.fn(() => cohorts);
selectors.filters.cohort = jest.fn(() => `${cohorts[1].id}`);
expect(moduleSelectors.selectedCohortEntry(testState)).toEqual(cohorts[1]);
});
});
describe('selectedTrackEntry', () => {
it('returns the selected track entry object', () => {
const tracks = [
{ slug: 'S1', name: 's-a' },
{ slug: 'S2', name: 's-b' },
{ slug: 'S3', name: 's-c' },
];
selectors.tracks.allTracks = jest.fn(() => tracks);
selectors.filters.track = jest.fn(() => tracks[2].slug);
expect(moduleSelectors.selectedTrackEntry(testState)).toEqual(tracks[2]);
});
});
describe('shouldShowSpinner', () => {
const selector = moduleSelectors.shouldShowSpinner;
const testSelector = (canView, showSpinner, expected) => {
selectors.roles.canUserViewGradebook = jest.fn(() => canView);
selectors.grades.showSpinner = jest.fn(() => showSpinner);
expect(selector(testState)).toEqual(expected);
};
describe('user can view gradebook, but showSpinner is false', () => {
it('returns false', () => {
testSelector(true, false, false);
});
});
describe('user cannot view gradebook, but showSpinner is true', () => {
it('returns false', () => {
testSelector(false, true, false);
});
});
describe('user can view gradebook, and showSpinner is true', () => {
it('returns true', () => {
testSelector(true, true, true);
});
});
});
describe('showBulkManagement', () => {
const selector = moduleSelectors.showBulkManagement;
const mkState = (bulkManagementAvailable) => ({ config: { bulkManagementAvailable } });
it('returns true when bulk management is enabled for the course', () => {
expect(selector(mkState(true))).toEqual(true);
});
it('returns false when bulk management is not enabled for the course', () => {
expect(selector(mkState(false))).toEqual(false);
});
});
});