Skip to content

Commit 84fab47

Browse files
committed
fix: use default params instead of defaultProps for new props, add permission tests
1 parent b60df73 commit 84fab47

8 files changed

Lines changed: 90 additions & 20 deletions

File tree

src/grading-settings/GradingSettings.test.jsx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,25 @@ import {
33
} from '@src/testUtils';
44
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
55
import { getCourseSettingsApiUrl } from '@src/data/api';
6+
import { mockWaffleFlags } from '@src/data/apiHooks.mock';
7+
import { useUserPermissionsWithAuthzCourse } from '@src/authz/hooks';
68

79
import gradingSettings from './__mocks__/gradingSettings';
810
import { getGradingSettingsApiUrl } from './data/api';
911
import * as apiHooks from './data/apiHooks';
1012
import GradingSettings from './GradingSettings';
1113
import messages from './messages';
1214

15+
jest.mock('@src/authz/hooks', () => ({
16+
useUserPermissionsWithAuthzCourse: jest.fn().mockReturnValue({
17+
isLoading: false,
18+
permissions: {
19+
canViewGradingSettings: true,
20+
canEditGradingSettings: true,
21+
},
22+
}),
23+
}));
24+
1325
const courseId = '123';
1426
let axiosMock;
1527

@@ -125,3 +137,74 @@ describe('<GradingSettings />', () => {
125137
expect(screen.getByTestId('connectionErrorAlert')).toBeInTheDocument();
126138
});
127139
});
140+
141+
describe('<GradingSettings /> permissions', () => {
142+
const setupMocks = () => {
143+
const mocks = initializeMocks();
144+
Object.defineProperty(window, 'scrollTo', { value: jest.fn(), writable: true });
145+
const { axiosMock: mock } = mocks;
146+
mock.onGet(getGradingSettingsApiUrl(courseId)).reply(200, gradingSettings);
147+
mock.onPost(getGradingSettingsApiUrl(courseId)).reply(200, {});
148+
mock.onGet(getCourseSettingsApiUrl(courseId)).reply(200, {});
149+
return mock;
150+
};
151+
152+
beforeEach(() => {
153+
jest.mocked(useUserPermissionsWithAuthzCourse).mockReturnValue({
154+
isLoading: false,
155+
permissions: { canViewGradingSettings: true, canEditGradingSettings: true },
156+
});
157+
});
158+
159+
it('should render normally when authz flag is disabled (no regression)', async () => {
160+
mockWaffleFlags({ enableAuthzCourseAuthoring: false });
161+
setupMocks();
162+
render(<RootWrapper />);
163+
expect(await screen.findAllByText(messages.headingTitle.defaultMessage)).not.toHaveLength(0);
164+
});
165+
166+
it('should render normally when user has view and edit permissions', async () => {
167+
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
168+
setupMocks();
169+
render(<RootWrapper />);
170+
expect(await screen.findAllByText(messages.headingTitle.defaultMessage)).not.toHaveLength(0);
171+
});
172+
173+
it('should show permission denied alert when user lacks view permission', async () => {
174+
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
175+
jest.mocked(useUserPermissionsWithAuthzCourse).mockReturnValue({
176+
isLoading: false,
177+
permissions: { canViewGradingSettings: false, canEditGradingSettings: false },
178+
});
179+
setupMocks();
180+
render(<RootWrapper />);
181+
expect(await screen.findByTestId('permissionDeniedAlert')).toBeInTheDocument();
182+
});
183+
184+
it('should disable inputs when user has view but not edit permission', async () => {
185+
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
186+
jest.mocked(useUserPermissionsWithAuthzCourse).mockReturnValue({
187+
isLoading: false,
188+
permissions: { canViewGradingSettings: true, canEditGradingSettings: false },
189+
});
190+
setupMocks();
191+
render(<RootWrapper />);
192+
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
193+
segmentInputs.forEach((input) => expect(input).toBeDisabled());
194+
});
195+
196+
it('should disable save button when user lacks edit permission', async () => {
197+
mockWaffleFlags({ enableAuthzCourseAuthoring: true });
198+
jest.mocked(useUserPermissionsWithAuthzCourse).mockReturnValue({
199+
isLoading: false,
200+
permissions: { canViewGradingSettings: true, canEditGradingSettings: false },
201+
});
202+
setupMocks();
203+
render(<RootWrapper />);
204+
const segmentInputs = await screen.findAllByTestId('grading-scale-segment-input');
205+
// Trigger a change to show the save alert
206+
fireEvent.change(segmentInputs[1], { target: { value: 'Test' } });
207+
const saveBtn = screen.getByTestId('grading-settings-save-alert').querySelector('button[type="button"]:last-child');
208+
expect(saveBtn).toBeDisabled();
209+
});
210+
});

