Skip to content

Commit 5f43f94

Browse files
Merge pull request #989 from openedx/sundas/INF-1243
test: added test cases to change toggle based on channel
2 parents 0ee0f41 + 67feee5 commit 5f43f94

4 files changed

Lines changed: 81 additions & 20 deletions

File tree

src/notification-preferences/NotificationPreferenceApp.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const NotificationPreferenceApp = ({ appId }) => {
4141
return null;
4242
}
4343
return (
44-
<Collapsible.Advanced open={appToggle} data-testid="notification-app" className="mb-5">
44+
<Collapsible.Advanced open={appToggle} data-testid={`${appId}-app`} className="mb-5">
4545
<Collapsible.Trigger>
4646
<div className="d-flex align-items-center">
4747
<span className="mr-auto">

src/notification-preferences/NotificationPreferenceRow.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const NotificationPreferenceRow = ({ appId, preferenceName }) => {
7878
value={preference[channel]}
7979
onChange={onToggle}
8080
disabled={nonEditable.includes(channel) || updatePreferencesStatus === LOADING_STATUS}
81+
id={`${preferenceName}-${channel}`}
8182
/>
8283
</div>
8384
))}

src/notification-preferences/NotificationPreferences.test.jsx

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import { Provider } from 'react-redux';
33
import { BrowserRouter as Router } from 'react-router-dom';
44
import configureStore from 'redux-mock-store';
5-
import { fireEvent, render, screen } from '@testing-library/react';
5+
import {
6+
fireEvent, render, screen, waitFor, act, within,
7+
} from '@testing-library/react';
68
import * as auth from '@edx/frontend-platform/auth';
79
import { IntlProvider } from '@edx/frontend-platform/i18n';
810
import NotificationPreferences from './NotificationPreferences';
@@ -29,37 +31,51 @@ const defaultPreferences = {
2931
],
3032
preferences: [
3133
{
32-
id: 'newPost',
34+
id: 'core',
3335
appId: 'discussion',
34-
web: false,
35-
push: false,
36-
mobile: false,
36+
web: true,
37+
push: true,
38+
email: true,
3739
},
3840
{
3941
id: 'newComment',
4042
appId: 'discussion',
4143
web: false,
4244
push: false,
43-
mobile: false,
45+
email: false,
4446
},
4547
{
4648
id: 'newAssignment',
4749
appId: 'coursework',
4850
web: false,
4951
push: false,
50-
mobile: false,
52+
email: false,
5153
},
5254
{
5355
id: 'newGrade',
5456
appId: 'coursework',
5557
web: false,
5658
push: false,
57-
mobile: false,
59+
email: false,
5860
},
5961
],
60-
nonEditable: {},
62+
nonEditable: {
63+
discussion: {
64+
core: [
65+
'web',
66+
],
67+
},
68+
},
6169
};
6270

