From 2f5ee793459be17c1f0de2cf2253b42597db17e1 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 11:27:06 -0500 Subject: [PATCH 1/7] feat: set custom logging attribute for is_bff_enabled --- .../enterprise-page/EnterprisePage.jsx | 24 +++++++++++---- .../enterprise-page/EnterprisePage.test.jsx | 29 ++++++++++++++++++- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/components/enterprise-page/EnterprisePage.jsx b/src/components/enterprise-page/EnterprisePage.jsx index b38365fb1d..9f2cde25e6 100644 --- a/src/components/enterprise-page/EnterprisePage.jsx +++ b/src/components/enterprise-page/EnterprisePage.jsx @@ -7,14 +7,15 @@ import { getLoggingService } from '@edx/frontend-platform/logging'; import { isDefinedAndNotNull } from '../../utils/common'; import { useAlgoliaSearch } from '../../utils/hooks'; import { pushUserCustomerAttributes } from '../../utils/optimizely'; -import { useEnterpriseCustomer } from '../app/data'; +import { isBFFEnabledForEnterpriseCustomer, useEnterpriseCustomer } from '../app/data'; -const EnterprisePage = ({ children }) => { +/** + * Custom hook to set custom attributes for logging service: + * - enterprise_customer_uuid - The UUID of the enterprise customer + * - is_bff_enabled - Whether the BFF is enabled for the enterprise customer + */ +function useLoggingCustomAttributes() { const { data: enterpriseCustomer } = useEnterpriseCustomer(); - const config = getConfig(); - const [searchClient, searchIndex] = useAlgoliaSearch(config); - const { authenticatedUser } = useContext(AppContext); - useEffect(() => { if (isDefinedAndNotNull(enterpriseCustomer)) { pushUserCustomerAttributes(enterpriseCustomer); @@ -22,8 +23,19 @@ const EnterprisePage = ({ children }) => { // Set custom attributes for logging service const loggingService = getLoggingService(); loggingService.setCustomAttribute('enterprise_customer_uuid', enterpriseCustomer.uuid); + const isBFFEnabled = isBFFEnabledForEnterpriseCustomer(enterpriseCustomer.uuid); + loggingService.setCustomAttribute('is_bff_enabled', isBFFEnabled); } }, [enterpriseCustomer]); +} + +const EnterprisePage = ({ children }) => { + const config = getConfig(); + const [searchClient, searchIndex] = useAlgoliaSearch(config); + const { authenticatedUser } = useContext(AppContext); + + // Set custom attributes via logging service + useLoggingCustomAttributes(); const contextValue = useMemo(() => ({ authenticatedUser, diff --git a/src/components/enterprise-page/EnterprisePage.test.jsx b/src/components/enterprise-page/EnterprisePage.test.jsx index e9f163fc27..4e14f206f9 100644 --- a/src/components/enterprise-page/EnterprisePage.test.jsx +++ b/src/components/enterprise-page/EnterprisePage.test.jsx @@ -30,7 +30,12 @@ describe('', () => { useEnterpriseCustomer.mockReturnValue({ data: mockEnterpriseCustomer }); }); - const defaultAppContextValue = { authenticatedUser: mockAuthenticatedUser }; + const defaultAppContextValue = { + authenticatedUser: mockAuthenticatedUser, + config: { + FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS: [], + }, + }; const EnterprisePageWrapper = ({ children, appContextValue = defaultAppContextValue }) => ( @@ -70,4 +75,26 @@ describe('', () => { }), ); }); + + it.each([ + { isBFFEnabled: false }, + { isBFFEnabled: true }, + ])('sets custom attributes via logging service', ({ isBFFEnabled }) => { + // Mock the BFF-related feature flag + const bffFeatureFlag = isBFFEnabled ? [mockEnterpriseCustomer.uuid] : []; + const appContextValueWithBFFConfig = { + authenticatedUser: mockAuthenticatedUser, + config: { + FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS: bffFeatureFlag, + }, + }; + + // Mount the component + mount(); + + // Verify that the custom attributes were set + expect(mockSetCustomAttribute).toHaveBeenCalledTimes(2); + expect(mockSetCustomAttribute).toHaveBeenCalledWith('enterprise_customer_uuid', mockEnterpriseCustomer.uuid); + expect(mockSetCustomAttribute).toHaveBeenCalledWith('is_bff_enabled', isBFFEnabled); + }); }); From b8b2ccf89bda7c6166e544c8fca6a15b5c25f2f7 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 11:29:35 -0500 Subject: [PATCH 2/7] feat: create helper function to make BFF requests with logError and logInfo --- src/components/app/data/services/bffs.js | 72 +++++++++++++-- src/components/app/data/services/bffs.test.js | 88 ++++++++++++++++--- 2 files changed, 140 insertions(+), 20 deletions(-) diff --git a/src/components/app/data/services/bffs.js b/src/components/app/data/services/bffs.js index 65b6e0b33a..30e30a85a0 100644 --- a/src/components/app/data/services/bffs.js +++ b/src/components/app/data/services/bffs.js @@ -1,7 +1,7 @@ import { getConfig } from '@edx/frontend-platform/config'; -import { logError } from '@edx/frontend-platform/logging'; +import { logError, logInfo } from '@edx/frontend-platform/logging'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; -import { camelCaseObject } from '@edx/frontend-platform/utils'; +import { camelCaseObject, snakeCaseObject } from '@edx/frontend-platform/utils'; export const baseLearnerBFFResponse = { enterpriseCustomerUserSubsidies: { @@ -20,19 +20,73 @@ export const learnerDashboardBFFResponse = { enterpriseCourseEnrollments: [], }; -export async function fetchEnterpriseLearnerDashboard(customerIdentifiers) { - const { ENTERPRISE_ACCESS_BASE_URL } = getConfig(); - const url = `${ENTERPRISE_ACCESS_BASE_URL}/api/v1/bffs/learner/dashboard/`; +/** + * Log any errors and warnings from the BFF response. + * @param {Object} args + * @param {String} args.url - The URL of the BFF API endpoint. + * @param {Object} args.response - The camelCased response from the BFF API endpoint. + */ +export function logErrorsAndWarningsFromBFFResponse({ url, response }) { + response.errors.forEach((error) => { + logError(`BFF Error (${url}): ${error.developerMessage}`); + }); + response.warnings.forEach((warning) => { + logInfo(`BFF Warning (${url}): ${warning.developerMessage}`); + }); +} + +/** + * Make a request to the specified BFF API endpoint. + * @param {Object} args + * @param {String} args.url - The URL of the BFF API endpoint. + * @param {Object} args.defaultResponse - The default response to return if unable to resolve the request. + * @param {Object} args.options - The options to pass to the BFF API endpoint. + * @param {String} args.options.enterpriseId - The UUID of the enterprise customer. + * @param {String} args.options.enterpriseSlug - The slug of the enterprise customer. + * @returns {Promise} - The response from the BFF. + */ +export async function makeBFFRequest({ url, defaultResponse, options = {} }) { + const { enterpriseId, enterpriseSlug, ...optionsRest } = options; + const snakeCaseOptionsRest = optionsRest ? snakeCaseObject(optionsRest) : {}; + + // If neither enterpriseId or enterpriseSlug is provided, return the default response. + if (!enterpriseId && !enterpriseSlug) { + return defaultResponse; + } + try { const params = { - enterprise_customer_uuid: customerIdentifiers?.enterpriseId, - enterprise_customer_slug: customerIdentifiers?.enterpriseSlug, + enterprise_customer_uuid: enterpriseId, + enterprise_customer_slug: enterpriseSlug, + ...snakeCaseOptionsRest, }; + // Make request to BFF. const result = await getAuthenticatedHttpClient().post(url, params); - return camelCaseObject(result.data); + const response = camelCaseObject(result.data); + + // Log any errors and warnings from the BFF response. + logErrorsAndWarningsFromBFFResponse({ url, response }); + + // Return the response from the BFF. + return response; } catch (error) { logError(error); - return learnerDashboardBFFResponse; + return defaultResponse; } } + +/** + * Fetch the learner dashboard BFF API for the specified enterprise customer. + * @param {Object} args + * @param {String} args.enterpriseId - The UUID of the enterprise customer. + * @param {String} args.enterpriseSlug - The slug of the enterprise customer. + * @returns {Promise} - The learner dashboard metadata. + */ +export async function fetchEnterpriseLearnerDashboard({ enterpriseId, enterpriseSlug }) { + return makeBFFRequest({ + url: `${getConfig().ENTERPRISE_ACCESS_BASE_URL}/api/v1/bffs/learner/dashboard/`, + defaultResponse: learnerDashboardBFFResponse, + options: { enterpriseId, enterpriseSlug }, + }); +} diff --git a/src/components/app/data/services/bffs.test.js b/src/components/app/data/services/bffs.test.js index aced16f1b6..450138c851 100644 --- a/src/components/app/data/services/bffs.test.js +++ b/src/components/app/data/services/bffs.test.js @@ -1,6 +1,7 @@ import MockAdapter from 'axios-mock-adapter'; import axios from 'axios'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { logError, logInfo } from '@edx/frontend-platform/logging'; import { v4 as uuidv4 } from 'uuid'; import { camelCaseObject } from '@edx/frontend-platform'; @@ -13,15 +14,20 @@ getAuthenticatedHttpClient.mockReturnValue(axios); const APP_CONFIG = { ENTERPRISE_ACCESS_BASE_URL: 'http://localhost:18270', }; + jest.mock('@edx/frontend-platform/config', () => ({ ...jest.requireActual('@edx/frontend-platform'), getConfig: jest.fn(() => APP_CONFIG), })); - jest.mock('@edx/frontend-platform/auth', () => ({ ...jest.requireActual('@edx/frontend-platform/auth'), getAuthenticatedHttpClient: jest.fn(), })); +jest.mock('@edx/frontend-platform/logging', () => ({ + ...jest.requireActual('@edx/frontend-platform/logging'), + logError: jest.fn(), + logInfo: jest.fn(), +})); const mockEnterpriseCustomer = enterpriseCustomerFactory(); const mockCustomerAgreementUuid = uuidv4(); @@ -29,7 +35,8 @@ const mockSubscriptionCatalogUuid = uuidv4(); const mockSubscriptionLicenseUuid = uuidv4(); const mockSubscriptionPlanUuid = uuidv4(); const mockActivationKey = uuidv4(); -const mockBFFDashboardResponse = { + +const mockBaseLearnerBFFResponse = { enterprise_customer_user_subsidies: { subscriptions: { customer_agreement: { @@ -96,6 +103,12 @@ const mockBFFDashboardResponse = { }, }, }, + errors: [], + warnings: [], +}; + +const mockBFFDashboardResponse = { + ...mockBaseLearnerBFFResponse, enterprise_course_enrollments: [ { course_run_id: 'course-v1:edX+DemoX+3T2022', @@ -119,25 +132,78 @@ const mockBFFDashboardResponse = { is_revoked: false, }, ], - errors: [], - warnings: [], }; + describe('fetchEnterpriseLearnerDashboard', () => { - const enterpriseDashboard = `${APP_CONFIG.ENTERPRISE_ACCESS_BASE_URL}/api/v1/bffs/learner/dashboard/`; + const urlForDashboardBFF = `${APP_CONFIG.ENTERPRISE_ACCESS_BASE_URL}/api/v1/bffs/learner/dashboard/`; + beforeEach(() => { jest.clearAllMocks(); axiosMock.reset(); }); - it('returns learner dashboard metadata', async () => { - axiosMock.onPost(enterpriseDashboard).reply(200, mockBFFDashboardResponse); - const result = await fetchEnterpriseLearnerDashboard({ enterpriseId: mockEnterpriseCustomer.uuid }); + it.each([ + { + enterpriseId: mockEnterpriseCustomer.uuid, + enterpriseSlug: null, + }, + { + enterpriseId: null, + enterpriseSlug: mockEnterpriseCustomer.slug, + }, + { + enterpriseId: mockEnterpriseCustomer.uuid, + enterpriseSlug: mockEnterpriseCustomer.slug, + }, + ])('returns learner dashboard metadata (%s)', async ({ + enterpriseId, + enterpriseSlug, + }) => { + axiosMock.onPost(urlForDashboardBFF).reply(200, mockBFFDashboardResponse); + const result = await fetchEnterpriseLearnerDashboard({ enterpriseId, enterpriseSlug }); expect(result).toEqual(camelCaseObject(mockBFFDashboardResponse)); }); - it('catches error and returns null', async () => { - axiosMock.onPost(enterpriseDashboard).reply(404, learnerDashboardBFFResponse); - const result = await fetchEnterpriseLearnerDashboard(null); + it.each([ + { + enterpriseId: mockEnterpriseCustomer.uuid, + enterpriseSlug: null, + }, + { + enterpriseId: null, + enterpriseSlug: mockEnterpriseCustomer.slug, + }, + { + enterpriseId: mockEnterpriseCustomer.uuid, + enterpriseSlug: mockEnterpriseCustomer.slug, + }, + ])('catches error and returns default dashboard BFF response (%s)', async ({ + enterpriseId, + enterpriseSlug, + }) => { + axiosMock.onPost(urlForDashboardBFF).reply(404, learnerDashboardBFFResponse); + const result = await fetchEnterpriseLearnerDashboard({ enterpriseId, enterpriseSlug }); expect(result).toEqual(learnerDashboardBFFResponse); }); + + it('logs errors and warnings from BFF response', async () => { + const mockError = { + developer_message: 'This is a developer message', + }; + const mockWarning = { + developer_message: 'This is a developer warning', + }; + const mockResponseWithErrorsAndWarnings = { + ...mockBFFDashboardResponse, + errors: [mockError], + warnings: [mockWarning], + }; + axiosMock.onPost(urlForDashboardBFF).reply(200, mockResponseWithErrorsAndWarnings); + const result = await fetchEnterpriseLearnerDashboard({ enterpriseSlug: mockEnterpriseCustomer.slug }); + expect(result).toEqual(camelCaseObject(mockResponseWithErrorsAndWarnings)); + + // Assert the logError and logInfo functions were called with the expected arguments. + expect(logError).toHaveBeenCalledWith(`BFF Error (${urlForDashboardBFF}): ${mockError.developer_message}`); + expect(logInfo).toHaveBeenCalledWith(`BFF Warning (${urlForDashboardBFF}): ${mockWarning.developer_message}`); + }); }); From fb57c1278df4f15164fd4fbd15c8e7d43776ae1f Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 11:36:46 -0500 Subject: [PATCH 3/7] chore: docstring update --- src/components/app/data/services/bffs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/app/data/services/bffs.js b/src/components/app/data/services/bffs.js index 30e30a85a0..14a4fcbae1 100644 --- a/src/components/app/data/services/bffs.js +++ b/src/components/app/data/services/bffs.js @@ -41,8 +41,8 @@ export function logErrorsAndWarningsFromBFFResponse({ url, response }) { * @param {String} args.url - The URL of the BFF API endpoint. * @param {Object} args.defaultResponse - The default response to return if unable to resolve the request. * @param {Object} args.options - The options to pass to the BFF API endpoint. - * @param {String} args.options.enterpriseId - The UUID of the enterprise customer. - * @param {String} args.options.enterpriseSlug - The slug of the enterprise customer. + * @param {String} [args.options.enterpriseId] - The UUID of the enterprise customer. + * @param {String} [args.options.enterpriseSlug] - The slug of the enterprise customer. * @returns {Promise} - The response from the BFF. */ export async function makeBFFRequest({ url, defaultResponse, options = {} }) { @@ -79,8 +79,8 @@ export async function makeBFFRequest({ url, defaultResponse, options = {} }) { /** * Fetch the learner dashboard BFF API for the specified enterprise customer. * @param {Object} args - * @param {String} args.enterpriseId - The UUID of the enterprise customer. - * @param {String} args.enterpriseSlug - The slug of the enterprise customer. + * @param {String} [args.enterpriseId] - The UUID of the enterprise customer. + * @param {String} [args.enterpriseSlug] - The slug of the enterprise customer. * @returns {Promise} - The learner dashboard metadata. */ export async function fetchEnterpriseLearnerDashboard({ enterpriseId, enterpriseSlug }) { From 71d968500061dd0ac065b9daf2d2c72ebda6a13a Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 11:58:55 -0500 Subject: [PATCH 4/7] refactor: move bffs service file to TS --- .../services/{bffs.test.js => bffs.test.ts} | 10 ++++---- .../app/data/services/{bffs.js => bffs.ts} | 25 ++++++++++++++++--- src/types.d.ts | 12 +++++++-- 3 files changed, 37 insertions(+), 10 deletions(-) rename src/components/app/data/services/{bffs.test.js => bffs.test.ts} (97%) rename src/components/app/data/services/{bffs.js => bffs.ts} (84%) diff --git a/src/components/app/data/services/bffs.test.js b/src/components/app/data/services/bffs.test.ts similarity index 97% rename from src/components/app/data/services/bffs.test.js rename to src/components/app/data/services/bffs.test.ts index 450138c851..6ca3fb1c09 100644 --- a/src/components/app/data/services/bffs.test.js +++ b/src/components/app/data/services/bffs.test.ts @@ -29,7 +29,7 @@ jest.mock('@edx/frontend-platform/logging', () => ({ logInfo: jest.fn(), })); -const mockEnterpriseCustomer = enterpriseCustomerFactory(); +const mockEnterpriseCustomer = enterpriseCustomerFactory() as Types.EnterpriseCustomer; const mockCustomerAgreementUuid = uuidv4(); const mockSubscriptionCatalogUuid = uuidv4(); const mockSubscriptionLicenseUuid = uuidv4(); @@ -145,10 +145,10 @@ describe('fetchEnterpriseLearnerDashboard', () => { it.each([ { enterpriseId: mockEnterpriseCustomer.uuid, - enterpriseSlug: null, + enterpriseSlug: undefined, }, { - enterpriseId: null, + enterpriseId: undefined, enterpriseSlug: mockEnterpriseCustomer.slug, }, { @@ -167,10 +167,10 @@ describe('fetchEnterpriseLearnerDashboard', () => { it.each([ { enterpriseId: mockEnterpriseCustomer.uuid, - enterpriseSlug: null, + enterpriseSlug: undefined, }, { - enterpriseId: null, + enterpriseId: undefined, enterpriseSlug: mockEnterpriseCustomer.slug, }, { diff --git a/src/components/app/data/services/bffs.js b/src/components/app/data/services/bffs.ts similarity index 84% rename from src/components/app/data/services/bffs.js rename to src/components/app/data/services/bffs.ts index 14a4fcbae1..cc1bac8d3a 100644 --- a/src/components/app/data/services/bffs.js +++ b/src/components/app/data/services/bffs.ts @@ -45,7 +45,11 @@ export function logErrorsAndWarningsFromBFFResponse({ url, response }) { * @param {String} [args.options.enterpriseSlug] - The slug of the enterprise customer. * @returns {Promise} - The response from the BFF. */ -export async function makeBFFRequest({ url, defaultResponse, options = {} }) { +export async function makeBFFRequest({ + url, + defaultResponse, + options = {} as Types.BFFRequestOptions, +}) { const { enterpriseId, enterpriseSlug, ...optionsRest } = options; const snakeCaseOptionsRest = optionsRest ? snakeCaseObject(optionsRest) : {}; @@ -76,6 +80,11 @@ export async function makeBFFRequest({ url, defaultResponse, options = {} }) { } } +export interface EnterpriseLearnerDashboardOptions { + enterpriseId?: string; + enterpriseSlug?: string; +} + /** * Fetch the learner dashboard BFF API for the specified enterprise customer. * @param {Object} args @@ -83,10 +92,20 @@ export async function makeBFFRequest({ url, defaultResponse, options = {} }) { * @param {String} [args.enterpriseSlug] - The slug of the enterprise customer. * @returns {Promise} - The learner dashboard metadata. */ -export async function fetchEnterpriseLearnerDashboard({ enterpriseId, enterpriseSlug }) { +export async function fetchEnterpriseLearnerDashboard({ + enterpriseId, + enterpriseSlug, +}: EnterpriseLearnerDashboardOptions) { + const options = {} as Types.BFFRequestOptions; + if (enterpriseId) { + options.enterpriseId = enterpriseId; + } + if (enterpriseSlug) { + options.enterpriseSlug = enterpriseSlug; + } return makeBFFRequest({ url: `${getConfig().ENTERPRISE_ACCESS_BASE_URL}/api/v1/bffs/learner/dashboard/`, defaultResponse: learnerDashboardBFFResponse, - options: { enterpriseId, enterpriseSlug }, + options, }); } diff --git a/src/types.d.ts b/src/types.d.ts index 094568314d..4a4a0d56f0 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -29,6 +29,14 @@ export interface AuthenticatedUser { administrator: boolean; } +export interface BFFRequestAdditionalOptions { + [key: string]: any; // Allow any additional properties +} + +export type BFFRequestOptions = + | ({ enterpriseId: string; enterpriseSlug?: string; } & BFFRequestAdditionalOptions) + | ({ enterpriseId?: string; enterpriseSlug: string; } & BFFRequestAdditionalOptions); + export interface EnterpriseCustomer { uuid: string; slug: string; @@ -43,7 +51,7 @@ export interface EnterpriseLearnerData { staffEnterpriseCustomer: Types.EnterpriseCustomer; } -interface DueDate { +interface EnrollmentDueDate { name: string; date: string; url: string; @@ -69,7 +77,7 @@ export interface EnterpriseCourseEnrollment { course_run_url: string; resume_course_run_url?: string; is_revoked: boolean; - due_dates: DueDate[]; + due_dates: EnrollmentDueDate[]; } // Application Data (subsidy) From 7d890ab732666eaad4b99df50f755287f69f162f Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 12:16:21 -0500 Subject: [PATCH 5/7] chore: tests --- src/components/app/data/utils.js | 1 + .../enterprise-page/EnterprisePage.jsx | 8 ++++--- .../enterprise-page/EnterprisePage.test.jsx | 24 ++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/components/app/data/utils.js b/src/components/app/data/utils.js index 5489b53dc0..c84f6ea63b 100644 --- a/src/components/app/data/utils.js +++ b/src/components/app/data/utils.js @@ -887,6 +887,7 @@ export function transformCourseMetadataByAllocatedCourseRunAssignments({ export function isBFFEnabledForEnterpriseCustomer(enterpriseCustomerUuid) { const { FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS } = getConfig(); + console.log('FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS', FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS); if (!FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS) { return false; } diff --git a/src/components/enterprise-page/EnterprisePage.jsx b/src/components/enterprise-page/EnterprisePage.jsx index 9f2cde25e6..b4024a549f 100644 --- a/src/components/enterprise-page/EnterprisePage.jsx +++ b/src/components/enterprise-page/EnterprisePage.jsx @@ -20,11 +20,13 @@ function useLoggingCustomAttributes() { if (isDefinedAndNotNull(enterpriseCustomer)) { pushUserCustomerAttributes(enterpriseCustomer); - // Set custom attributes for logging service + // Set custom attributes via logging service const loggingService = getLoggingService(); loggingService.setCustomAttribute('enterprise_customer_uuid', enterpriseCustomer.uuid); - const isBFFEnabled = isBFFEnabledForEnterpriseCustomer(enterpriseCustomer.uuid); - loggingService.setCustomAttribute('is_bff_enabled', isBFFEnabled); + loggingService.setCustomAttribute( + 'is_bff_enabled', + isBFFEnabledForEnterpriseCustomer(enterpriseCustomer.uuid), + ); } }, [enterpriseCustomer]); } diff --git a/src/components/enterprise-page/EnterprisePage.test.jsx b/src/components/enterprise-page/EnterprisePage.test.jsx index 4e14f206f9..29de7aa7a9 100644 --- a/src/components/enterprise-page/EnterprisePage.test.jsx +++ b/src/components/enterprise-page/EnterprisePage.test.jsx @@ -4,12 +4,13 @@ import { AppContext } from '@edx/frontend-platform/react'; import { getLoggingService } from '@edx/frontend-platform/logging'; import EnterprisePage from './EnterprisePage'; -import { useEnterpriseCustomer } from '../app/data'; +import { isBFFEnabledForEnterpriseCustomer, useEnterpriseCustomer } from '../app/data'; import { authenticatedUserFactory, enterpriseCustomerFactory } from '../app/data/services/data/__factories__'; jest.mock('../app/data', () => ({ ...jest.requireActual('../app/data'), useEnterpriseCustomer: jest.fn(), + isBFFEnabledForEnterpriseCustomer: jest.fn().mockReturnValue(false), })); const mockEnterpriseCustomer = enterpriseCustomerFactory(); @@ -79,18 +80,19 @@ describe('', () => { it.each([ { isBFFEnabled: false }, { isBFFEnabled: true }, - ])('sets custom attributes via logging service', ({ isBFFEnabled }) => { - // Mock the BFF-related feature flag - const bffFeatureFlag = isBFFEnabled ? [mockEnterpriseCustomer.uuid] : []; - const appContextValueWithBFFConfig = { - authenticatedUser: mockAuthenticatedUser, - config: { - FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS: bffFeatureFlag, - }, - }; + ])('sets custom attributes via logging service (%s)', ({ isBFFEnabled }) => { + // Mock the BFF feature flag + isBFFEnabledForEnterpriseCustomer.mockReturnValue(isBFFEnabled); // Mount the component - mount(); + const wrapper = mount( + +
+ , + ); + + // Verify the children are rendered + expect(wrapper.find('[data-testid="child-component"]').exists()).toBe(true); // Verify that the custom attributes were set expect(mockSetCustomAttribute).toHaveBeenCalledTimes(2); From af2ad79bc8e7085094e0cefca3fa4890f6146732 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 12:54:55 -0500 Subject: [PATCH 6/7] chore: cover addtl case in tests --- src/components/app/data/services/bffs.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/app/data/services/bffs.test.ts b/src/components/app/data/services/bffs.test.ts index 6ca3fb1c09..2f7cbbf309 100644 --- a/src/components/app/data/services/bffs.test.ts +++ b/src/components/app/data/services/bffs.test.ts @@ -177,6 +177,10 @@ describe('fetchEnterpriseLearnerDashboard', () => { enterpriseId: mockEnterpriseCustomer.uuid, enterpriseSlug: mockEnterpriseCustomer.slug, }, + { + enterpriseId: undefined, + enterpriseSlug: undefined, + }, ])('catches error and returns default dashboard BFF response (%s)', async ({ enterpriseId, enterpriseSlug, From 93ebcc7ceea7e86428660cc3b6e4c2eb6fcb573d Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Tue, 10 Dec 2024 14:13:17 -0500 Subject: [PATCH 7/7] refactor: annotate enterpriseCustomerFactory with Types.EnterpriseCustomer --- src/components/app/data/services/bffs.test.ts | 2 +- ...ustomerUser.factory.js => enterpriseCustomerUser.factory.ts} | 2 +- src/components/app/data/utils.js | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename src/components/app/data/services/data/__factories__/{enterpriseCustomerUser.factory.js => enterpriseCustomerUser.factory.ts} (96%) diff --git a/src/components/app/data/services/bffs.test.ts b/src/components/app/data/services/bffs.test.ts index 2f7cbbf309..3fe65a4ea7 100644 --- a/src/components/app/data/services/bffs.test.ts +++ b/src/components/app/data/services/bffs.test.ts @@ -29,7 +29,7 @@ jest.mock('@edx/frontend-platform/logging', () => ({ logInfo: jest.fn(), })); -const mockEnterpriseCustomer = enterpriseCustomerFactory() as Types.EnterpriseCustomer; +const mockEnterpriseCustomer = enterpriseCustomerFactory(); const mockCustomerAgreementUuid = uuidv4(); const mockSubscriptionCatalogUuid = uuidv4(); const mockSubscriptionLicenseUuid = uuidv4(); diff --git a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts similarity index 96% rename from src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js rename to src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts index cab510dc53..64282a0d57 100644 --- a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js +++ b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.ts @@ -37,7 +37,7 @@ Factory.define('enterpriseCustomer') secondary_color: faker.internet.color(), tertiary_color: faker.internet.color(), }); -export function enterpriseCustomerFactory(overrides = {}) { +export function enterpriseCustomerFactory(overrides = {}): Types.EnterpriseCustomer { return camelCaseObject(Factory.build('enterpriseCustomer', overrides)); } diff --git a/src/components/app/data/utils.js b/src/components/app/data/utils.js index c84f6ea63b..5489b53dc0 100644 --- a/src/components/app/data/utils.js +++ b/src/components/app/data/utils.js @@ -887,7 +887,6 @@ export function transformCourseMetadataByAllocatedCourseRunAssignments({ export function isBFFEnabledForEnterpriseCustomer(enterpriseCustomerUuid) { const { FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS } = getConfig(); - console.log('FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS', FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS); if (!FEATURE_ENABLE_BFF_API_FOR_ENTERPRISE_CUSTOMERS) { return false; }