src/grading-settings/assignment-section/assignments/AssignmentItem.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const AssignmentItem = ({
2020
secondErrorMsg,
2121
gradeField,
2222
trailingElement,
23-
disabled,
23+
disabled = false,
2424
}) => (
2525
<li className={className}>
2626
<Form.Group className={classNames('form-group-custom', {
@@ -66,7 +66,6 @@ AssignmentItem.defaultProps = {
6666
errorEffort: false,
6767
gradeField: undefined,
6868
trailingElement: undefined,
69-
disabled: false,
7069
};
7170

7271
AssignmentItem.propTypes = {

src/grading-settings/assignment-section/assignments/AssignmentTypeName.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const AssignmentTypeName = ({
1111
value,
1212
errorEffort,
1313
onChange,
14-
disabled,
14+
disabled = false,
1515
}) => {
1616
const intl = useIntl();
1717
const initialAssignmentName = useRef(value);
@@ -62,7 +62,6 @@ const AssignmentTypeName = ({
6262

6363
AssignmentTypeName.defaultProps = {
6464
errorEffort: false,
65-
disabled: false,
6665
};
6766

6867
AssignmentTypeName.propTypes = {

src/grading-settings/assignment-section/index.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const AssignmentSection = ({
2222
setGradingData,
2323
courseAssignmentLists,
2424
setShowSuccessAlert,
25-
isEditable,
25+
isEditable = true,
2626
}) => {
2727
const intl = useIntl();
2828
const [errorList, setErrorList] = useState({});
@@ -206,7 +206,6 @@ const AssignmentSection = ({
206206
AssignmentSection.defaultProps = {
207207
courseAssignmentLists: undefined,
208208
graders: undefined,
209-
isEditable: true,
210209
};
211210

212211
AssignmentSection.propTypes = {

src/grading-settings/credit-section/index.jsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const CreditSection = ({
1212
minimumGradeCredit,
1313
setGradingData,
1414
setShowSuccessAlert,
15-
isEditable,
15+
isEditable = true,
1616
}) => {
1717
const intl = useIntl();
1818
const [errorEffort, setErrorEffort] = useState(false);
@@ -66,10 +66,6 @@ const CreditSection = ({
6666
);
6767
};
6868

69-
CreditSection.defaultProps = {
70-
isEditable: true,
71-
};
72-
7369
CreditSection.propTypes = {
7470
eligibleGrade: PropTypes.number.isRequired,
7571
setShowSavePrompt: PropTypes.func.isRequired,

src/grading-settings/deadline-section/index.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { formatTime, timerValidation } from './utils';
99
import messages from './messages';
1010

1111
const DeadlineSection = ({
12-
setShowSavePrompt, gracePeriod, setGradingData, setShowSuccessAlert, isEditable,
12+
setShowSavePrompt, gracePeriod, setGradingData, setShowSuccessAlert, isEditable = true,
1313
}) => {
1414
const intl = useIntl();
1515
const timeStampValue = gracePeriod
@@ -69,7 +69,6 @@ const DeadlineSection = ({
6969

7070
DeadlineSection.defaultProps = {
7171
gracePeriod: null,
72-
isEditable: true,
7372
};
7473

7574
DeadlineSection.propTypes = {

src/grading-settings/grading-scale/GradingScale.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const GradingScale = ({
2323
setOverrideInternetConnectionAlert,
2424
setEligibleGrade,
2525
defaultGradeDesignations,
26-
isEditable,
26+
isEditable = true,
2727
}) => {
2828
const intl = useIntl();
2929
const [gradingSegments, setGradingSegments] = useState(sortedGrades);
@@ -267,7 +267,6 @@ GradingScale.propTypes = {
267267

268268
GradingScale.defaultProps = {
269269
defaultGradeDesignations: DEFAULT_GRADE_LETTERS,
270-
isEditable: true,
271270
};
272271

273272
export default GradingScale;

src/grading-settings/grading-scale/components/GradingScaleHandle.jsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
44
import { MAXIMUM_SCALE_LENGTH } from '../utils';
55

66
const GradingScaleHandle = ({
7-
idx, value, gradingSegments, getHandleProps, isEditable,
7+
idx, value, gradingSegments, getHandleProps, isEditable = true,
88
}) => (
99
<button
1010
key={value}
@@ -19,10 +19,6 @@ const GradingScaleHandle = ({
1919
/>
2020
);
2121

22-
GradingScaleHandle.defaultProps = {
23-
isEditable: true,
24-
};
25-
2622
GradingScaleHandle.propTypes = {
2723
idx: PropTypes.number.isRequired,
2824
value: PropTypes.number.isRequired,

0 commit comments

Comments
 (0)