Skip to content

Commit ec157ca

Browse files
committed
test: ImpoertStepperModal.test added
1 parent 68edfa1 commit ec157ca

7 files changed

Lines changed: 169 additions & 6 deletions

File tree

src/course-outline/data/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export interface CourseOutline {
2626

2727
// TODO: This interface has only basic data, all the rest needs to be added.
2828
export interface CourseDetails {
29-
course_id: string;
29+
courseId: string;
3030
title: string;
3131
subtitle?: string;
3232
org: string;
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import userEvent from '@testing-library/user-event';
2+
import {
3+
initializeMocks,
4+
render,
5+
screen,
6+
fireEvent,
7+
waitFor,
8+
} from '@src/testUtils';
9+
import { initialState } from '@src/studio-home/factories/mockApiResponses';
10+
import { RequestStatus } from '@src/data/constants';
11+
import { type DeprecatedReduxState } from '@src/store';
12+
import studioHomeMock from '@src/studio-home/__mocks__/studioHomeMock';
13+
import { mockGetMigrationInfo } from '@src/studio-home/data/api.mocks';
14+
import { getCourseDetailsApiUrl } from '@src/course-outline/data/api';
15+
import { ImportStepperModal } from './ImportStepperModal';
16+
17+
let axiosMock;
18+
mockGetMigrationInfo.applyMock();
19+
type StudioHomeState = DeprecatedReduxState['studioHome'];
20+
21+
const libraryKey = 'lib:org:lib1';
22+
const mockOnClose = jest.fn();
23+
const numPages = 1;
24+
const coursesCount = studioHomeMock.courses.length;
25+
26+
const renderComponent = (studioHomeState: Partial<StudioHomeState> = {}) => {
27+
// Generate a custom initial state based on studioHomeCoursesRequestParams
28+
const customInitialState: Partial<DeprecatedReduxState> = {
29+
...initialState,
30+
studioHome: {
31+
...initialState.studioHome,
32+
studioHomeData: {
33+
courses: studioHomeMock.courses,
34+
numPages,
35+
coursesCount,
36+
},
37+
loadingStatuses: {
38+
...initialState.studioHome.loadingStatuses,
39+
courseLoadingStatus: RequestStatus.SUCCESSFUL,
40+
},
41+
...studioHomeState,
42+
},
43+
};
44+
45+
// Initialize the store with the custom initial state
46+
const newMocks = initializeMocks({ initialState: customInitialState });
47+
const store = newMocks.reduxStore;
48+
axiosMock = newMocks.axiosMock;
49+
50+
return {
51+
...render(
52+
<ImportStepperModal
53+
libraryKey={libraryKey}
54+
onClose={mockOnClose}
55+
isOpen
56+
/>,
57+
),
58+
store,
59+
};
60+
};
61+
62+
describe('<ImportStepperModal />', () => {
63+
it('should render correctly', async () => {
64+
renderComponent();
65+
// Renders the stepper header
66+
expect(await screen.findByText('Select Course')).toBeInTheDocument();
67+
expect(await screen.findByText('Review Import Details')).toBeInTheDocument();
68+
69+
// Renders the course list and previously imported chip
70+
expect(screen.getByText(/managing risk in the information age/i)).toBeInTheDocument();
71+
expect(screen.getByText(/run 0/i)).toBeInTheDocument();
72+
expect(await screen.findByText('Previously Imported')).toBeInTheDocument();
73+
74+
// Renders cancel and next step buttons
75+
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
76+
expect(screen.getByRole('button', { name: /next step/i })).toBeInTheDocument();
77+
});
78+
79+
it('should cancel the import', async () => {
80+
const user = userEvent.setup();
81+
renderComponent();
82+
83+
const cancelButon = await screen.findByRole('button', { name: /cancel/i });
84+
await user.click(cancelButon);
85+
86+
expect(mockOnClose).toHaveBeenCalled();
87+
});
88+
89+
it('should go to review import details step', async () => {
90+
const user = userEvent.setup();
91+
renderComponent();
92+
axiosMock.onGet(getCourseDetailsApiUrl('course-v1:HarvardX+123+2023')).reply(200, {
93+
courseId: 'course-v1:HarvardX+123+2023',
94+
title: 'Managing Risk in the Information Age',
95+
subtitle: '',
96+
org: 'HarvardX',
97+
description: 'This is a test course',
98+
});
99+
100+
const nextButton = await screen.findByRole('button', { name: /next step/i });
101+
expect(nextButton).toBeDisabled();
102+
103+
// Select a course
104+
const courseCard = screen.getAllByRole('radio')[0];
105+
await fireEvent.click(courseCard);
106+
expect(courseCard).toBeChecked();
107+
108+
// Click next
109+
expect(nextButton).toBeEnabled();
110+
await user.click(nextButton);
111+
112+
await waitFor(async () => expect(await screen.findByText(
113+
/managing risk in the information age is being analyzed for review prior to import/i,
114+
)).toBeInTheDocument());
115+
116+
expect(screen.getByText('Analysis Summary')).toBeInTheDocument();
117+
expect(screen.getByText('Import Details')).toBeInTheDocument();
118+
// The import details is loading
119+
expect(screen.getByText('The selected course is being analyzed for import and review')).toBeInTheDocument();
120+
});
121+
122+
it('the course should remain selected on back', async () => {
123+
const user = userEvent.setup();
124+
renderComponent();
125+
126+
const nextButton = await screen.findByRole('button', { name: /next step/i });
127+
expect(nextButton).toBeDisabled();
128+
129+
// Select a course
130+
const courseCard = screen.getAllByRole('radio')[0];
131+
await fireEvent.click(courseCard);
132+
expect(courseCard).toBeChecked();
133+
134+
// Click next
135+
expect(nextButton).toBeEnabled();
136+
await user.click(nextButton);
137+
138+
const backButton = await screen.getByRole('button', { name: /back/i });
139+
await user.click(backButton);
140+
141+
expect(screen.getByText(/managing risk in the information age/i)).toBeInTheDocument();
142+
expect(courseCard).toBeChecked();
143+
});
144+
});

src/library-authoring/course-import/ImportStepperModal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ export const ImportStepperModal = ({
6565
<ModalDialog.CloseButton variant="tertiary">
6666
<FormattedMessage {...messages.importCourseCalcel} />
6767
</ModalDialog.CloseButton>
68-
<Button onClick={() => setCurrentStep('review-details')}>
68+
<Button
69+
onClick={() => setCurrentStep('review-details')}
70+
disabled={selectedCourseId === undefined}
71+
>
6972
<FormattedMessage {...messages.importCourseNext} />
7073
</Button>
7174
</ActionRow>

src/library-authoring/course-import/ReviewImportDetails.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { useCourseDetails } from '@src/course-outline/data/apiHooks';
77
import messages from './messages';
88

99
export const ReviewImportDetails = ({ courseId }: { courseId?: string }) => {
10-
const { data } = useCourseDetails(courseId);
10+
const { data, isPending } = useCourseDetails(courseId);
1111

1212
return (
1313
<Stack gap={4}>
1414
<Card>
15-
{data ? (
15+
{data && !isPending ? (
1616
<Card.Section>
1717
<h4><FormattedMessage {...messages.importCourseInProgressStatusTitle} /></h4>
1818
<p>

src/studio-home/data/api.mocks.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { camelCaseObject } from '@edx/frontend-platform';
22

33
import { createAxiosError } from '@src/testUtils';
44
import * as api from './api';
5-
import { generateGetStudioHomeLibrariesApiResponse } from '../factories/mockApiResponses';
5+
import { generateGetStudioHomeLibrariesApiResponse, generateGetMigrationInfo } from '../factories/mockApiResponses';
66

77
/**
88
* Mock for `getContentLibraryV2List()`
@@ -21,3 +21,9 @@ export const mockGetStudioHomeLibraries = {
2121
libraries: [],
2222
}),
2323
};
24+
25+
export const mockGetMigrationInfo = {
26+
applyMock: () => jest.spyOn(api, 'getMigrationInfo').mockResolvedValue(
27+
camelCaseObject(generateGetMigrationInfo()),
28+
),
29+
};

src/studio-home/factories/mockApiResponses.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,13 @@ export const generateNewVideoApiResponse = () => ({
166166
upload_url: 'http://testing.org',
167167
}],
168168
});
169+
170+
export const generateGetMigrationInfo = () => ({
171+
'course-v1:HarvardX+123+2023': [{
172+
sourceKey: 'course-v1:HarvardX+123+2023',
173+
targetCollectionKey: 'ltc:org:coll-1',
174+
targetCollectionTitle: 'Collection 1',
175+
targetKey: 'lib:org:lib1',
176+
targetTitle: 'Library 1',
177+
}],
178+
});

src/studio-home/tabs-section/courses-tab/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const CardList = ({
6666

6767
const {
6868
data: migrationInfoData,
69-
} = useMigrationInfo(courses?.map(item => item.courseKey) || [], true);
69+
} = useMigrationInfo(courses?.map(item => item.courseKey) || [], currentLibraryId !== undefined);
7070

7171
const processedMigrationInfo = useMemo(() => {
7272
const result = {};

0 commit comments

Comments
 (0)