Files
frontend-app-learner-dashboard/src/hooks/api.test.js
2025-06-30 16:15:52 -06:00

276 lines
9.4 KiB
JavaScript

import React from 'react';
import { AppContext } from '@edx/frontend-platform/react';
import { keyStore } from 'utils';
import { RequestKeys } from 'data/constants/requests';
import { post } from 'data/services/lms/utils';
import api from 'data/services/lms/api';
import * as reduxHooks from 'data/redux/hooks';
import * as apiHooks from './api';
const reduxKeys = keyStore(reduxHooks);
jest.mock('data/services/lms/utils', () => ({
post: jest.fn((...args) => ({ post: args })),
}));
jest.mock('data/services/lms/api', () => ({
initializeList: jest.fn(),
updateEntitlementEnrollment: jest.fn(),
unenrollFromCourse: jest.fn(),
deleteEntitlementEnrollment: jest.fn(),
updateEmailSettings: jest.fn(),
createCreditRequest: jest.fn(),
}));
jest.mock('data/redux/hooks', () => ({
useCardCourseRunData: jest.fn(),
useCardCreditData: jest.fn(),
useCardEntitlementData: jest.fn(),
useLoadData: jest.fn(),
useMakeNetworkRequest: jest.fn(),
useClearRequest: jest.fn(),
useEmailConfirmationData: jest.fn(),
}));
jest.mock('react', () => ({
...jest.requireActual('react'),
useContext: jest.fn(context => context),
}));
const moduleKeys = keyStore(apiHooks);
const testString = 'TEST-string';
const uuid = 'test-UUID';
const cardId = 'test-card-id';
const selection = 'test-selection';
const courseId = 'test-COURSE-id';
const isRefundable = 'test-is-refundable';
const user = 'test-user';
const loadData = jest.fn();
reduxHooks.useLoadData.mockReturnValue(loadData);
const clearRequest = jest.fn();
reduxHooks.useClearRequest.mockReturnValue(clearRequest);
reduxHooks.useCardCourseRunData.mockReturnValue({ courseId });
reduxHooks.useCardEntitlementData.mockReturnValue({ uuid, isRefundable });
let hook;
let out;
const testInitCardHook = (hookKey) => {
test(`initializes ${hookKey} with cardId`, () => {
expect(reduxHooks[hookKey]).toHaveBeenCalledWith(cardId);
});
};
const initializeApp = jest.fn();
describe('api hooks', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('useNetworkRequest', () => {
const makeNetworkRequest = jest.fn(args => ({ networkRequest: args }));
const action = jest.fn((...actionArgs) => ({ action: actionArgs }));
const args = { some: 'test', args: 'for you' };
it('returns network request based on incoming action', () => {
reduxHooks.useMakeNetworkRequest.mockReturnValue(makeNetworkRequest);
hook = apiHooks.useNetworkRequest(action, args);
expect(hook()).toEqual(makeNetworkRequest({ promise: action(), ...args }));
});
it('forwards action arguments', () => {
reduxHooks.useMakeNetworkRequest.mockReturnValue(makeNetworkRequest);
hook = apiHooks.useNetworkRequest(action, args);
const actionArgs = [1, 2, 3];
expect(hook(...actionArgs)).toEqual(
makeNetworkRequest({ promise: action(...actionArgs), ...args }),
);
});
});
describe('network requests', () => {
const mockUseNetworkRequest = jest.fn((action, args) => ({ action, args }));
const testRequestKey = (requestKey) => {
test('requestKey', () => { expect(hook.args.requestKey).toEqual(requestKey); });
};
beforeEach(() => {
jest.spyOn(apiHooks, moduleKeys.useNetworkRequest).mockImplementation(mockUseNetworkRequest);
});
describe('useInitializeApp', () => {
beforeEach(() => {
hook = apiHooks.useInitializeApp();
});
it('calls initialize api method', () => {
expect(hook.action).toEqual(api.initializeList);
});
testRequestKey(RequestKeys.initialize);
it('initializes load data hook', () => {
expect(reduxHooks.useLoadData).toHaveBeenCalledWith();
});
it('calls loadData with data on success', () => {
hook.args.onSuccess({ data: testString });
expect(loadData).toHaveBeenCalledWith(testString);
});
});
describe('entitlement enrollment hooks', () => {
beforeEach(() => {
jest.spyOn(apiHooks, moduleKeys.useInitializeApp).mockReturnValue(initializeApp);
});
const testInitialization = () => {
it('initializes useInitializeApp', () => {
expect(apiHooks.useInitializeApp).toHaveBeenCalledWith();
});
testInitCardHook(reduxKeys.useCardEntitlementData);
};
const testArgs = (requestKey) => {
testRequestKey(requestKey);
it('initializes app on success', () => {
expect(hook.args.onSuccess).toEqual(initializeApp);
});
};
describe('useNewEntitlementEnrollment', () => {
beforeEach(() => {
hook = apiHooks.useNewEntitlementEnrollment(cardId);
});
testInitialization();
testArgs(RequestKeys.newEntitlementEnrollment);
it('calls updateEntitlementEnrollment api method', () => {
hook.action(selection);
expect(api.updateEntitlementEnrollment)
.toHaveBeenCalledWith({ uuid, courseId: selection });
});
});
describe('useSwitchEntitlementEnrollment', () => {
beforeEach(() => {
hook = apiHooks.useSwitchEntitlementEnrollment(cardId);
});
testInitialization();
testArgs(RequestKeys.switchEntitlementSession);
it('calls updateEntitlementEnrollment api method', () => {
hook.action(selection);
expect(api.updateEntitlementEnrollment)
.toHaveBeenCalledWith({ uuid, courseId: selection });
});
});
describe('useLeaveEntitlementSession', () => {
beforeEach(() => {
hook = apiHooks.useLeaveEntitlementSession(cardId);
});
testInitialization();
testArgs(RequestKeys.leaveEntitlementSession);
it('calls updateEntitlementEnrollment api method', () => {
hook.action();
expect(api.deleteEntitlementEnrollment)
.toHaveBeenCalledWith({ uuid, isRefundable });
});
});
});
describe('useUnenrollFromCourse', () => {
beforeEach(() => {
hook = apiHooks.useUnenrollFromCourse(cardId);
});
testInitCardHook(reduxKeys.useCardCourseRunData);
testRequestKey(RequestKeys.unenrollFromCourse);
it('calls unenrollFromCourse api method with courseId', () => {
hook.action();
expect(api.unenrollFromCourse).toHaveBeenCalledWith({ courseId });
});
});
describe('useMasqueradeAs', () => {
beforeEach(() => {
hook = apiHooks.useMasqueradeAs(cardId);
});
it('initializes load data hook', () => {
expect(reduxHooks.useLoadData).toHaveBeenCalledWith();
});
testRequestKey(RequestKeys.masquerade);
it('calls initializeList api method', () => {
hook.action(user);
expect(api.initializeList).toHaveBeenCalledWith({ user });
});
it('loads data on success', () => {
hook.args.onSuccess({ data: testString });
expect(loadData).toHaveBeenCalledWith(testString);
});
});
describe('useClearMasquerade', () => {
beforeEach(() => {
jest.spyOn(apiHooks, moduleKeys.useInitializeApp).mockReturnValue(initializeApp);
hook = apiHooks.useClearMasquerade(cardId);
});
it('initializes clear request redux hook', () => {
expect(reduxHooks.useClearRequest).toHaveBeenCalledWith();
});
it('initializes useInitializeApp hook', () => {
expect(apiHooks.useInitializeApp).toHaveBeenCalledWith();
});
it('clears masquerade state and initializes app on call', () => {
hook();
expect(clearRequest).toHaveBeenCalledWith(RequestKeys.masquerade);
expect(initializeApp).toHaveBeenCalledWith();
});
});
describe('useUpdateEmailSettings', () => {
const enable = 'test-enable';
beforeEach(() => {
hook = apiHooks.useUpdateEmailSettings(cardId);
});
testInitCardHook(reduxKeys.useCardCourseRunData);
testRequestKey(RequestKeys.updateEmailSettings);
it('calls updateEmailSettings api method on call', () => {
hook.action(enable);
expect(api.updateEmailSettings).toHaveBeenCalledWith({ courseId, enable });
});
});
describe('useSendConfirmEmail', () => {
const sendEmailUrl = 'test-send-email-url';
beforeEach(() => {
reduxHooks.useEmailConfirmationData.mockReturnValue({ sendEmailUrl });
hook = apiHooks.useSendConfirmEmail(cardId);
out = hook();
});
it('initializes useEmailConfirmationData hook', () => {
expect(reduxHooks.useEmailConfirmationData).toHaveBeenCalledWith();
});
it('posts to email url on call', () => {
expect(out).toEqual(post(sendEmailUrl));
});
});
describe('useCreateCreditRequest', () => {
const username = 'test-username';
const providerId = 'test-provider-id';
beforeEach(() => {
React.useContext.mockReturnValue({ authenticatedUser: { username } });
reduxHooks.useCardCreditData.mockReturnValue({ providerId });
hook = apiHooks.useCreateCreditRequest(cardId);
});
testInitCardHook(reduxKeys.useCardCreditData);
testInitCardHook(reduxKeys.useCardCourseRunData);
it('initializes username from app context', () => {
expect(React.useContext).toHaveBeenCalledWith(AppContext);
});
it('calls createCreditRequest api method on call', () => {
out = hook();
expect(api.createCreditRequest).toHaveBeenCalledWith({
providerId,
courseId,
username,
});
});
});
});
});