Skip to content

Commit

Permalink
fix: use correct enterpriseFeatures in loaders (#1241)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamstankiewicz authored Dec 18, 2024
1 parent 400ae26 commit 71e99a3
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 8 deletions.
90 changes: 90 additions & 0 deletions src/components/app/data/queries/extractEnterpriseFeatures.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { when, resetAllWhenMocks } from 'jest-when';
import { authenticatedUserFactory, enterpriseCustomerFactory } from '../services/data/__factories__';
import extractEnterpriseFeatures from './extractEnterpriseFeatures';
import { queryEnterpriseLearner } from './queries';

const mockEnsureQueryData = jest.fn();
const mockQueryClient = {
ensureQueryData: mockEnsureQueryData,
};
const mockAuthenticatedUser = authenticatedUserFactory();
const mockEnterpriseCustomer = enterpriseCustomerFactory();

const getQueryEnterpriseLearner = ({ hasEnterpriseSlug = true } = {}) => queryEnterpriseLearner(
mockAuthenticatedUser.username,
hasEnterpriseSlug ? mockEnterpriseCustomer.slug : undefined,
);

describe('extractEnterpriseFeatures', () => {
beforeEach(() => {
jest.clearAllMocks();
resetAllWhenMocks();
});

it.each([
{
routeEnterpriseSlug: mockEnterpriseCustomer.slug,
enterpriseFeatures: { featureA: true, featureB: false },
},
{
routeEnterpriseSlug: undefined,
enterpriseFeatures: { featureA: true, featureB: false },
},
{
routeEnterpriseSlug: mockEnterpriseCustomer.slug,
enterpriseFeatures: { featureA: true, featureB: false },
},
])('should return the correct enterprise features (%s)', async ({
routeEnterpriseSlug,
enterpriseFeatures,
}) => {
const args = {
queryClient: mockQueryClient,
authenticatedUser: mockAuthenticatedUser,
enterpriseSlug: routeEnterpriseSlug,
};

const queryEnterpriseLearnerResult = {
enterpriseFeatures,
};
const queryEnterpriseLearnerQueryKey = getQueryEnterpriseLearner({
hasEnterpriseSlug: !!routeEnterpriseSlug,
}).queryKey;

when(mockEnsureQueryData)
.calledWith(
expect.objectContaining({
queryKey: queryEnterpriseLearnerQueryKey,
}),
)
.mockResolvedValue(queryEnterpriseLearnerResult);

const features = await extractEnterpriseFeatures(args);
expect(features).toEqual(enterpriseFeatures);
});

it('should throw an error if enterprise features cannot be found', async () => {
const routeEnterpriseSlug = mockEnterpriseCustomer.slug;
const args = {
queryClient: mockQueryClient,
authenticatedUser: mockAuthenticatedUser,
enterpriseSlug: routeEnterpriseSlug,
};

const queryEnterpriseLearnerQueryKey = getQueryEnterpriseLearner({
hasEnterpriseSlug: !!routeEnterpriseSlug,
}).queryKey;

when(mockEnsureQueryData)
.calledWith(
expect.objectContaining({
queryKey: queryEnterpriseLearnerQueryKey,
}),
)
.mockRejectedValue(new Error('Could not retrieve enterprise features'));

await expect(extractEnterpriseFeatures(args)).rejects.toThrow(
'Could not retrieve enterprise features',
);
});
});
27 changes: 27 additions & 0 deletions src/components/app/data/queries/extractEnterpriseFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { queryEnterpriseLearner } from './queries';

interface ExtractEnterpriseCustomerArgs {
queryClient: Types.QueryClient;
authenticatedUser: Types.AuthenticatedUser;
enterpriseSlug?: string;
}

/**
* Extracts the enterpriseFeatures from the enterpriseLearnerData for the current user and enterprise slug.
*/
async function extractEnterpriseFeatures({
queryClient,
authenticatedUser,
enterpriseSlug,
} : ExtractEnterpriseCustomerArgs) : Promise<Types.EnterpriseFeatures> {
// Retrieve linked enterprise customers for the current user from query cache, or
// fetch from the server if not available.
const linkedEnterpriseCustomersQuery = queryEnterpriseLearner(authenticatedUser.username, enterpriseSlug);
const enterpriseLearnerData = await queryClient.ensureQueryData<Types.EnterpriseLearnerData>(
linkedEnterpriseCustomersQuery,
);
const { enterpriseFeatures } = enterpriseLearnerData;
return enterpriseFeatures;
}

export default extractEnterpriseFeatures;
1 change: 1 addition & 0 deletions src/components/app/data/queries/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as extractEnterpriseCustomer } from './extractEnterpriseCustomer';
export { default as extractEnterpriseFeatures } from './extractEnterpriseFeatures';
export { default as queries } from './queryKeyFactory';

