Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 40 additions & 34 deletions src/taxonomy/data/apiHooks.test.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// @ts-check
import React from 'react'; // Required to use JSX syntax without type errors

import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import MockAdapter from 'axios-mock-adapter';

import { initializeMocks } from '@src/testUtils';
import { apiUrls } from './api';

import {
Expand All @@ -17,6 +14,7 @@ import {
useImportTags,
useImportNewTaxonomy,
} from './apiHooks';
import { TaxonomyType } from './constants';

let axiosMock;

Expand All @@ -30,49 +28,57 @@ const queryClient = new QueryClient({

const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
<IntlProvider locale="en">
{children}
</IntlProvider>
<IntlProvider locale="en">{children}</IntlProvider>
</QueryClientProvider>
);

const emptyFile = new File([], 'empty.csv');

const taxonomyTypes = Object.values(TaxonomyType);

describe('import taxonomy api calls', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
({ axiosMock } = initializeMocks());
});

afterEach(() => {
jest.clearAllMocks();
});

it('should call import new taxonomy', async () => {
const mockResult = {
id: 8,
name: 'Taxonomy name',
exportId: 'taxonomy_export_id',
description: 'Taxonomy description',
};
axiosMock.onPost(apiUrls.createTaxonomyFromImport()).reply(201, mockResult);
const { result } = renderHook(() => useImportNewTaxonomy(), { wrapper });
const mutateResult = await result.current.mutateAsync({
name: 'Taxonomy name',
description: 'Taxonomy description',
file: emptyFile,
});

expect(axiosMock.history.post[0].url).toEqual(apiUrls.createTaxonomyFromImport());
expect(mutateResult).toEqual(mockResult);
});
it.each(taxonomyTypes)(
'should call import new taxonomy with the %s type',
async (taxonomyType) => {
const mockResult = {
id: 8,
name: 'Taxonomy name',
exportId: 'taxonomy_export_id',
description: 'Taxonomy description',
};
axiosMock
.onPost(apiUrls.createTaxonomyFromImport())
.reply(201, mockResult);
const { result } = renderHook(() => useImportNewTaxonomy(), {
wrapper,
});
const mutateResult = await result.current.mutateAsync({
name: 'Taxonomy name',
description: 'Taxonomy description',
taxonomyType,
file: emptyFile,
});

expect(axiosMock.history.post[0].url).toEqual(
apiUrls.createTaxonomyFromImport(),
);
const formData = axiosMock.history.post[0].data;
expect(formData.get('taxonomy_name')).toEqual('Taxonomy name');
expect(formData.get('taxonomy_description')).toEqual(
'Taxonomy description',
);
expect(formData.get('taxonomy_type')).toEqual(taxonomyType);
expect(mutateResult).toEqual(mockResult);
},
);

it('should call import tags', async () => {
const taxonomy = { id: 1, name: 'taxonomy name' };
Expand Down
17 changes: 13 additions & 4 deletions src/taxonomy/data/apiHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { apiUrls, ALL_TAXONOMIES, getApiErrorMessage } from './api';
import * as api from './api';
import type { QueryOptions, TagListData } from './types';
import { TaxonomyType } from './constants';

// Query key patterns. Allows an easy way to clear all data related to a given taxonomy.
// https://github.com/openedx/frontend-app-admin-portal/blob/2ba315d/docs/decisions/0006-tanstack-react-query.rst
Expand Down Expand Up @@ -69,7 +70,12 @@ export const taxonomyQueryKeys = {
* @param taxonomyId ID of the taxonomy
* @param fileId Some string to uniquely identify the file we want to upload
*/
importPlan: (taxonomyId: number, fileId: string) => [...taxonomyQueryKeys.all, 'importPlan', taxonomyId, fileId],
importPlan: (taxonomyId: number | undefined, fileId: string) => [
...taxonomyQueryKeys.all,
'importPlan',
taxonomyId ?? '',
fileId,
],
} satisfies Record<string, (string | number)[] | ((...args: any[]) => (string | number)[])>;

/**
Expand Down Expand Up @@ -116,11 +122,13 @@ export const useImportNewTaxonomy = () => {
mutationFn: async ({
name,
description,
taxonomyType,
file,
}: { name: string; description: string; file: File; }) => {
}: { name: string; description: string; taxonomyType: TaxonomyType; file: File; }) => {
const formData = new FormData();
formData.append('taxonomy_name', name);
formData.append('taxonomy_description', description);
formData.append('taxonomy_type', taxonomyType);
formData.append('file', file);

const { data } = await getAuthenticatedHttpClient().post(apiUrls.createTaxonomyFromImport(), formData);
Expand Down Expand Up @@ -165,10 +173,11 @@ export const useImportTags = () => {

/**
* Preview the results of importing the given file into an existing taxonomy.
* @param taxonomyId The ID of the taxonomy whose tags we're updating.
* @param taxonomyId The ID of the taxonomy whose tags we're updating, or undefined if a new taxonomy is
* being created (in which case there is no plan to preview).
* @param file The file that we want to import
*/
export const useImportPlan = (taxonomyId: number, file: File | null) =>
export const useImportPlan = (taxonomyId: number | undefined, file: File | null) =>
useQuery({
queryKey: taxonomyQueryKeys.importPlan(taxonomyId, file ? `${file.name}${file.lastModified}${file.size}` : ''),
queryFn: async (): Promise<string | null> => {
Expand Down
5 changes: 5 additions & 0 deletions src/taxonomy/data/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
* will be incomplete because the backend only supports a taxonomy size of 10,000 items or fewer.
*/
export const MAX_TAXONOMY_ITEMS = 10000;

export enum TaxonomyType {
Tags = 'tags',
Competency = 'competency',
}
Loading