Skip to content

Commit

Permalink
chore: Added unit tests for useCourseUpgrade() and useTrackEvent() hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
rijuma committed Dec 16, 2024
1 parent c61291b commit 055c6fa
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/context/course-info-context.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createContext } from 'react';

export const CourseInfoContext = createContext('course-info', {
export const CourseInfoContext = createContext({
courseId: null,
unitId: null,
isUpgradeEligible: false,
Expand Down
1 change: 0 additions & 1 deletion src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
/* eslint-disable import/prefer-default-export */
export { default as useCourseUpgrade } from './use-course-upgrade';
export { default as useTrackEvent } from './use-track-event';
1 change: 1 addition & 0 deletions src/hooks/use-course-upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function useCourseUpgrade() {

if (auditTrial?.expirationDate) {
const auditTrialExpirationDate = new Date(auditTrial.expirationDate);

auditTrialDaysRemaining = Math.ceil((auditTrialExpirationDate - Date.now()) / millisecondsInOneDay);

auditTrialExpired = auditTrialDaysRemaining < 0;
Expand Down
159 changes: 159 additions & 0 deletions src/hooks/use-course-upgrade.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { renderHook as rtlRenderHook } from '@testing-library/react-hooks';
import { useSelector } from 'react-redux';
import { useModel } from '@src/generic/model-store'; // eslint-disable-line import/no-unresolved
import { CourseInfoProvider } from '../context';
import useCourseUpgrade from './use-course-upgrade';

jest.mock('@src/generic/model-store', () => ({ useModel: jest.fn() }), { virtual: true });
jest.mock('react-redux', () => ({ useSelector: jest.fn() }));

const mockedUpgradeUrl = 'https://upgrade.edx/course/test';
const mockedAuditTrialLengthDays = 7;

const contextWrapper = ({ courseInfo }) => function Wrapper({ children }) { // eslint-disable-line react/prop-types
return (
<CourseInfoProvider value={courseInfo}>
{children}
</CourseInfoProvider>
);
};

const renderHook = ({
courseInfo, offer = {}, verifiedMode = {}, state = { learningAssistant: {} },
}) => {
useModel.mockImplementation((model) => {
switch (model) {
case 'coursewareMeta': return { offer };
case 'courseHomeMeta': return { verifiedMode };
default: {
throw new Error('Model not mocked');
}
}
});

useSelector.mockReturnValue(state.learningAssistant);

return rtlRenderHook(
() => useCourseUpgrade(),
{ wrapper: contextWrapper({ courseInfo }) },
);
};

describe('useCourseUpgrade()', () => {
beforeAll(() => jest.useFakeTimers().setSystemTime(new Date('2024-01-10 09:00:00')));
afterAll(() => jest.useRealTimers());
afterEach(() => jest.resetAllMocks());

it('should return { upgradeable: false } if not eligible', () => {
const { result } = renderHook({ courseInfo: { isUpgradeEligible: false } });

expect(result.current).toEqual({ upgradeable: false });
});

it('should return { upgradeable: false } if missing upgradeUrl', () => {
const { result } = renderHook({ courseInfo: { isUpgradeEligible: true } });

expect(result.current).toEqual({ upgradeable: false });
});

it('should return { upgradeable: true } if eligible and upgradeable and no trial info for both offer and verifiedMode urls', () => {
const expected = {
upgradeable: true,
auditTrial: undefined,
auditTrialDaysRemaining: undefined,
auditTrialExpired: false,
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: mockedUpgradeUrl,
};

const { result: resultOffer } = renderHook({
courseInfo: { isUpgradeEligible: true },
offer: {
upgradeUrl: mockedUpgradeUrl,
},
state: {
learningAssistant: {
auditTrialLengthDays: mockedAuditTrialLengthDays,
},
},
});

expect(resultOffer.current).toEqual(expected);

const { result: resultVerified } = renderHook({
courseInfo: { isUpgradeEligible: true },
verifiedMode: {
upgradeUrl: mockedUpgradeUrl,
},
state: {
learningAssistant: {
auditTrialLengthDays: mockedAuditTrialLengthDays,
},
},
});

expect(resultVerified.current).toEqual(expected);
});

it('should return trial info if enabled and not expired', () => {
const { result } = renderHook({
courseInfo: { isUpgradeEligible: true },
offer: {
upgradeUrl: mockedUpgradeUrl,
},
verifiedMode: {
upgradeUrl: mockedUpgradeUrl,
},
state: {
learningAssistant: {
auditTrialLengthDays: mockedAuditTrialLengthDays,
auditTrial: {
expirationDate: '2024-01-15 09:00:00',
},
},
},
});

expect(result.current).toEqual({
auditTrial: {
expirationDate: '2024-01-15 09:00:00',
},
auditTrialDaysRemaining: 5,
auditTrialExpired: false,
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: 'https://upgrade.edx/course/test',
upgradeable: true,
});
});

it('should return trial info if expired', () => {
const { result } = renderHook({
courseInfo: { isUpgradeEligible: true },
offer: {
upgradeUrl: mockedUpgradeUrl,
},
verifiedMode: {
upgradeUrl: mockedUpgradeUrl,
},
state: {
learningAssistant: {
auditTrialLengthDays: mockedAuditTrialLengthDays,
auditTrial: {
expirationDate: '2024-01-05 09:00:00',
},
},
},
});

expect(result.current).toEqual({
auditTrial: {
expirationDate: '2024-01-05 09:00:00',
},
auditTrialDaysRemaining: -5,
auditTrialExpired: true,
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: 'https://upgrade.edx/course/test',
upgradeable: true,
});
});
});
54 changes: 54 additions & 0 deletions src/hooks/use-track-event.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { renderHook as rtlRenderHook } from '@testing-library/react-hooks';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { CourseInfoProvider } from '../context';

import useTrackEvent from './use-track-event';

const mockedUserId = 123;
const mockedCourseId = 'some-course-id';
const mockedModuleId = 'some-module-id';

jest.mock('@edx/frontend-platform/analytics', () => ({
sendTrackEvent: jest.fn(),
}));

const mockedAuthenticatedUser = { userId: mockedUserId };
jest.mock('@edx/frontend-platform/auth', () => ({
getAuthenticatedUser: () => mockedAuthenticatedUser,
}));

const contextWrapper = ({ courseInfo }) => function Wrapper({ children }) { // eslint-disable-line react/prop-types
return (
<CourseInfoProvider value={courseInfo}>
{children}
</CourseInfoProvider>
);
};

const renderHook = ({
courseInfo,
}) => rtlRenderHook(
() => useTrackEvent(),
{ wrapper: contextWrapper({ courseInfo }) },
);

describe('useCourseUpgrade()', () => {
afterEach(() => jest.resetAllMocks());

it('should return a track method that calls sendTrackEvent with the contextual information', () => {
const { result } = renderHook({ courseInfo: { courseId: mockedCourseId, moduleId: mockedModuleId } });

const { track } = result.current;

const eventLabel = 'some-cool-event-to-track';

track(eventLabel, { some_extra_prop: 42 });

expect(sendTrackEvent).toHaveBeenCalledWith(eventLabel, {
course_id: mockedCourseId,
user_id: mockedUserId,
module_id: mockedModuleId,
some_extra_prop: 42,
});
});
});

0 comments on commit 055c6fa

Please sign in to comment.