export * from './queries';
Expand Down
4 changes: 2 additions & 2 deletions src/components/app/routes/loaders/rootLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const makeRootLoader: Types.MakeRouteLoaderFunctionWithQueryClient = function ma
activeEnterpriseCustomer,
allLinkedEnterpriseCustomerUsers,
} = enterpriseLearnerData;
const { staffEnterpriseCustomer } = enterpriseLearnerData;
const { staffEnterpriseCustomer, enterpriseFeatures } = enterpriseLearnerData;

// User has no active, linked enterprise customer and no staff-only customer metadata exists; return early.
if (!enterpriseCustomer) {
Expand Down Expand Up @@ -68,7 +68,7 @@ const makeRootLoader: Types.MakeRouteLoaderFunctionWithQueryClient = function ma
userEmail,
queryClient,
requestUrl,
enterpriseFeatures: enterpriseCustomer.enterpriseFeatures,
enterpriseFeatures,
});

// Redirect to the same URL without a trailing slash, if applicable.
Expand Down
2 changes: 1 addition & 1 deletion src/components/dashboard/data/dashboardLoader.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ describe('dashboardLoader', () => {
expect(await screen.findByTestId('dashboard')).toBeInTheDocument();
}

expect(mockQueryClient.ensureQueryData).toHaveBeenCalledTimes(4);
expect(mockQueryClient.ensureQueryData).toHaveBeenCalledTimes(5);
expect(mockQueryClient.ensureQueryData).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: shouldUseBFFQuery
Expand Down
15 changes: 14 additions & 1 deletion src/components/dashboard/data/dashboardLoader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ensureAuthenticatedUser, redirectToSearchPageForNewUser } from '../../app/routes/data';
import {
extractEnterpriseCustomer,
extractEnterpriseFeatures,
queryEnterpriseCourseEnrollments,
queryEnterprisePathwaysList,
queryEnterpriseProgramsList,
Expand Down Expand Up @@ -31,19 +32,31 @@ const makeDashboardLoader: Types.MakeRouteLoaderFunctionWithQueryClient = functi
}

const { enterpriseSlug } = params;

// Extract enterprise customer.
const enterpriseCustomer = await extractEnterpriseCustomer({
queryClient,
authenticatedUser,
enterpriseSlug,
});

// Extract enterprise features.
const enterpriseFeatures = await extractEnterpriseFeatures({
queryClient,
authenticatedUser,
enterpriseSlug,
});

// Attempt to resolve the BFF query for the dashboard.
const dashboardBFFQuery = resolveBFFQuery(
requestUrl.pathname,
{
enterpriseCustomerUuid: enterpriseCustomer.uuid,
enterpriseFeatures: enterpriseCustomer.enterpriseFeatures,
enterpriseFeatures,
},
);

// Load enrollments, policies, and conditionally redirect for new users
const loadEnrollmentsPoliciesAndRedirectForNewUsers = Promise.all([
queryClient.ensureQueryData(
dashboardBFFQuery
Expand Down
10 changes: 6 additions & 4 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,19 @@ export interface EnterpriseCustomer {
slug: string;
name: string;
enableOneAcademy: boolean;
enterpriseFeatures: {
enterpriseLearnerBFFEnabled: boolean;
[key: string]: boolean;
};
}

export interface EnterpriseFeatures {
enterpriseLearnerBFFEnabled: boolean;
[key: string]: boolean;
}

export interface EnterpriseLearnerData {
enterpriseCustomer: Types.EnterpriseCustomer;
activeEnterpriseCustomer: Types.EnterpriseCustomer;
allLinkedEnterpriseCustomerUsers: any[];
staffEnterpriseCustomer: Types.EnterpriseCustomer;
enterpriseFeatures: Types.EnterpriseFeatures;
}

interface EnrollmentDueDate {
Expand Down

0 comments on commit 71e99a3

Please sign in to comment.