71+
const updateChannelPreferences = (toggleVal = false) => ({
72+
preferences: [
73+
{ id: 'core', appId: 'discussion', web: true },
74+
{ id: 'newComment', appId: 'discussion', web: toggleVal },
75+
{ id: 'newAssignment', appId: 'coursework', web: toggleVal },
76+
],
77+
});
78+
6379
const setupStore = (override = {}) => {
6480
const storeState = defaultState;
6581
storeState.courses = {
@@ -78,17 +94,19 @@ const setupStore = (override = {}) => {
7894
return store;
7995
};
8096

81-
const renderComponent = (store = {}) => render(
97+
const notificationPreferences = (store = {}) => (
8298
<Router>
8399
<IntlProvider locale="en">
84100
<Provider store={store}>
85101
<NotificationPreferences />
86102
</Provider>
87103
</IntlProvider>
88-
</Router>,
104+
</Router>
89105
);
106+
90107
describe('Notification Preferences', () => {
91108
let store;
109+
92110
beforeEach(() => {
93111
store = setupStore({
94112
...defaultPreferences,
@@ -108,38 +126,76 @@ describe('Notification Preferences', () => {
108126
afterEach(() => jest.clearAllMocks());
109127

110128
it('tests if all notification apps are listed', async () => {
111-
await renderComponent(store);
112-
expect(screen.queryAllByTestId('notification-app')).toHaveLength(2);
129+
await render(notificationPreferences(store));
130+
expect(screen.queryByTestId('discussion-app')).toBeInTheDocument();
131+
expect(screen.queryByTestId('coursework-app')).toBeInTheDocument();
113132
});
133+
114134
it('show spinner if api call is in progress', async () => {
115135
store = setupStore({ status: LOADING_STATUS });
116-
await renderComponent(store);
136+
await render(notificationPreferences(store));
117137
expect(screen.queryByTestId('loading-spinner')).toBeInTheDocument();
118138
});
119139

120140
it('tests if all notification preferences are listed', async () => {
121-
await renderComponent(store);
141+
await render(notificationPreferences(store));
122142
expect(screen.queryAllByTestId('notification-preference')).toHaveLength(4);
123143
});
124144

125145
it('update group on click', async () => {
126-
const wrapper = await renderComponent(store);
146+
const wrapper = await render(notificationPreferences(store));
127147
const element = wrapper.container.querySelector('#discussion-app-toggle');
128148
await fireEvent.click(element);
129149
expect(mockDispatch).toHaveBeenCalled();
130150
});
131151

132152
it('update preference on click', async () => {
133-
const wrapper = await renderComponent(store);
134-
const element = wrapper.container.querySelector('#newPost-web');
153+
const wrapper = await render(notificationPreferences(store));
154+
const element = wrapper.container.querySelector('#core-web');
135155
expect(element).not.toBeChecked();
136156
await fireEvent.click(element);
137157
expect(mockDispatch).toHaveBeenCalled();
138158
});
139159

140160
it('show not found page if invalid course id is entered in url', async () => {
141161
store = setupStore({ status: FAILURE_STATUS, selectedCourse: 'invalid-course-id' });
142-
await renderComponent(store);
162+
await render(notificationPreferences(store));
143163
expect(screen.queryByTestId('not-found-page')).toBeInTheDocument();
144164
});
165+
166+
it('updates all preferences in the column on web channel click', async () => {
167+
store = setupStore(updateChannelPreferences(true));
168+
const wrapper = render(notificationPreferences(store));
169+
170+
const getChannelSwitch = (id) => screen.queryByTestId(`${id}-web`);
171+
const notificationTypes = ['newComment', 'newAssignment'];
172+
173+
const verifyState = (toggleState) => {
174+
notificationTypes.forEach((notificationType) => {
175+
if (toggleState) {
176+
expect(getChannelSwitch(notificationType)).toBeChecked();
177+
} else {
178+
expect(getChannelSwitch(notificationType)).not.toBeChecked();
179+
}
180+
});
181+
};
182+
183+
verifyState(true);
184+
expect(getChannelSwitch('core')).toBeChecked();
185+
186+
const discussionApp = screen.queryByTestId('discussion-app');
187+
const webChannel = within(discussionApp).queryByText('Web');
188+
189+
await act(async () => {
190+
await fireEvent.click(webChannel);
191+
});
192+
193+
store = setupStore(updateChannelPreferences(false));
194+
wrapper.rerender(notificationPreferences(store));
195+
196+
await waitFor(() => {
197+
verifyState(false);
198+
expect(getChannelSwitch('core')).toBeChecked();
199+
});
200+
});
145201
});

src/notification-preferences/ToggleSwitch.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ const ToggleSwitch = ({
77
value,
88
disabled,
99
onChange,
10+
id,
1011
}) => (
1112
<Form.Switch
1213
name={name}
1314
checked={value}
1415
disabled={disabled}
1516
onChange={onChange}
17+
data-testid={id}
1618
/>
1719
);
1820

@@ -21,11 +23,13 @@ ToggleSwitch.propTypes = {
2123
value: PropTypes.bool.isRequired,
2224
disabled: PropTypes.bool,
2325
onChange: PropTypes.func,
26+
id: PropTypes.string,
2427
};
2528

2629
ToggleSwitch.defaultProps = {
2730
onChange: () => null,
2831
disabled: false,
32+
id: '',
2933
};
3034

3135
export default React.memo(ToggleSwitch);

0 commit comments

Comments
 (0)