@openedx/frontend-app-authn 1.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.rst +204 -0
- package/package.json +79 -0
- package/src/Main.tsx +23 -0
- package/src/__mocks__/file.js +1 -0
- package/src/__mocks__/svg.js +1 -0
- package/src/app.scss +6 -0
- package/src/app.ts +43 -0
- package/src/base-container/components/default-layout/DefaultLayout.test.jsx +48 -0
- package/src/base-container/components/default-layout/LargeLayout.jsx +42 -0
- package/src/base-container/components/default-layout/MediumLayout.jsx +49 -0
- package/src/base-container/components/default-layout/SmallLayout.jsx +37 -0
- package/src/base-container/components/default-layout/index.jsx +3 -0
- package/src/base-container/components/default-layout/messages.js +16 -0
- package/src/base-container/components/image-layout/ExtraSmallLayout.jsx +31 -0
- package/src/base-container/components/image-layout/LargeLayout.jsx +32 -0
- package/src/base-container/components/image-layout/MediumLayout.jsx +32 -0
- package/src/base-container/components/image-layout/SmallLayout.jsx +31 -0
- package/src/base-container/components/image-layout/index.jsx +4 -0
- package/src/base-container/components/image-layout/index.scss +37 -0
- package/src/base-container/components/image-layout/messages.js +16 -0
- package/src/base-container/components/welcome-page-layout/LargeLayout.jsx +46 -0
- package/src/base-container/components/welcome-page-layout/MediumLayout.jsx +49 -0
- package/src/base-container/components/welcome-page-layout/SmallLayout.jsx +38 -0
- package/src/base-container/components/welcome-page-layout/index.jsx +3 -0
- package/src/base-container/components/welcome-page-layout/messages.js +21 -0
- package/src/base-container/index.jsx +70 -0
- package/src/base-container/tests/BaseContainer.test.jsx +44 -0
- package/src/common-components/EmbeddedRegistrationRoute.jsx +26 -0
- package/src/common-components/EnterpriseSSO.jsx +110 -0
- package/src/common-components/FormGroup.jsx +106 -0
- package/src/common-components/InstitutionLogistration.jsx +102 -0
- package/src/common-components/NotFoundPage.jsx +15 -0
- package/src/common-components/PasswordField.jsx +175 -0
- package/src/common-components/RedirectLogistration.jsx +94 -0
- package/src/common-components/RegisterFaIcons.jsx +8 -0
- package/src/common-components/SocialAuthProviders.jsx +75 -0
- package/src/common-components/ThirdPartyAuth.jsx +123 -0
- package/src/common-components/ThirdPartyAuthAlert.jsx +49 -0
- package/src/common-components/UnAuthOnlyRoute.jsx +41 -0
- package/src/common-components/data/actions.js +27 -0
- package/src/common-components/data/reducers.js +63 -0
- package/src/common-components/data/sagas.js +32 -0
- package/src/common-components/data/selectors.js +28 -0
- package/src/common-components/data/service.js +23 -0
- package/src/common-components/data/tests/reducer.test.js +82 -0
- package/src/common-components/data/tests/sagas.test.js +71 -0
- package/src/common-components/index.jsx +14 -0
- package/src/common-components/messages.jsx +127 -0
- package/src/common-components/tests/EmbeddedRegistrationRoute.test.jsx +76 -0
- package/src/common-components/tests/FormField.test.jsx +289 -0
- package/src/common-components/tests/SocialAuthProviders.test.jsx +75 -0
- package/src/common-components/tests/ThirdPartyAuthAlert.test.jsx +39 -0
- package/src/common-components/tests/UnAuthOnlyRoute.test.jsx +73 -0
- package/src/common-components/tests/__snapshots__/SocialAuthProviders.test.jsx.snap +156 -0
- package/src/common-components/tests/__snapshots__/ThirdPartyAuthAlert.test.jsx.snap +53 -0
- package/src/constants.ts +1 -0
- package/src/data/configureStore.js +33 -0
- package/src/data/constants.js +38 -0
- package/src/data/countries.ts +59 -0
- package/src/data/oneTrust.js +3 -0
- package/src/data/reducers.js +36 -0
- package/src/data/sagas.js +19 -0
- package/src/data/tests/cookies.test.js +42 -0
- package/src/data/tests/dataUtils.test.js +19 -0
- package/src/data/tests/reduxUtils.test.js +14 -0
- package/src/data/utils/cookies.js +12 -0
- package/src/data/utils/dataUtils.js +81 -0
- package/src/data/utils/index.js +11 -0
- package/src/data/utils/reduxUtils.js +34 -0
- package/src/data/utils/useMobileResponsive.js +24 -0
- package/src/field-renderer/FieldRenderer.jsx +156 -0
- package/src/field-renderer/index.jsx +2 -0
- package/src/field-renderer/tests/FieldRenderer.test.jsx +201 -0
- package/src/forgot-password/ForgotPasswordAlert.jsx +97 -0
- package/src/forgot-password/ForgotPasswordPage.jsx +193 -0
- package/src/forgot-password/data/actions.js +32 -0
- package/src/forgot-password/data/reducers.js +58 -0
- package/src/forgot-password/data/sagas.js +35 -0
- package/src/forgot-password/data/selectors.js +10 -0
- package/src/forgot-password/data/service.js +21 -0
- package/src/forgot-password/data/tests/reducers.test.js +34 -0
- package/src/forgot-password/data/tests/sagas.test.js +67 -0
- package/src/forgot-password/index.js +5 -0
- package/src/forgot-password/messages.js +128 -0
- package/src/forgot-password/tests/ForgotPasswordPage.test.jsx +269 -0
- package/src/i18n/index.js +25 -0
- package/src/index.ts +3 -0
- package/src/login/AccountActivationMessage.jsx +78 -0
- package/src/login/ChangePasswordPrompt.jsx +91 -0
- package/src/login/LoginFailure.jsx +231 -0
- package/src/login/LoginPage.jsx +368 -0
- package/src/login/data/actions.js +39 -0
- package/src/login/data/constants.js +20 -0
- package/src/login/data/reducers.js +76 -0
- package/src/login/data/sagas.js +45 -0
- package/src/login/data/service.js +24 -0
- package/src/login/data/tests/reducers.test.js +155 -0
- package/src/login/data/tests/sagas.test.js +110 -0
- package/src/login/index.js +5 -0
- package/src/login/messages.jsx +211 -0
- package/src/login/tests/AccountActivationMessage.test.jsx +122 -0
- package/src/login/tests/ChangePasswordPrompt.test.jsx +75 -0
- package/src/login/tests/LoginFailure.test.jsx +323 -0
- package/src/login/tests/LoginPage.test.jsx +839 -0
- package/src/logistration/Logistration.jsx +189 -0
- package/src/logistration/Logistration.test.jsx +275 -0
- package/src/progressive-profiling/ProgressiveProfiling.jsx +313 -0
- package/src/progressive-profiling/ProgressiveProfilingPageModal.jsx +56 -0
- package/src/progressive-profiling/data/actions.js +22 -0
- package/src/progressive-profiling/data/reducers.js +38 -0
- package/src/progressive-profiling/data/sagas.js +24 -0
- package/src/progressive-profiling/data/selectors.js +14 -0
- package/src/progressive-profiling/data/service.js +17 -0
- package/src/progressive-profiling/index.js +5 -0
- package/src/progressive-profiling/messages.jsx +57 -0
- package/src/progressive-profiling/tests/ProgressiveProfiling.test.jsx +322 -0
- package/src/register/RegistrationFields/CountryField/CountryField.jsx +164 -0
- package/src/register/RegistrationFields/CountryField/CountryField.test.jsx +204 -0
- package/src/register/RegistrationFields/CountryField/validator.js +32 -0
- package/src/register/RegistrationFields/EmailField/EmailField.jsx +140 -0
- package/src/register/RegistrationFields/EmailField/EmailField.test.jsx +236 -0
- package/src/register/RegistrationFields/EmailField/constants.js +131 -0
- package/src/register/RegistrationFields/EmailField/validator.js +126 -0
- package/src/register/RegistrationFields/EmailField/validator.test.js +39 -0
- package/src/register/RegistrationFields/HonorCodeField/HonorCode.jsx +104 -0
- package/src/register/RegistrationFields/HonorCodeField/HonorCode.test.jsx +70 -0
- package/src/register/RegistrationFields/NameField/NameField.jsx +68 -0
- package/src/register/RegistrationFields/NameField/NameField.test.jsx +146 -0
- package/src/register/RegistrationFields/NameField/validator.js +22 -0
- package/src/register/RegistrationFields/TermsOfServiceField/TermsOfService.jsx +58 -0
- package/src/register/RegistrationFields/TermsOfServiceField/TermsOfService.test.jsx +55 -0
- package/src/register/RegistrationFields/UsernameField/UsernameField.jsx +162 -0
- package/src/register/RegistrationFields/UsernameField/UsernameField.test.jsx +319 -0
- package/src/register/RegistrationFields/UsernameField/validator.js +16 -0
- package/src/register/RegistrationFields/index.js +6 -0
- package/src/register/RegistrationPage.jsx +428 -0
- package/src/register/RegistrationPage.test.jsx +854 -0
- package/src/register/components/ConfigurableRegistrationForm.jsx +244 -0
- package/src/register/components/RegistrationFailure.jsx +80 -0
- package/src/register/components/tests/ConfigurableRegistrationForm.test.jsx +401 -0
- package/src/register/components/tests/RegistrationFailure.test.jsx +212 -0
- package/src/register/components/tests/ThirdPartyAuth.test.jsx +439 -0
- package/src/register/data/actions.js +85 -0
- package/src/register/data/constants.js +13 -0
- package/src/register/data/reducers.js +140 -0
- package/src/register/data/sagas.js +58 -0
- package/src/register/data/selectors.js +34 -0
- package/src/register/data/service.js +45 -0
- package/src/register/data/tests/reducers.test.js +277 -0
- package/src/register/data/tests/sagas.test.js +239 -0
- package/src/register/data/tests/utils.test.js +98 -0
- package/src/register/data/utils.js +153 -0
- package/src/register/index.js +4 -0
- package/src/register/messages.jsx +206 -0
- package/src/reset-password/ResetPasswordFailure.jsx +55 -0
- package/src/reset-password/ResetPasswordPage.jsx +224 -0
- package/src/reset-password/ResetPasswordSuccess.jsx +19 -0
- package/src/reset-password/data/actions.js +50 -0
- package/src/reset-password/data/constants.js +16 -0
- package/src/reset-password/data/reducers.js +44 -0
- package/src/reset-password/data/sagas.js +67 -0
- package/src/reset-password/data/selectors.js +10 -0
- package/src/reset-password/data/service.js +61 -0
- package/src/reset-password/data/tests/sagas.test.js +185 -0
- package/src/reset-password/index.js +5 -0
- package/src/reset-password/messages.js +88 -0
- package/src/reset-password/tests/ResetPasswordPage.test.jsx +241 -0
- package/src/routes.jsx +79 -0
- package/src/sass/_base_component.scss +202 -0
- package/src/sass/_forgot_password.scss +3 -0
- package/src/sass/_login_page.scss +3 -0
- package/src/sass/_progressive_profiling_page.scss +30 -0
- package/src/sass/_registration.scss +123 -0
- package/src/sass/_reset_password.scss +3 -0
- package/src/sass/_style.scss +465 -0
- package/src/setupTest.js +68 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { Provider } from 'react-redux';
|
|
2
|
+
|
|
3
|
+
import { injectIntl, IntlProvider } from '@openedx/frontend-base';
|
|
4
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
5
|
+
import { act } from 'react-dom/test-utils';
|
|
6
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
7
|
+
import configureStore from 'redux-mock-store';
|
|
8
|
+
|
|
9
|
+
import { fetchRealtimeValidations } from '../../register/data/actions';
|
|
10
|
+
import FormGroup from '../FormGroup';
|
|
11
|
+
import PasswordField from '../PasswordField';
|
|
12
|
+
|
|
13
|
+
describe('FormGroup', () => {
|
|
14
|
+
const props = {
|
|
15
|
+
floatingLabel: 'Email',
|
|
16
|
+
helpText: ['Email field help text'],
|
|
17
|
+
name: 'email',
|
|
18
|
+
value: '',
|
|
19
|
+
handleFocus: jest.fn(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
it('should show help text on field focus', () => {
|
|
23
|
+
const { queryByText, getByLabelText } = render(<FormGroup {...props} />);
|
|
24
|
+
const emailInput = getByLabelText('Email');
|
|
25
|
+
|
|
26
|
+
expect(queryByText('Email field help text')).toBeNull();
|
|
27
|
+
|
|
28
|
+
fireEvent.focus(emailInput);
|
|
29
|
+
|
|
30
|
+
const helpText = queryByText('Email field help text');
|
|
31
|
+
|
|
32
|
+
expect(helpText).toBeTruthy();
|
|
33
|
+
expect(helpText.textContent).toEqual('Email field help text');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('PasswordField', () => {
|
|
38
|
+
const mockStore = configureStore();
|
|
39
|
+
const IntlPasswordField = injectIntl(PasswordField);
|
|
40
|
+
let props = {};
|
|
41
|
+
let store = {};
|
|
42
|
+
|
|
43
|
+
const reduxWrapper = children => (
|
|
44
|
+
<IntlProvider locale="en">
|
|
45
|
+
<MemoryRouter>
|
|
46
|
+
<Provider store={store}>{children}</Provider>
|
|
47
|
+
</MemoryRouter>
|
|
48
|
+
</IntlProvider>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const initialState = {
|
|
52
|
+
register: {
|
|
53
|
+
validationApiRateLimited: false,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
store = mockStore(initialState);
|
|
59
|
+
props = {
|
|
60
|
+
floatingLabel: 'Password',
|
|
61
|
+
name: 'password',
|
|
62
|
+
value: 'password123',
|
|
63
|
+
handleFocus: jest.fn(),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should show/hide password on icon click', () => {
|
|
68
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
69
|
+
const passwordInput = getByLabelText('Password');
|
|
70
|
+
|
|
71
|
+
const showPasswordButton = getByLabelText('Show password');
|
|
72
|
+
fireEvent.click(showPasswordButton);
|
|
73
|
+
expect(passwordInput.type).toBe('text');
|
|
74
|
+
|
|
75
|
+
const hidePasswordButton = getByLabelText('Hide password');
|
|
76
|
+
fireEvent.click(hidePasswordButton);
|
|
77
|
+
expect(passwordInput.type).toBe('password');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should show password requirement tooltip on focus', async () => {
|
|
81
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
82
|
+
const passwordInput = getByLabelText('Password');
|
|
83
|
+
jest.useFakeTimers();
|
|
84
|
+
await act(async () => {
|
|
85
|
+
fireEvent.focus(passwordInput);
|
|
86
|
+
jest.runAllTimers();
|
|
87
|
+
});
|
|
88
|
+
const passwordRequirementTooltip = document.querySelector('#password-requirement-left');
|
|
89
|
+
|
|
90
|
+
expect(passwordRequirementTooltip).toBeTruthy();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should show all password requirement checks as failed', async () => {
|
|
94
|
+
props = {
|
|
95
|
+
...props,
|
|
96
|
+
value: '',
|
|
97
|
+
};
|
|
98
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
99
|
+
const passwordInput = getByLabelText('Password');
|
|
100
|
+
jest.useFakeTimers();
|
|
101
|
+
await act(async () => {
|
|
102
|
+
fireEvent.focus(passwordInput);
|
|
103
|
+
jest.runAllTimers();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const letterCheckIcon = document.querySelector('#letter-check span');
|
|
107
|
+
const numberCheckIcon = document.querySelector('#number-check span');
|
|
108
|
+
const charactersCheckIcon = document.querySelector('#characters-check span');
|
|
109
|
+
|
|
110
|
+
expect(letterCheckIcon).toBeTruthy();
|
|
111
|
+
expect(letterCheckIcon.className).toContain('pgn__icon mr-1 text-light-700');
|
|
112
|
+
|
|
113
|
+
expect(numberCheckIcon).toBeTruthy();
|
|
114
|
+
expect(numberCheckIcon.className).toContain('pgn__icon mr-1 text-light-700');
|
|
115
|
+
|
|
116
|
+
expect(charactersCheckIcon).toBeTruthy();
|
|
117
|
+
expect(charactersCheckIcon.className).toContain('pgn__icon mr-1 text-light-700');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should update password requirement checks', async () => {
|
|
121
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
122
|
+
const passwordInput = getByLabelText('Password');
|
|
123
|
+
jest.useFakeTimers();
|
|
124
|
+
await act(async () => {
|
|
125
|
+
fireEvent.focus(passwordInput);
|
|
126
|
+
jest.runAllTimers();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const letterCheckIcon = document.querySelector('#letter-check span');
|
|
130
|
+
const numberCheckIcon = document.querySelector('#number-check span');
|
|
131
|
+
const charactersCheckIcon = document.querySelector('#characters-check span');
|
|
132
|
+
|
|
133
|
+
expect(letterCheckIcon).toBeTruthy();
|
|
134
|
+
expect(letterCheckIcon.className).toContain('pgn__icon text-success mr-1');
|
|
135
|
+
|
|
136
|
+
expect(numberCheckIcon).toBeTruthy();
|
|
137
|
+
expect(numberCheckIcon.className).toContain('pgn__icon text-success mr-1');
|
|
138
|
+
|
|
139
|
+
expect(charactersCheckIcon).toBeTruthy();
|
|
140
|
+
expect(charactersCheckIcon.className).toContain('pgn__icon text-success mr-1');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should not run validations when blur is fired on password icon click', () => {
|
|
144
|
+
const { container, getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
145
|
+
const passwordInput = container.querySelector('input[name="password"]');
|
|
146
|
+
|
|
147
|
+
const passwordIcon = getByLabelText('Show password');
|
|
148
|
+
|
|
149
|
+
fireEvent.blur(passwordInput, {
|
|
150
|
+
target: {
|
|
151
|
+
name: 'password',
|
|
152
|
+
value: 'invalid',
|
|
153
|
+
},
|
|
154
|
+
relatedTarget: passwordIcon,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(container.querySelector('div[feedback-for="password"]')).toBeNull();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should call props handle blur if available', () => {
|
|
161
|
+
props = {
|
|
162
|
+
...props,
|
|
163
|
+
handleBlur: jest.fn(),
|
|
164
|
+
};
|
|
165
|
+
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
166
|
+
const passwordInput = container.querySelector('input[name="password"]');
|
|
167
|
+
|
|
168
|
+
fireEvent.blur(passwordInput, {
|
|
169
|
+
target: {
|
|
170
|
+
name: 'password',
|
|
171
|
+
value: '',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
expect(props.handleBlur).toHaveBeenCalledTimes(1);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should run validations on blur event when rendered from register page', () => {
|
|
179
|
+
props = {
|
|
180
|
+
...props,
|
|
181
|
+
handleErrorChange: jest.fn(),
|
|
182
|
+
};
|
|
183
|
+
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
184
|
+
const passwordInput = container.querySelector('input[name="password"]');
|
|
185
|
+
|
|
186
|
+
fireEvent.blur(passwordInput, {
|
|
187
|
+
target: {
|
|
188
|
+
name: 'password',
|
|
189
|
+
value: '',
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
|
|
194
|
+
expect(props.handleErrorChange).toHaveBeenCalledWith(
|
|
195
|
+
'password',
|
|
196
|
+
'Password criteria has not been met',
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should not clear error when focus is fired on password icon click when rendered from register page', () => {
|
|
201
|
+
props = {
|
|
202
|
+
...props,
|
|
203
|
+
handleErrorChange: jest.fn(),
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
207
|
+
|
|
208
|
+
const passwordIcon = getByLabelText('Show password');
|
|
209
|
+
|
|
210
|
+
fireEvent.focus(passwordIcon, {
|
|
211
|
+
target: {
|
|
212
|
+
name: 'passwordIcon',
|
|
213
|
+
value: '',
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(props.handleErrorChange).toHaveBeenCalledTimes(0);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should clear error when focus is fired on password icon click when rendered from register page', () => {
|
|
221
|
+
props = {
|
|
222
|
+
...props,
|
|
223
|
+
handleErrorChange: jest.fn(),
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
227
|
+
|
|
228
|
+
const passwordIcon = getByLabelText('Show password');
|
|
229
|
+
|
|
230
|
+
fireEvent.focus(passwordIcon, {
|
|
231
|
+
target: {
|
|
232
|
+
name: 'password',
|
|
233
|
+
value: 'invalid',
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
|
|
238
|
+
expect(props.handleErrorChange).toHaveBeenCalledWith(
|
|
239
|
+
'password',
|
|
240
|
+
'',
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should run backend validations when frontend validations pass on blur when rendered from register page', () => {
|
|
245
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
246
|
+
props = {
|
|
247
|
+
...props,
|
|
248
|
+
handleErrorChange: jest.fn(),
|
|
249
|
+
};
|
|
250
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
251
|
+
const passwordField = getByLabelText('Password');
|
|
252
|
+
fireEvent.blur(passwordField, {
|
|
253
|
+
target: {
|
|
254
|
+
name: 'password',
|
|
255
|
+
value: 'password123',
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations({ password: 'password123' }));
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('should use password value from prop when password icon is focused out (blur due to icon)', () => {
|
|
263
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
264
|
+
props = {
|
|
265
|
+
...props,
|
|
266
|
+
value: 'testPassword',
|
|
267
|
+
handleErrorChange: jest.fn(),
|
|
268
|
+
handleBlur: jest.fn(),
|
|
269
|
+
};
|
|
270
|
+
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
|
271
|
+
|
|
272
|
+
const passwordIcon = getByLabelText('Show password');
|
|
273
|
+
|
|
274
|
+
fireEvent.blur(passwordIcon, {
|
|
275
|
+
target: {
|
|
276
|
+
name: 'passwordIcon',
|
|
277
|
+
value: undefined,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
expect(props.handleBlur).toHaveBeenCalledTimes(1);
|
|
282
|
+
expect(props.handleBlur).toHaveBeenCalledWith({
|
|
283
|
+
target: {
|
|
284
|
+
name: 'password',
|
|
285
|
+
value: 'testPassword',
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { IntlProvider } from '@openedx/frontend-base';
|
|
2
|
+
import renderer from 'react-test-renderer';
|
|
3
|
+
|
|
4
|
+
import registerIcons from '../RegisterFaIcons';
|
|
5
|
+
import SocialAuthProviders from '../SocialAuthProviders';
|
|
6
|
+
|
|
7
|
+
registerIcons();
|
|
8
|
+
|
|
9
|
+
describe('SocialAuthProviders', () => {
|
|
10
|
+
let props = {};
|
|
11
|
+
|
|
12
|
+
const appleProvider = {
|
|
13
|
+
id: 'oa2-apple-id',
|
|
14
|
+
name: 'Apple',
|
|
15
|
+
iconClass: null,
|
|
16
|
+
iconImage: 'https://edx.devstack.lms/logo.png',
|
|
17
|
+
loginUrl: '/auth/login/apple-id/?auth_entry=login&next=/dashboard',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const facebookProvider = {
|
|
21
|
+
id: 'oa2-facebook',
|
|
22
|
+
name: 'Facebook',
|
|
23
|
+
iconClass: null,
|
|
24
|
+
iconImage: 'https://edx.devstack.lms/facebook-logo.png',
|
|
25
|
+
loginUrl: '/auth/login/facebook/?auth_entry=login&next=/dashboard',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
it('should match social auth provider with iconImage snapshot', () => {
|
|
29
|
+
props = { socialAuthProviders: [appleProvider, facebookProvider] };
|
|
30
|
+
|
|
31
|
+
const tree = renderer.create(
|
|
32
|
+
<IntlProvider locale="en">
|
|
33
|
+
<SocialAuthProviders {...props} />
|
|
34
|
+
</IntlProvider>,
|
|
35
|
+
).toJSON();
|
|
36
|
+
|
|
37
|
+
expect(tree).toMatchSnapshot();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should match social auth provider with iconClass snapshot', () => {
|
|
41
|
+
props = {
|
|
42
|
+
socialAuthProviders: [{
|
|
43
|
+
...appleProvider,
|
|
44
|
+
iconClass: 'google',
|
|
45
|
+
iconImage: null,
|
|
46
|
+
}],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const tree = renderer.create(
|
|
50
|
+
<IntlProvider locale="en">
|
|
51
|
+
<SocialAuthProviders {...props} />
|
|
52
|
+
</IntlProvider>,
|
|
53
|
+
).toJSON();
|
|
54
|
+
|
|
55
|
+
expect(tree).toMatchSnapshot();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should match social auth provider with default icon snapshot', () => {
|
|
59
|
+
props = {
|
|
60
|
+
socialAuthProviders: [{
|
|
61
|
+
...appleProvider,
|
|
62
|
+
iconClass: 'default',
|
|
63
|
+
iconImage: null,
|
|
64
|
+
}],
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const tree = renderer.create(
|
|
68
|
+
<IntlProvider locale="en">
|
|
69
|
+
<SocialAuthProviders {...props} />
|
|
70
|
+
</IntlProvider>,
|
|
71
|
+
).toJSON();
|
|
72
|
+
|
|
73
|
+
expect(tree).toMatchSnapshot();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { IntlProvider } from '@openedx/frontend-base';
|
|
2
|
+
import renderer from 'react-test-renderer';
|
|
3
|
+
|
|
4
|
+
import { REGISTER_PAGE } from '../../data/constants';
|
|
5
|
+
import ThirdPartyAuthAlert from '../ThirdPartyAuthAlert';
|
|
6
|
+
|
|
7
|
+
describe('ThirdPartyAuthAlert', () => {
|
|
8
|
+
let props = {};
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
props = {
|
|
12
|
+
currentProvider: 'Google',
|
|
13
|
+
platformName: 'edX',
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should match login page third party auth alert message snapshot', () => {
|
|
18
|
+
const tree = renderer.create(
|
|
19
|
+
<IntlProvider locale="en">
|
|
20
|
+
<ThirdPartyAuthAlert {...props} />
|
|
21
|
+
</IntlProvider>,
|
|
22
|
+
).toJSON();
|
|
23
|
+
expect(tree).toMatchSnapshot();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should match register page third party auth alert message snapshot', () => {
|
|
27
|
+
props = {
|
|
28
|
+
...props,
|
|
29
|
+
referrer: REGISTER_PAGE,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const tree = renderer.create(
|
|
33
|
+
<IntlProvider locale="en">
|
|
34
|
+
<ThirdPartyAuthAlert {...props} />
|
|
35
|
+
</IntlProvider>,
|
|
36
|
+
).toJSON();
|
|
37
|
+
expect(tree).toMatchSnapshot();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* eslint-disable import/no-import-module-exports */
|
|
2
|
+
/* eslint-disable react/function-component-definition */
|
|
3
|
+
|
|
4
|
+
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@openedx/frontend-base';
|
|
5
|
+
import { render } from '@testing-library/react';
|
|
6
|
+
import { act } from 'react-dom/test-utils';
|
|
7
|
+
import {
|
|
8
|
+
MemoryRouter, Route, BrowserRouter as Router, Routes,
|
|
9
|
+
} from 'react-router-dom';
|
|
10
|
+
|
|
11
|
+
import { UnAuthOnlyRoute } from '..';
|
|
12
|
+
import { REGISTER_PAGE } from '../../data/constants';
|
|
13
|
+
|
|
14
|
+
jest.mock('@openedx/frontend-base', () => ({
|
|
15
|
+
...jest.requireActual('@openedx/frontend-base'),
|
|
16
|
+
getAuthenticatedUser: jest.fn(),
|
|
17
|
+
fetchAuthenticatedUser: jest.fn(),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const RRD = require('react-router-dom');
|
|
21
|
+
// Just render plain div with its children
|
|
22
|
+
// eslint-disable-next-line react/prop-types
|
|
23
|
+
RRD.BrowserRouter = ({ children }) => <div>{ children }</div>;
|
|
24
|
+
module.exports = RRD;
|
|
25
|
+
|
|
26
|
+
const TestApp = () => (
|
|
27
|
+
<Router>
|
|
28
|
+
<div>
|
|
29
|
+
<Routes>
|
|
30
|
+
<Route path={REGISTER_PAGE} element={<UnAuthOnlyRoute><span>Register Page</span></UnAuthOnlyRoute>} />
|
|
31
|
+
</Routes>
|
|
32
|
+
</div>
|
|
33
|
+
</Router>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
describe('UnAuthOnlyRoute', () => {
|
|
37
|
+
const routerWrapper = () => (
|
|
38
|
+
<MemoryRouter initialEntries={[REGISTER_PAGE]}>
|
|
39
|
+
<TestApp />
|
|
40
|
+
</MemoryRouter>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
jest.clearAllMocks();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should have called with forceRefresh true', async () => {
|
|
48
|
+
const user = {
|
|
49
|
+
username: 'gonzo',
|
|
50
|
+
other: 'data',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
getAuthenticatedUser.mockReturnValue(user);
|
|
54
|
+
fetchAuthenticatedUser.mockReturnValueOnce(Promise.resolve(user));
|
|
55
|
+
|
|
56
|
+
await act(async () => {
|
|
57
|
+
await render(routerWrapper());
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(fetchAuthenticatedUser).toBeCalledWith({ forceRefresh: true });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should have called with forceRefresh false', async () => {
|
|
64
|
+
getAuthenticatedUser.mockReturnValue(null);
|
|
65
|
+
fetchAuthenticatedUser.mockReturnValueOnce(Promise.resolve(null));
|
|
66
|
+
|
|
67
|
+
await act(async () => {
|
|
68
|
+
await render(routerWrapper());
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(fetchAuthenticatedUser).toBeCalledWith({ forceRefresh: false });
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`SocialAuthProviders should match social auth provider with default icon snapshot 1`] = `
|
|
4
|
+
<button
|
|
5
|
+
className="btn-social btn-oa2-apple-id mr-3"
|
|
6
|
+
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
|
|
7
|
+
id="oa2-apple-id"
|
|
8
|
+
onClick={[Function]}
|
|
9
|
+
type="button"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
aria-hidden="true"
|
|
13
|
+
className="btn-tpa__font-container"
|
|
14
|
+
>
|
|
15
|
+
<span
|
|
16
|
+
className="pgn__icon h-75"
|
|
17
|
+
>
|
|
18
|
+
<svg
|
|
19
|
+
aria-hidden={true}
|
|
20
|
+
fill="none"
|
|
21
|
+
focusable={false}
|
|
22
|
+
height={24}
|
|
23
|
+
role="img"
|
|
24
|
+
viewBox="0 0 24 24"
|
|
25
|
+
width={24}
|
|
26
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
27
|
+
>
|
|
28
|
+
<path
|
|
29
|
+
d="M11 7 9.6 8.4l2.6 2.6H2v2h10.2l-2.6 2.6L11 17l5-5-5-5zm9 12h-8v2h10V3H12v2h8v14z"
|
|
30
|
+
fill="currentColor"
|
|
31
|
+
/>
|
|
32
|
+
</svg>
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<span
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
className="notranslate mr-auto pl-2"
|
|
38
|
+
id="provider-name"
|
|
39
|
+
>
|
|
40
|
+
Apple
|
|
41
|
+
</span>
|
|
42
|
+
<span
|
|
43
|
+
className="sr-only"
|
|
44
|
+
>
|
|
45
|
+
Sign in with Apple
|
|
46
|
+
</span>
|
|
47
|
+
</button>
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
exports[`SocialAuthProviders should match social auth provider with iconClass snapshot 1`] = `
|
|
51
|
+
<button
|
|
52
|
+
className="btn-social btn-oa2-apple-id mr-3"
|
|
53
|
+
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
|
|
54
|
+
id="oa2-apple-id"
|
|
55
|
+
onClick={[Function]}
|
|
56
|
+
type="button"
|
|
57
|
+
>
|
|
58
|
+
<div
|
|
59
|
+
aria-hidden="true"
|
|
60
|
+
className="btn-tpa__font-container"
|
|
61
|
+
>
|
|
62
|
+
<svg
|
|
63
|
+
aria-hidden="true"
|
|
64
|
+
className="svg-inline--fa fa-google "
|
|
65
|
+
data-icon="google"
|
|
66
|
+
data-prefix="fab"
|
|
67
|
+
focusable="false"
|
|
68
|
+
role="img"
|
|
69
|
+
style={{}}
|
|
70
|
+
viewBox="0 0 488 512"
|
|
71
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
72
|
+
>
|
|
73
|
+
<path
|
|
74
|
+
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
|
|
75
|
+
fill="currentColor"
|
|
76
|
+
style={{}}
|
|
77
|
+
/>
|
|
78
|
+
</svg>
|
|
79
|
+
</div>
|
|
80
|
+
<span
|
|
81
|
+
aria-hidden="true"
|
|
82
|
+
className="notranslate mr-auto pl-2"
|
|
83
|
+
id="provider-name"
|
|
84
|
+
>
|
|
85
|
+
Apple
|
|
86
|
+
</span>
|
|
87
|
+
<span
|
|
88
|
+
className="sr-only"
|
|
89
|
+
>
|
|
90
|
+
Sign in with Apple
|
|
91
|
+
</span>
|
|
92
|
+
</button>
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
exports[`SocialAuthProviders should match social auth provider with iconImage snapshot 1`] = `
|
|
96
|
+
[
|
|
97
|
+
<button
|
|
98
|
+
className="btn-social btn-oa2-apple-id mr-3"
|
|
99
|
+
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
|
|
100
|
+
id="oa2-apple-id"
|
|
101
|
+
onClick={[Function]}
|
|
102
|
+
type="button"
|
|
103
|
+
>
|
|
104
|
+
<div
|
|
105
|
+
aria-hidden="true"
|
|
106
|
+
>
|
|
107
|
+
<img
|
|
108
|
+
alt="icon Apple"
|
|
109
|
+
className="btn-tpa__image-icon"
|
|
110
|
+
src="https://edx.devstack.lms/logo.png"
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
<span
|
|
114
|
+
aria-hidden="true"
|
|
115
|
+
className="notranslate mr-auto pl-2"
|
|
116
|
+
id="provider-name"
|
|
117
|
+
>
|
|
118
|
+
Apple
|
|
119
|
+
</span>
|
|
120
|
+
<span
|
|
121
|
+
className="sr-only"
|
|
122
|
+
>
|
|
123
|
+
Sign in with Apple
|
|
124
|
+
</span>
|
|
125
|
+
</button>,
|
|
126
|
+
<button
|
|
127
|
+
className="btn-social btn-oa2-facebook "
|
|
128
|
+
data-provider-url="/auth/login/facebook/?auth_entry=login&next=/dashboard"
|
|
129
|
+
id="oa2-facebook"
|
|
130
|
+
onClick={[Function]}
|
|
131
|
+
type="button"
|
|
132
|
+
>
|
|
133
|
+
<div
|
|
134
|
+
aria-hidden="true"
|
|
135
|
+
>
|
|
136
|
+
<img
|
|
137
|
+
alt="icon Facebook"
|
|
138
|
+
className="btn-tpa__image-icon"
|
|
139
|
+
src="https://edx.devstack.lms/facebook-logo.png"
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
<span
|
|
143
|
+
aria-hidden="true"
|
|
144
|
+
className="notranslate mr-auto pl-2"
|
|
145
|
+
id="provider-name"
|
|
146
|
+
>
|
|
147
|
+
Facebook
|
|
148
|
+
</span>
|
|
149
|
+
<span
|
|
150
|
+
className="sr-only"
|
|
151
|
+
>
|
|
152
|
+
Sign in with Facebook
|
|
153
|
+
</span>
|
|
154
|
+
</button>,
|
|
155
|
+
]
|
|
156
|
+
`;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ThirdPartyAuthAlert should match login page third party auth alert message snapshot 1`] = `
|
|
4
|
+
<div
|
|
5
|
+
className="fade alert-content alert-warning mt-n2 mb-5 alert show"
|
|
6
|
+
id="tpa-alert"
|
|
7
|
+
role="alert"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
className="pgn__alert-message-wrapper"
|
|
11
|
+
>
|
|
12
|
+
<div
|
|
13
|
+
className="alert-message-content"
|
|
14
|
+
>
|
|
15
|
+
<p>
|
|
16
|
+
You have successfully signed into Google, but your Google account does not have a linked Test Site account. To link your accounts, sign in now using your Test Site password.
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
exports[`ThirdPartyAuthAlert should match register page third party auth alert message snapshot 1`] = `
|
|
24
|
+
[
|
|
25
|
+
<div
|
|
26
|
+
className="fade alert-content alert-success mt-n2 mb-5 alert show"
|
|
27
|
+
id="tpa-alert"
|
|
28
|
+
role="alert"
|
|
29
|
+
>
|
|
30
|
+
<div
|
|
31
|
+
className="pgn__alert-message-wrapper"
|
|
32
|
+
>
|
|
33
|
+
<div
|
|
34
|
+
className="alert-message-content"
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
className="alert-heading h4"
|
|
38
|
+
>
|
|
39
|
+
Almost done!
|
|
40
|
+
</div>
|
|
41
|
+
<p>
|
|
42
|
+
You've successfully signed into Google! We just need a little more information before you start learning with Test Site.
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>,
|
|
47
|
+
<h4
|
|
48
|
+
className="mt-4 mb-4"
|
|
49
|
+
>
|
|
50
|
+
Finish creating your account
|
|
51
|
+
</h4>,
|
|
52
|
+
]
|
|
53
|
+
`;
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const appId = 'org.openedx.frontend.app.authn';
|