Skip to content

Commit 90aee6a

Browse files
committed
fix: use default params instead of defaultProps for new props, add permission tests
1 parent fcce1df commit 90aee6a

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
@@ -7,13 +7,25 @@ import {
77
} from '@src/testUtils';
88
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
99
import { getCourseSettingsApiUrl } from '@src/data/api';
10+
import { mockWaffleFlags } from '@src/data/apiHooks.mock';
11+
import { useUserPermissionsWithAuthzCourse } from '@src/authz/hooks';
1012

1113
import gradingSettings from './__mocks__/gradingSettings';
1214
import { getGradingSettingsApiUrl } from './data/api';
1315
import * as apiHooks from './data/apiHooks';
1416
import GradingSettings from './GradingSettings';
1517
import messages from './messages';
1618

19+
jest.mock('@src/authz/hooks', () => ({
20+
useUserPermissionsWithAuthzCourse: jest.fn().mockReturnValue({
21+
isLoading: false,
22+
permissions: {
23+
canViewGradingSettings: true,
24+
canEditGradingSettings: true,
25+
},
26+
}),
27+
}));
28+
1729
const courseId = '123';
1830
let axiosMock;
1931

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

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
@@ -67,7 +67,6 @@ AssignmentItem.defaultProps = {
6767
errorEffort: false,
6868
gradeField: undefined,
6969
trailingElement: undefined,
70-
disabled: false,
7170
};
7271

7372
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);
@@ -63,7 +63,6 @@ const AssignmentTypeName = ({
6363

6464
AssignmentTypeName.defaultProps = {
6565
errorEffort: false,
66-
disabled: false,
6766
};
6867

6968
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({});
@@ -207,7 +207,6 @@ const AssignmentSection = ({
207207
AssignmentSection.defaultProps = {
208208
courseAssignmentLists: undefined,
209209
graders: undefined,
210-
isEditable: true,
211210
};
212211

213212
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
@@ -13,7 +13,7 @@ const DeadlineSection = ({
1313
gracePeriod,
1414
setGradingData,
1515
setShowSuccessAlert,
16-
isEditable,
16+
isEditable = true,
1717
}) => {
1818
const intl = useIntl();
1919
const timeStampValue = gracePeriod
@@ -74,7 +74,6 @@ const DeadlineSection = ({
7474

7575
DeadlineSection.defaultProps = {
7676
gracePeriod: null,
77-
isEditable: true,
7877
};
7978

8079
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);
@@ -269,7 +269,6 @@ GradingScale.propTypes = {
269269

270270
GradingScale.defaultProps = {
271271
defaultGradeDesignations: DEFAULT_GRADE_LETTERS,
272-
isEditable: true,
273272
};
274273

275274
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
@@ -8,7 +8,7 @@ const GradingScaleHandle = ({
88
value,
99
gradingSegments,
1010
getHandleProps,
11-
isEditable,
11+
isEditable = true,
1212
}) => (
1313
<button
1414
key={value}
@@ -26,10 +26,6 @@ const GradingScaleHandle = ({
2626
/>
2727
);
2828

29-
GradingScaleHandle.defaultProps = {
30-
isEditable: true,
31-
};
32-
3329
GradingScaleHandle.propTypes = {
3430
idx: PropTypes.number.isRequired,
3531
value: PropTypes.number.isRequired,

0 commit comments

Comments
 (0)