From 9f7bae710ce9a0ac0f738343a6ac2caee287e042 Mon Sep 17 00:00:00 2001 From: Hamzah Ullah Date: Mon, 24 Feb 2025 15:39:34 -0500 Subject: [PATCH] chore: add test --- .../enterpriseCustomerUser.factory.ts | 4 +- src/components/app/routes/data/utils.test.js | 137 +++++++++++++++++- .../UserEnrollmentForm.test.jsx | 17 ++- src/utils/tests.jsx | 35 ++++- 4 files changed, 183 insertions(+), 10 deletions(-) diff --git a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts index 64282a0d57..8c68e90ab5 100644 --- a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts +++ b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts @@ -18,8 +18,8 @@ export function authenticatedUserFactory(overrides = {}) { Factory.define('enterpriseCustomer') .attr('active', true) .attr('created', dayjs().toISOString()) - .attr('uuid', uuidv4()) - .attr('auth_org_id', uuidv4()) + .attr('uuid', () => uuidv4()) + .attr('auth_org_id', () => uuidv4()) .attr('slug', faker.lorem.slug()) .attr('name', faker.company.name()) .attr('contact_email', faker.internet.email()) diff --git a/src/components/app/routes/data/utils.test.js b/src/components/app/routes/data/utils.test.js index 8a34b48c7d..0703764416 100644 --- a/src/components/app/routes/data/utils.test.js +++ b/src/components/app/routes/data/utils.test.js @@ -1,4 +1,19 @@ -import { transformEnterpriseCustomer } from '../../data'; +import { waitFor } from '@testing-library/react'; +import { + queryEnterpriseLearnerDashboardBFF, + resolveBFFQuery, + transformEnterpriseCustomer, + updateUserActiveEnterprise, +} from '../../data'; +import { ensureActiveEnterpriseCustomerUser } from './utils'; +import { authenticatedUserFactory, enterpriseCustomerFactory } from '../../data/services/data/__factories__'; +import { generateTestPermutations } from '../../../../utils/tests'; + +jest.mock('../../data', () => ({ + ...jest.requireActual('../../data'), + updateUserActiveEnterprise: jest.fn(), + resolveBFFQuery: jest.fn(), +})); describe('transformEnterpriseCustomer', () => { it('returns null with disabled learner portal', () => { @@ -64,3 +79,123 @@ describe('transformEnterpriseCustomer', () => { }); }); }); + +describe('ensureActiveEnterpriseCustomerUser', () => { + // active enterprise customer + const mockEnterpriseCustomerOne = enterpriseCustomerFactory({ + + }); + // inactive enterprise customer + const mockEnterpriseCustomerTwo = enterpriseCustomerFactory({ + active: false, + }); + + const mockEnterpriseSlugOne = mockEnterpriseCustomerOne.slug; + + const mockActiveEnterpriseCustomer = mockEnterpriseCustomerOne; + + const mockAllLinkedEnterpriseCustomerUsers = [ + { + id: 1, + enterpriseCustomer: mockEnterpriseCustomerOne, + active: true, + }, + { + id: 2, + enterpriseCustomer: mockEnterpriseCustomerTwo, + active: false, + }, + ]; + const mockShouldUpdateActiveEnterpriseCustomerUser = false; + const mockEnterpriseLearnerData = { + enterpriseCustomer: mockEnterpriseCustomerOne, + activeEnterpriseCustomer: mockActiveEnterpriseCustomer, + allLinkedEnterpriseCustomerUsers: mockAllLinkedEnterpriseCustomerUsers, + shouldUpdateActiveEnterpriseCustomerUser: mockShouldUpdateActiveEnterpriseCustomerUser, + }; + + const mockRequestUrl = new URL(`/${mockEnterpriseSlugOne}`, 'http://localhost'); + + const mockAuthenticatedUser = authenticatedUserFactory(); + + const mockQueryClient = { + ensureQueryData: jest.fn().mockResolvedValue(), + getQueryData: jest.fn(), + setQueryData: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it.each(generateTestPermutations({ + isBFFData: [true, false], + shouldUpdateActiveEnterpriseCustomerUser: [true, false], + }))('should update active enterprise customer if shouldUpdateActiveEnterpriseCustomerUser is (%s)', async ({ + isBFFData, + shouldUpdateActiveEnterpriseCustomerUser, + }) => { + resolveBFFQuery.mockReturnValue(isBFFData ? queryEnterpriseLearnerDashboardBFF : null); + const updatedEnterpriseCustomerMetadata = shouldUpdateActiveEnterpriseCustomerUser + // If the customer is updated, we update expected output from ensureActiveEnterpriseCustomerUser and + // verify the active customer is updated + ? { + expectedEnterpriseCustomer: mockEnterpriseCustomerTwo, + timesUpdateActiveEnterpriseCustomerCalled: 1, + expectedAllLinkedEnterpriseCustomers: [ + { + id: 1, + enterpriseCustomer: mockEnterpriseCustomerOne, + active: false, + }, + { + id: 2, + enterpriseCustomer: mockEnterpriseCustomerTwo, + active: true, + }, + ], + } + // If the customer is not updated, it should return the current enterprise customer and + // not update the active enterprise + : { + expectedEnterpriseCustomer: mockEnterpriseCustomerOne, + timesUpdateActiveEnterpriseCustomerCalled: 0, + expectedAllLinkedEnterpriseCustomers: mockAllLinkedEnterpriseCustomerUsers, + }; + // If we need to update the active enterprise customer, set the inactive customer to the current enterprise customer + const updatedMockEnterpriseLearnerData = { + ...mockEnterpriseLearnerData, + enterpriseCustomer: updatedEnterpriseCustomerMetadata.expectedEnterpriseCustomer, + shouldUpdateActiveEnterpriseCustomerUser, + }; + + const { + enterpriseCustomer, + allLinkedEnterpriseCustomerUsers, + } = await ensureActiveEnterpriseCustomerUser({ + enterpriseLearnerData: updatedMockEnterpriseLearnerData, + enterpriseSlug: mockEnterpriseSlugOne, + isBFFData, + requestUrl: mockRequestUrl, + authenticatedUser: mockAuthenticatedUser, + queryClient: mockQueryClient, + }); + + await waitFor( + () => { + expect(updateUserActiveEnterprise).toHaveBeenCalledTimes( + updatedEnterpriseCustomerMetadata.timesUpdateActiveEnterpriseCustomerCalled, + ); + if (shouldUpdateActiveEnterpriseCustomerUser) { + expect(updateUserActiveEnterprise).toHaveBeenCalledWith({ + enterpriseCustomer: updatedEnterpriseCustomerMetadata.expectedEnterpriseCustomer, + }); + } + }, + ); + expect(enterpriseCustomer).toEqual(updatedEnterpriseCustomerMetadata.expectedEnterpriseCustomer); + expect(allLinkedEnterpriseCustomerUsers).toEqual( + updatedEnterpriseCustomerMetadata.expectedAllLinkedEnterpriseCustomers, + ); + }); +}); diff --git a/src/components/executive-education-2u/UserEnrollmentForm.test.jsx b/src/components/executive-education-2u/UserEnrollmentForm.test.jsx index df08f272f3..449162716f 100644 --- a/src/components/executive-education-2u/UserEnrollmentForm.test.jsx +++ b/src/components/executive-education-2u/UserEnrollmentForm.test.jsx @@ -17,11 +17,11 @@ import { LEARNER_CREDIT_SUBSIDY_TYPE, queryCanRedeemContextQueryKey, queryEnterpriseCourseEnrollments, + queryEnterpriseLearnerDashboardBFF, queryRedeemablePolicies, useCourseMetadata, useEnterpriseCourseEnrollments, useEnterpriseCustomer, - queryEnterpriseLearnerDashboardBFF, useIsBFFEnabled, } from '../app/data'; import { authenticatedUserFactory, enterpriseCustomerFactory } from '../app/data/services/data/__factories__'; @@ -259,8 +259,11 @@ describe('UserEnrollmentForm', () => { subsidyType: LEARNER_CREDIT_SUBSIDY_TYPE, }, }); + const expectedEnterpriseCustomer = isDSCEnabled + ? mockEnterpriseCustomer + : mockEnterpriseCustomerWithDisabledDataSharingConsent; if (!isDSCEnabled) { - useEnterpriseCustomer.mockReturnValue({ data: mockEnterpriseCustomerWithDisabledDataSharingConsent }); + useEnterpriseCustomer.mockReturnValue({ data: expectedEnterpriseCustomer }); } const mockExternalEnrollmentUrl = `/${mockEnterpriseCustomer.slug}/executive-education-2u/course/${mockCourseKey}/enroll/${mockCourseRunKey}`; @@ -319,12 +322,14 @@ describe('UserEnrollmentForm', () => { useStatefulEnroll.mock.calls[0][0].onSuccess(newTransaction); }); - const canRedeemQueryKey = queryCanRedeemContextQueryKey(mockEnterpriseCustomer.uuid, mockCourseKey); + const canRedeemQueryKey = queryCanRedeemContextQueryKey(expectedEnterpriseCustomer.uuid, mockCourseKey); const redeemablePoliciesQueryKey = queryRedeemablePolicies({ - enterpriseUuid: mockEnterpriseCustomer.uuid, + enterpriseUuid: expectedEnterpriseCustomer.uuid, lmsUserId: mockAuthenticatedUser.userId, }).queryKey; - const enterpriseCourseEnrollmentsQueryKey = queryEnterpriseCourseEnrollments(mockEnterpriseCustomer.uuid).queryKey; + const enterpriseCourseEnrollmentsQueryKey = queryEnterpriseCourseEnrollments( + expectedEnterpriseCustomer.uuid, + ).queryKey; const expectedQueriesToInvalidate = [ canRedeemQueryKey, redeemablePoliciesQueryKey, @@ -333,7 +338,7 @@ describe('UserEnrollmentForm', () => { if (isBFFEnabled) { const dashboardBFFQueryKey = queryEnterpriseLearnerDashboardBFF({ - enterpriseSlug: mockEnterpriseCustomer.slug, + enterpriseSlug: expectedEnterpriseCustomer.slug, }).queryKey; const expectedBFFQueriesToInvalidate = [dashboardBFFQueryKey]; expectedQueriesToInvalidate.push(...expectedBFFQueriesToInvalidate); diff --git a/src/utils/tests.jsx b/src/utils/tests.jsx index 7b8d729294..fa3a0f90f5 100644 --- a/src/utils/tests.jsx +++ b/src/utils/tests.jsx @@ -1,5 +1,5 @@ import { isValidElement } from 'react'; -import { BrowserRouter as Router, RouterProvider, createMemoryRouter } from 'react-router-dom'; +import { BrowserRouter as Router, createMemoryRouter, RouterProvider } from 'react-router-dom'; import { createMemoryHistory } from 'history'; import dayjs from 'dayjs'; import { render } from '@testing-library/react'; // eslint-disable-line import/no-extraneous-dependencies @@ -119,3 +119,36 @@ export function queryClient(defaultOptions = {}) { }, }); } + +/** + * Generates all possible permutations of an object where each key has multiple possible values. + * + * @param {Object.} options - An object where each key has an array of possible values. + * @returns {Object[]} - An array of objects containing all possible combinations of the input values. + * + * @example + * const input = { + * shouldUpdateActiveEnterpriseCustomerUser: [true, false], + * isBFFData: [true, false], + * anotherFlag: ["A", "B"] + * }; + * + * const result = generatePermutations(input); + * console.log(result); + * + * // Output: + * // [ + * // { shouldUpdateActiveEnterpriseCustomerUser: true, isBFFData: true, anotherFlag: "A" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: true, isBFFData: true, anotherFlag: "B" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: true, isBFFData: false, anotherFlag: "A" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: true, isBFFData: false, anotherFlag: "B" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: false, isBFFData: true, anotherFlag: "A" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: false, isBFFData: true, anotherFlag: "B" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: false, isBFFData: false, anotherFlag: "A" }, + * // { shouldUpdateActiveEnterpriseCustomerUser: false, isBFFData: false, anotherFlag: "B" } + * // ] + */ +export const generateTestPermutations = (options) => Object.entries(options).reduce( + (acc, [key, values]) => acc.flatMap(prev => values.map(value => ({ ...prev, [key]: value }))), + [{}], +);