forked from openedx/frontend-app-authoring
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGradingSettings.test.jsx
More file actions
208 lines (186 loc) · 8.58 KB
/
GradingSettings.test.jsx
File metadata and controls
208 lines (186 loc) · 8.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import {
act,
fireEvent,
render,
screen,
initializeMocks,
} from '@src/testUtils';
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
import { getCourseSettingsApiUrl } from '@src/data/api';
import { mockWaffleFlags } from '@src/data/apiHooks.mock';
import { useCourseUserPermissions } from '@src/authz/hooks';
import gradingSettings from './__mocks__/gradingSettings';
import { getGradingSettingsApiUrl } from './data/api';
import * as apiHooks from './data/apiHooks';
import GradingSettings from './GradingSettings';
import messages from './messages';
jest.mock('@src/authz/hooks', () => ({
useCourseUserPermissions: jest.fn().mockReturnValue({
isLoading: false,
canViewGradingSettings: true,
canEditGradingSettings: true,
}),
}));
const courseId = '123';
let axiosMock;
const RootWrapper = () => (
<CourseAuthoringProvider courseId={courseId}>
<GradingSettings />
</CourseAuthoringProvider>
);
describe('<GradingSettings />', () => {
beforeEach(() => {
const mocks = initializeMocks();
// jsdom doesn't implement scrollTo; mock to avoid noisy console errors.
Object.defineProperty(window, 'scrollTo', { value: jest.fn(), writable: true });
axiosMock = mocks.axiosMock;
axiosMock
.onGet(getGradingSettingsApiUrl(courseId))
.reply(200, gradingSettings);
axiosMock
.onPost(getGradingSettingsApiUrl(courseId))
.reply(200, {});
axiosMock.onGet(getCourseSettingsApiUrl(courseId))
.reply(200, {});
render(<RootWrapper />);
});
function testSaving() {
const saveBtn = screen.getByText(messages.buttonSaveText.defaultMessage);
expect(saveBtn).toBeInTheDocument();
fireEvent.click(saveBtn);
expect(screen.getByText(messages.buttonSavingText.defaultMessage)).toBeInTheDocument();
}
function setOnlineStatus(isOnline) {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValue(isOnline);
act(() => {
window.dispatchEvent(new window.Event(isOnline ? 'online' : 'offline'));
});
}
it('should render without errors', async () => {
const gradingElements = await screen.findAllByText(messages.headingTitle.defaultMessage);
const gradingTitle = gradingElements[0];
expect(screen.getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument();
expect(gradingTitle).toBeInTheDocument();
expect(screen.getByText(messages.policy.defaultMessage)).toBeInTheDocument();
expect(screen.getByText(messages.policiesDescription.defaultMessage)).toBeInTheDocument();
});
it('should update segment input value and show save alert', async () => {
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
expect(segmentInputs).toHaveLength(5);
const segmentInput = segmentInputs[1];
fireEvent.change(segmentInput, { target: { value: 'Test' } });
expect(segmentInput).toHaveValue('Test');
expect(screen.getByTestId('grading-settings-save-alert')).toBeVisible();
});
it('should update grading scale segment input value on change and cancel the action', async () => {
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
const segmentInput = segmentInputs[1];
fireEvent.change(segmentInput, { target: { value: 'Test' } });
fireEvent.click(screen.getByText(messages.buttonCancelText.defaultMessage));
expect(segmentInput).toHaveValue('a');
});
it('should save segment input changes and display saving message', async () => {
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
const segmentInput = segmentInputs[1];
fireEvent.change(segmentInput, { target: { value: 'Test' } });
testSaving();
});
it('should show success alert and hide save prompt after successful save', async () => {
// Trigger change to show save prompt
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
const segmentInput = segmentInputs[2];
fireEvent.change(segmentInput, { target: { value: 'PatchTest' } });
// Click save and verify pending state appears
const saveBtnInitial = screen.getByText(messages.buttonSaveText.defaultMessage);
fireEvent.click(saveBtnInitial);
expect(screen.getByText(messages.buttonSavingText.defaultMessage)).toBeInTheDocument();
// Wait for success alert to appear (mutation success)
const successAlert = await screen.findByText(messages.alertSuccess.defaultMessage);
expect(successAlert).toBeVisible();
// Pending label should disappear and save prompt should be hidden (button removed)
expect(screen.queryByText(messages.buttonSavingText.defaultMessage)).toBeNull();
const saveAlert = screen.queryByTestId('grading-settings-save-alert');
expect(saveAlert).toBeNull();
// Ensure original save button text is no longer present because the prompt closed
expect(screen.queryByText(messages.buttonSaveText.defaultMessage)).toBeNull();
});
it('should handle being offline gracefully', async () => {
setOnlineStatus(false);
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
const segmentInput = segmentInputs[1];
fireEvent.change(segmentInput, { target: { value: 'Test' } });
const saveBtn = screen.getByText(messages.buttonSaveText.defaultMessage);
expect(saveBtn).toBeInTheDocument();
fireEvent.click(saveBtn);
expect(screen.getByText(/studio's having trouble saving your work/i)).toBeInTheDocument();
expect(screen.queryByText(messages.buttonSavingText.defaultMessage)).not.toBeInTheDocument();
setOnlineStatus(true);
testSaving();
});
it('should display connection error alert when loading is denied', async () => {
jest.spyOn(apiHooks, 'useGradingSettings').mockReturnValue({ isError: true });
render(<RootWrapper />);
expect(screen.getByTestId('connectionErrorAlert')).toBeInTheDocument();
});
});
describe('<GradingSettings /> permissions', () => {
beforeEach(() => {
jest.restoreAllMocks();
const mocks = initializeMocks();
Object.defineProperty(window, 'scrollTo', { value: jest.fn(), writable: true });
const { axiosMock: mock } = mocks;
mock.onGet(getGradingSettingsApiUrl(courseId)).reply(200, gradingSettings);
mock.onPost(getGradingSettingsApiUrl(courseId)).reply(200, {});
mock.onGet(getCourseSettingsApiUrl(courseId)).reply(200, {});
jest.mocked(useCourseUserPermissions).mockReturnValue({
isLoading: false,
canViewGradingSettings: true,
canEditGradingSettings: true,
});
});
it('should render normally when authz flag is disabled (no regression)', async () => {
mockWaffleFlags({ enableAuthzCourseAuthoring: false });
render(<RootWrapper />);
expect(await screen.findAllByText(messages.headingTitle.defaultMessage)).not.toHaveLength(0);
});
it('should render normally when user has view and edit permissions', async () => {
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
render(<RootWrapper />);
expect(await screen.findAllByText(messages.headingTitle.defaultMessage)).not.toHaveLength(0);
});
it('should show permission denied alert when user lacks view permission', async () => {
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
jest.mocked(useCourseUserPermissions).mockReturnValue({
isLoading: false,
canViewGradingSettings: false,
canEditGradingSettings: false,
});
render(<RootWrapper />);
expect(await screen.findByTestId('permissionDeniedAlert')).toBeInTheDocument();
});
it('should disable inputs when user has view but not edit permission', async () => {
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
jest.mocked(useCourseUserPermissions).mockReturnValue({
isLoading: false,
canViewGradingSettings: true,
canEditGradingSettings: false,
});
render(<RootWrapper />);
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
segmentInputs.forEach((input) => expect(input).toBeDisabled());
});
it('should disable save button when user lacks edit permission', async () => {
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
jest.mocked(useCourseUserPermissions).mockReturnValue({
isLoading: false,
canViewGradingSettings: true,
canEditGradingSettings: false,
});
render(<RootWrapper />);
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
// Trigger a change to show the save alert
fireEvent.change(segmentInputs[1], { target: { value: 'Test' } });
const saveBtn = screen.getByTestId('grading-settings-save-alert').querySelector('button[type="button"]:last-child');
expect(saveBtn).toBeDisabled();
});
});