@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,854 @@
|
|
|
1
|
+
import { Provider } from 'react-redux';
|
|
2
|
+
import Cookies from 'universal-cookie';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
CurrentAppProvider, configureI18n, getAppConfig, getSiteConfig, getLocale, injectIntl, IntlProvider, mergeAppConfig,
|
|
6
|
+
} from '@openedx/frontend-base';
|
|
7
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
8
|
+
import { mockNavigate, BrowserRouter as Router } from 'react-router-dom';
|
|
9
|
+
import configureStore from 'redux-mock-store';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
|
|
13
|
+
} from '../data/constants';
|
|
14
|
+
import { appId } from '../constants';
|
|
15
|
+
import { initializeMockServices } from '../setupTest';
|
|
16
|
+
import {
|
|
17
|
+
backupRegistrationFormBegin,
|
|
18
|
+
clearRegistrationBackendError,
|
|
19
|
+
registerNewUser,
|
|
20
|
+
setUserPipelineDataLoaded,
|
|
21
|
+
} from './data/actions';
|
|
22
|
+
import { INTERNAL_SERVER_ERROR } from './data/constants';
|
|
23
|
+
import RegistrationPage from './RegistrationPage';
|
|
24
|
+
|
|
25
|
+
jest.mock('@openedx/frontend-base', () => ({
|
|
26
|
+
...jest.requireActual('@openedx/frontend-base'),
|
|
27
|
+
getLocale: jest.fn(),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
const { analyticsService } = initializeMockServices();
|
|
31
|
+
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
|
32
|
+
const mockStore = configureStore();
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
jest.mock('react-router-dom', () => {
|
|
36
|
+
const mockNavigation = jest.fn();
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line react/prop-types
|
|
39
|
+
const Navigate = ({ to }) => {
|
|
40
|
+
mockNavigation(to);
|
|
41
|
+
return <div />;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...jest.requireActual('react-router-dom'),
|
|
46
|
+
Navigate,
|
|
47
|
+
mockNavigate: mockNavigation,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Mock Cookies class
|
|
52
|
+
jest.mock('universal-cookie');
|
|
53
|
+
|
|
54
|
+
describe('RegistrationPage', () => {
|
|
55
|
+
mergeAppConfig(appId, {
|
|
56
|
+
PRIVACY_POLICY: 'https://privacy-policy.com',
|
|
57
|
+
TOS_AND_HONOR_CODE: 'https://tos-and-honot-code.com',
|
|
58
|
+
USER_RETENTION_COOKIE_NAME: 'authn-returning-user',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
let props = {};
|
|
62
|
+
let store = {};
|
|
63
|
+
const registrationFormData = {
|
|
64
|
+
configurableFormFields: {
|
|
65
|
+
marketingEmailsOptIn: true,
|
|
66
|
+
},
|
|
67
|
+
formFields: {
|
|
68
|
+
name: '', email: '', username: '', password: '',
|
|
69
|
+
},
|
|
70
|
+
emailSuggestion: {
|
|
71
|
+
suggestion: '', type: '',
|
|
72
|
+
},
|
|
73
|
+
errors: {
|
|
74
|
+
name: '', email: '', username: '', password: '',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const reduxWrapper = children => (
|
|
79
|
+
<IntlProvider locale="en">
|
|
80
|
+
<CurrentAppProvider appId={appId}>
|
|
81
|
+
<Provider store={store}>{children}</Provider>
|
|
82
|
+
</CurrentAppProvider>
|
|
83
|
+
</IntlProvider>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const routerWrapper = children => (
|
|
87
|
+
<Router>
|
|
88
|
+
{children}
|
|
89
|
+
</Router>
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const thirdPartyAuthContext = {
|
|
93
|
+
currentProvider: null,
|
|
94
|
+
finishAuthUrl: null,
|
|
95
|
+
providers: [],
|
|
96
|
+
pipelineUserDetails: null,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const initialState = {
|
|
100
|
+
register: {
|
|
101
|
+
registrationResult: { success: false, redirectUrl: '' },
|
|
102
|
+
registrationError: {},
|
|
103
|
+
registrationFormData,
|
|
104
|
+
usernameSuggestions: [],
|
|
105
|
+
|
|
106
|
+
},
|
|
107
|
+
commonComponents: {
|
|
108
|
+
thirdPartyAuthApiStatus: null,
|
|
109
|
+
thirdPartyAuthContext,
|
|
110
|
+
fieldDescriptions: {},
|
|
111
|
+
optionalFields: {
|
|
112
|
+
fields: {},
|
|
113
|
+
extended_profile: [],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
store = mockStore(initialState);
|
|
120
|
+
configureI18n({
|
|
121
|
+
messages: { 'es-419': {}, de: {}, 'en-us': {} },
|
|
122
|
+
});
|
|
123
|
+
props = {
|
|
124
|
+
handleInstitutionLogin: jest.fn(),
|
|
125
|
+
institutionLogin: false,
|
|
126
|
+
};
|
|
127
|
+
window.location = { search: '' };
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
afterEach(() => {
|
|
131
|
+
jest.clearAllMocks();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const populateRequiredFields = (
|
|
135
|
+
getByLabelText,
|
|
136
|
+
payload,
|
|
137
|
+
isThirdPartyAuth = false,
|
|
138
|
+
autoGeneratedUsernameEnabled = false,
|
|
139
|
+
) => {
|
|
140
|
+
fireEvent.change(getByLabelText('Full name'), { target: { value: payload.name, name: 'name' } });
|
|
141
|
+
if (!autoGeneratedUsernameEnabled) {
|
|
142
|
+
fireEvent.change(getByLabelText('Public username'), { target: { value: payload.username, name: 'username' } });
|
|
143
|
+
}
|
|
144
|
+
fireEvent.change(getByLabelText('Email'), { target: { value: payload.email, name: 'email' } });
|
|
145
|
+
|
|
146
|
+
if (!isThirdPartyAuth) {
|
|
147
|
+
fireEvent.change(getByLabelText('Password'), { target: { value: payload.password, name: 'password' } });
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
describe('Test Registration Page', () => {
|
|
152
|
+
const emptyFieldValidation = {
|
|
153
|
+
name: 'Enter your full name',
|
|
154
|
+
username: 'Username must be between 2 and 30 characters',
|
|
155
|
+
email: 'Enter your email',
|
|
156
|
+
password: 'Password criteria has not been met',
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// ******** test registration form submission ********
|
|
160
|
+
|
|
161
|
+
it('should submit form for valid input', () => {
|
|
162
|
+
getLocale.mockImplementation(() => ('en-us'));
|
|
163
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
164
|
+
|
|
165
|
+
delete window.location;
|
|
166
|
+
window.location = { href: getSiteConfig().baseUrl, search: '?next=/course/demo-course-url' };
|
|
167
|
+
|
|
168
|
+
const payload = {
|
|
169
|
+
name: 'John Doe',
|
|
170
|
+
username: 'john_doe',
|
|
171
|
+
email: 'john.doe@gmail.com',
|
|
172
|
+
password: 'password1',
|
|
173
|
+
total_registration_time: 0,
|
|
174
|
+
next: '/course/demo-course-url',
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
178
|
+
const { getByLabelText, getByText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
179
|
+
populateRequiredFields(getByLabelText, payload);
|
|
180
|
+
fireEvent.click(getByText('Create an account for free'));
|
|
181
|
+
|
|
182
|
+
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload }));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should submit form without password field when current provider is present', () => {
|
|
186
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
187
|
+
|
|
188
|
+
const formPayload = {
|
|
189
|
+
name: 'John Doe',
|
|
190
|
+
username: 'john_doe',
|
|
191
|
+
email: 'john.doe@example.com',
|
|
192
|
+
social_auth_provider: 'Apple',
|
|
193
|
+
total_registration_time: 0,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
store = mockStore({
|
|
197
|
+
...initialState,
|
|
198
|
+
commonComponents: {
|
|
199
|
+
...initialState.commonComponents,
|
|
200
|
+
thirdPartyAuthContext: {
|
|
201
|
+
...initialState.commonComponents.thirdPartyAuthContext,
|
|
202
|
+
currentProvider: 'Apple',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
207
|
+
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
208
|
+
|
|
209
|
+
populateRequiredFields(getByLabelText, formPayload, true);
|
|
210
|
+
const button = container.querySelector('button.btn-brand');
|
|
211
|
+
fireEvent.click(button);
|
|
212
|
+
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...formPayload }));
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should display an error when form is submitted with an invalid email', () => {
|
|
216
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
217
|
+
const emailError = "We couldn't create your account.Please check your responses and try again.";
|
|
218
|
+
|
|
219
|
+
const formPayload = {
|
|
220
|
+
name: 'Petro',
|
|
221
|
+
username: 'petro_qa',
|
|
222
|
+
email: 'petro @example.com',
|
|
223
|
+
password: 'password1',
|
|
224
|
+
total_registration_time: 0,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
228
|
+
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
229
|
+
populateRequiredFields(getByLabelText, formPayload, true);
|
|
230
|
+
|
|
231
|
+
const button = container.querySelector('button.btn-brand');
|
|
232
|
+
fireEvent.click(button);
|
|
233
|
+
|
|
234
|
+
const validationErrors = container.querySelector('#validation-errors');
|
|
235
|
+
expect(validationErrors.textContent).toContain(emailError);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should display an error when form is submitted with an invalid username', () => {
|
|
239
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
240
|
+
const usernameError = "We couldn't create your account.Please check your responses and try again.";
|
|
241
|
+
|
|
242
|
+
const formPayload = {
|
|
243
|
+
name: 'Petro',
|
|
244
|
+
username: 'petro qa',
|
|
245
|
+
email: 'petro@example.com',
|
|
246
|
+
password: 'password1',
|
|
247
|
+
total_registration_time: 0,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
251
|
+
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
252
|
+
populateRequiredFields(getByLabelText, formPayload, true);
|
|
253
|
+
const button = container.querySelector('button.btn-brand');
|
|
254
|
+
fireEvent.click(button);
|
|
255
|
+
const validationErrors = container.querySelector('#validation-errors');
|
|
256
|
+
expect(validationErrors.textContent).toContain(usernameError);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should submit form with marketing email opt in value', () => {
|
|
260
|
+
mergeAppConfig(appId, {
|
|
261
|
+
MARKETING_EMAILS_OPT_IN: 'true',
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
265
|
+
|
|
266
|
+
const payload = {
|
|
267
|
+
name: 'John Doe',
|
|
268
|
+
username: 'john_doe',
|
|
269
|
+
email: 'john.doe@gmail.com',
|
|
270
|
+
password: 'password1',
|
|
271
|
+
total_registration_time: 0,
|
|
272
|
+
marketing_emails_opt_in: true,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
276
|
+
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
277
|
+
populateRequiredFields(getByLabelText, payload);
|
|
278
|
+
const button = container.querySelector('button.btn-brand');
|
|
279
|
+
fireEvent.click(button);
|
|
280
|
+
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload }));
|
|
281
|
+
|
|
282
|
+
mergeAppConfig(appId, {
|
|
283
|
+
MARKETING_EMAILS_OPT_IN: '',
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should submit form without UsernameField when autoGeneratedUsernameEnabled is true', () => {
|
|
288
|
+
mergeAppConfig(appId, {
|
|
289
|
+
ENABLE_AUTO_GENERATED_USERNAME: true,
|
|
290
|
+
});
|
|
291
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
292
|
+
const payload = {
|
|
293
|
+
name: 'John Doe',
|
|
294
|
+
email: 'john.doe@gmail.com',
|
|
295
|
+
password: 'password1',
|
|
296
|
+
total_registration_time: 0,
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
300
|
+
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
301
|
+
populateRequiredFields(getByLabelText, payload, false, true);
|
|
302
|
+
const button = container.querySelector('button.btn-brand');
|
|
303
|
+
fireEvent.click(button);
|
|
304
|
+
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload }));
|
|
305
|
+
mergeAppConfig(appId, {
|
|
306
|
+
ENABLE_AUTO_GENERATED_USERNAME: false,
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should not display UsernameField when ENABLE_AUTO_GENERATED_USERNAME is true', () => {
|
|
311
|
+
mergeAppConfig(appId, {
|
|
312
|
+
ENABLE_AUTO_GENERATED_USERNAME: true,
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const { queryByLabelText } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
316
|
+
expect(queryByLabelText('Username')).toBeNull();
|
|
317
|
+
|
|
318
|
+
mergeAppConfig(appId, {
|
|
319
|
+
ENABLE_AUTO_GENERATED_USERNAME: false,
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should not dispatch registerNewUser on empty form Submission', () => {
|
|
324
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
325
|
+
|
|
326
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
327
|
+
|
|
328
|
+
const button = container.querySelector('button.btn-brand');
|
|
329
|
+
fireEvent.click(button);
|
|
330
|
+
|
|
331
|
+
expect(store.dispatch).not.toHaveBeenCalledWith(registerNewUser({}));
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// ******** test registration form validations ********
|
|
335
|
+
|
|
336
|
+
it('should show error messages for required fields on empty form submission', () => {
|
|
337
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
338
|
+
|
|
339
|
+
const button = container.querySelector('button.btn-brand');
|
|
340
|
+
fireEvent.click(button);
|
|
341
|
+
|
|
342
|
+
Object.entries(emptyFieldValidation).forEach(([fieldName, validationMessage]) => {
|
|
343
|
+
const feedbackElement = container.querySelector(`div[feedback-for="${fieldName}"]`);
|
|
344
|
+
expect(feedbackElement.textContent).toContain(validationMessage);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const alertBanner = 'We couldn\'t create your account.Please check your responses and try again.';
|
|
348
|
+
const validationErrors = container.querySelector('#validation-errors');
|
|
349
|
+
expect(validationErrors.textContent).toContain(alertBanner);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should set errors with validations returned by registration api', () => {
|
|
353
|
+
const usernameError = 'It looks like this username is already taken';
|
|
354
|
+
const emailError = `This email is already associated with an existing or previous ${getSiteConfig().siteName} account`;
|
|
355
|
+
store = mockStore({
|
|
356
|
+
...initialState,
|
|
357
|
+
register: {
|
|
358
|
+
...initialState.register,
|
|
359
|
+
registrationError: {
|
|
360
|
+
username: [{ userMessage: usernameError }],
|
|
361
|
+
email: [{ userMessage: emailError }],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlProvider locale="en"><IntlRegistrationPage {...props} /></IntlProvider>)));
|
|
366
|
+
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
|
367
|
+
const emailFeedback = container.querySelector('div[feedback-for="email"]');
|
|
368
|
+
|
|
369
|
+
expect(usernameFeedback.textContent).toContain(usernameError);
|
|
370
|
+
expect(emailFeedback.textContent).toContain(emailError);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('should clear error on focus', () => {
|
|
374
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
375
|
+
|
|
376
|
+
const submitButton = container.querySelector('button.btn-brand');
|
|
377
|
+
fireEvent.click(submitButton);
|
|
378
|
+
|
|
379
|
+
const passwordFeedback = container.querySelector('div[feedback-for="password"]');
|
|
380
|
+
expect(passwordFeedback.textContent).toContain(emptyFieldValidation.password);
|
|
381
|
+
|
|
382
|
+
const passwordField = container.querySelector('input#password');
|
|
383
|
+
fireEvent.focus(passwordField);
|
|
384
|
+
|
|
385
|
+
const isFeedbackPresent = container.contains(passwordFeedback);
|
|
386
|
+
expect(isFeedbackPresent).toBeFalsy();
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('should clear registration backend error on change', () => {
|
|
390
|
+
const emailError = 'This email is already associated with an existing or previous account';
|
|
391
|
+
store = mockStore({
|
|
392
|
+
...initialState,
|
|
393
|
+
register: {
|
|
394
|
+
...initialState.register,
|
|
395
|
+
registrationError: {
|
|
396
|
+
email: [{ userMessage: emailError }],
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
401
|
+
|
|
402
|
+
const { container } = render(routerWrapper(reduxWrapper(
|
|
403
|
+
<IntlRegistrationPage {...props} />,
|
|
404
|
+
)));
|
|
405
|
+
|
|
406
|
+
const emailInput = container.querySelector('input#email');
|
|
407
|
+
fireEvent.change(emailInput, { target: { value: 'test1@gmail.com', name: 'email' } });
|
|
408
|
+
expect(store.dispatch).toHaveBeenCalledWith(clearRegistrationBackendError('email'));
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// ******** test form buttons and fields ********
|
|
412
|
+
|
|
413
|
+
it('should match default button state', () => {
|
|
414
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
415
|
+
const button = container.querySelector('button[type="submit"] span');
|
|
416
|
+
expect(button.textContent).toEqual('Create an account for free');
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('should match pending button state', () => {
|
|
420
|
+
store = mockStore({
|
|
421
|
+
...initialState,
|
|
422
|
+
register: {
|
|
423
|
+
...initialState.register,
|
|
424
|
+
submitState: PENDING_STATE,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
429
|
+
|
|
430
|
+
const button = container.querySelector('button[type="submit"] span.sr-only');
|
|
431
|
+
expect(button.textContent).toEqual('pending');
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('should display opt-in/opt-out checkbox', () => {
|
|
435
|
+
mergeAppConfig(appId, {
|
|
436
|
+
MARKETING_EMAILS_OPT_IN: 'true',
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
440
|
+
const checkboxDivs = container.querySelectorAll('div.form-field--checkbox');
|
|
441
|
+
expect(checkboxDivs.length).toEqual(1);
|
|
442
|
+
|
|
443
|
+
mergeAppConfig(appId, {
|
|
444
|
+
MARKETING_EMAILS_OPT_IN: '',
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('should show button label based on cta query params value', () => {
|
|
449
|
+
const buttonLabel = 'Register';
|
|
450
|
+
delete window.location;
|
|
451
|
+
window.location = { href: getSiteConfig().baseUrl, search: `?cta=${buttonLabel}` };
|
|
452
|
+
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
|
|
453
|
+
const button = container.querySelector('button[type="submit"] span');
|
|
454
|
+
|
|
455
|
+
const buttonText = button.textContent;
|
|
456
|
+
|
|
457
|
+
expect(buttonText).toEqual(buttonLabel);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it('should check user retention cookie', () => {
|
|
461
|
+
store = mockStore({
|
|
462
|
+
...initialState,
|
|
463
|
+
register: {
|
|
464
|
+
...initialState.register,
|
|
465
|
+
registrationResult: {
|
|
466
|
+
success: true,
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
472
|
+
expect(Cookies.prototype.set).toHaveBeenCalledWith(getAppConfig(appId).USER_RETENTION_COOKIE_NAME, true, { domain: 'local.openedx.io', path: '/' });
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('should redirect to url returned in registration result after successful account creation', () => {
|
|
476
|
+
const dashboardURL = 'https://test.com/testing-dashboard/';
|
|
477
|
+
store = mockStore({
|
|
478
|
+
...initialState,
|
|
479
|
+
register: {
|
|
480
|
+
...initialState.register,
|
|
481
|
+
registrationResult: {
|
|
482
|
+
success: true,
|
|
483
|
+
redirectUrl: dashboardURL,
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
delete window.location;
|
|
488
|
+
window.location = { href: getSiteConfig().baseUrl };
|
|
489
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
490
|
+
expect(window.location.href).toBe(dashboardURL);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('should redirect to dashboard if features flags are configured but no optional fields are configured', () => {
|
|
494
|
+
mergeAppConfig(appId, {
|
|
495
|
+
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: true,
|
|
496
|
+
});
|
|
497
|
+
const dashboardUrl = 'https://test.com/testing-dashboard/';
|
|
498
|
+
store = mockStore({
|
|
499
|
+
...initialState,
|
|
500
|
+
register: {
|
|
501
|
+
...initialState.register,
|
|
502
|
+
registrationResult: {
|
|
503
|
+
success: true,
|
|
504
|
+
redirectUrl: dashboardUrl,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
commonComponents: {
|
|
508
|
+
...initialState.commonComponents,
|
|
509
|
+
optionalFields: {
|
|
510
|
+
fields: {},
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
delete window.location;
|
|
515
|
+
window.location = { href: getSiteConfig().baseUrl };
|
|
516
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
517
|
+
expect(window.location.href).toBe(dashboardUrl);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it('should redirect to progressive profiling page if optional fields are configured', () => {
|
|
521
|
+
getLocale.mockImplementation(() => ('en-us'));
|
|
522
|
+
mergeAppConfig(appId, {
|
|
523
|
+
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: true,
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
store = mockStore({
|
|
527
|
+
...initialState,
|
|
528
|
+
register: {
|
|
529
|
+
...initialState.register,
|
|
530
|
+
registrationResult: {
|
|
531
|
+
success: true,
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
commonComponents: {
|
|
535
|
+
...initialState.commonComponents,
|
|
536
|
+
optionalFields: {
|
|
537
|
+
extended_profile: [],
|
|
538
|
+
fields: {
|
|
539
|
+
level_of_education: { name: 'level_of_education', error_message: false },
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
render(reduxWrapper(
|
|
546
|
+
<Router>
|
|
547
|
+
<IntlRegistrationPage {...props} />
|
|
548
|
+
</Router>,
|
|
549
|
+
));
|
|
550
|
+
expect(mockNavigate).toHaveBeenCalledWith(AUTHN_PROGRESSIVE_PROFILING);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// ******** miscellaneous tests ********
|
|
554
|
+
|
|
555
|
+
it('should backup the registration form state when shouldBackupState is true', () => {
|
|
556
|
+
store = mockStore({
|
|
557
|
+
...initialState,
|
|
558
|
+
register: {
|
|
559
|
+
...initialState.register,
|
|
560
|
+
shouldBackupState: true,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
565
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
566
|
+
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationFormBegin({ ...registrationFormData }));
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it('should send page event when register page is rendered', () => {
|
|
570
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
571
|
+
expect(analyticsService.sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register', undefined);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('should send track event when user has successfully registered', () => {
|
|
575
|
+
store = mockStore({
|
|
576
|
+
...initialState,
|
|
577
|
+
register: {
|
|
578
|
+
...initialState.register,
|
|
579
|
+
registrationResult: {
|
|
580
|
+
success: true,
|
|
581
|
+
redirectUrl: 'https://test.com/testing-dashboard/',
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
delete window.location;
|
|
587
|
+
window.location = { href: getSiteConfig().baseUrl };
|
|
588
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
589
|
+
expect(analyticsService.sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', {});
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it('should populate form with pipeline user details', () => {
|
|
593
|
+
store = mockStore({
|
|
594
|
+
...initialState,
|
|
595
|
+
register: {
|
|
596
|
+
...initialState.register,
|
|
597
|
+
backedUpFormData: { ...registrationFormData },
|
|
598
|
+
},
|
|
599
|
+
commonComponents: {
|
|
600
|
+
...initialState.commonComponents,
|
|
601
|
+
thirdPartyAuthApiStatus: COMPLETE_STATE,
|
|
602
|
+
thirdPartyAuthContext: {
|
|
603
|
+
...initialState.commonComponents.thirdPartyAuthContext,
|
|
604
|
+
pipelineUserDetails: {
|
|
605
|
+
email: 'test@example.com',
|
|
606
|
+
username: 'test',
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
612
|
+
const { container } = render(reduxWrapper(
|
|
613
|
+
<Router>
|
|
614
|
+
<IntlRegistrationPage {...props} />
|
|
615
|
+
</Router>,
|
|
616
|
+
));
|
|
617
|
+
|
|
618
|
+
const emailInput = container.querySelector('input#email');
|
|
619
|
+
const usernameInput = container.querySelector('input#username');
|
|
620
|
+
|
|
621
|
+
expect(emailInput.value).toEqual('test@example.com');
|
|
622
|
+
expect(usernameInput.value).toEqual('test');
|
|
623
|
+
expect(store.dispatch).toHaveBeenCalledWith(setUserPipelineDataLoaded(true));
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it('should display error message based on the error code returned by API', () => {
|
|
627
|
+
store = mockStore({
|
|
628
|
+
...initialState,
|
|
629
|
+
register: {
|
|
630
|
+
...initialState.register,
|
|
631
|
+
registrationError: {
|
|
632
|
+
errorCode: INTERNAL_SERVER_ERROR,
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
638
|
+
const validationErrors = container.querySelector('div#validation-errors');
|
|
639
|
+
expect(validationErrors.textContent).toContain(
|
|
640
|
+
'An error has occurred. Try refreshing the page, or check your internet connection.',
|
|
641
|
+
);
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it('should update form fields state if updated in redux store', () => {
|
|
645
|
+
store = mockStore({
|
|
646
|
+
...initialState,
|
|
647
|
+
register: {
|
|
648
|
+
...initialState.register,
|
|
649
|
+
registrationFormData: {
|
|
650
|
+
...registrationFormData,
|
|
651
|
+
formFields: {
|
|
652
|
+
name: 'John Doe',
|
|
653
|
+
username: 'john_doe',
|
|
654
|
+
email: 'john.doe@yopmail.com',
|
|
655
|
+
password: 'password1',
|
|
656
|
+
},
|
|
657
|
+
emailSuggestion: {
|
|
658
|
+
suggestion: 'john.doe@hotmail.com', type: 'warning',
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
665
|
+
|
|
666
|
+
const fullNameInput = container.querySelector('input#name');
|
|
667
|
+
const usernameInput = container.querySelector('input#username');
|
|
668
|
+
const emailInput = container.querySelector('input#email');
|
|
669
|
+
const passwordInput = container.querySelector('input#password');
|
|
670
|
+
const emailSuggestion = container.querySelector('.email-suggestion-alert-warning');
|
|
671
|
+
|
|
672
|
+
expect(fullNameInput.value).toEqual('John Doe');
|
|
673
|
+
expect(usernameInput.value).toEqual('john_doe');
|
|
674
|
+
expect(emailInput.value).toEqual('john.doe@yopmail.com');
|
|
675
|
+
expect(passwordInput.value).toEqual('password1');
|
|
676
|
+
expect(emailSuggestion.textContent).toEqual('john.doe@hotmail.com');
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// ********* Embedded experience tests *********/
|
|
680
|
+
|
|
681
|
+
it('should call the postMessage API when embedded variant is rendered', () => {
|
|
682
|
+
getLocale.mockImplementation(() => ('en-us'));
|
|
683
|
+
mergeAppConfig(appId, {
|
|
684
|
+
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: true,
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
window.parent.postMessage = jest.fn();
|
|
688
|
+
|
|
689
|
+
delete window.location;
|
|
690
|
+
window.location = { href: getSiteConfig().baseUrl.concat(AUTHN_PROGRESSIVE_PROFILING), search: '?host=http://localhost/host-website' };
|
|
691
|
+
|
|
692
|
+
store = mockStore({
|
|
693
|
+
...initialState,
|
|
694
|
+
register: {
|
|
695
|
+
...initialState.register,
|
|
696
|
+
registrationResult: {
|
|
697
|
+
success: true,
|
|
698
|
+
},
|
|
699
|
+
},
|
|
700
|
+
commonComponents: {
|
|
701
|
+
...initialState.commonComponents,
|
|
702
|
+
optionalFields: {
|
|
703
|
+
extended_profile: {},
|
|
704
|
+
fields: {
|
|
705
|
+
level_of_education: { name: 'level_of_education', error_message: false },
|
|
706
|
+
},
|
|
707
|
+
},
|
|
708
|
+
},
|
|
709
|
+
});
|
|
710
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
711
|
+
expect(window.parent.postMessage).toHaveBeenCalledTimes(2);
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
it('should not display validations error on blur event when embedded variant is rendered', () => {
|
|
715
|
+
delete window.location;
|
|
716
|
+
window.location = { href: getSiteConfig().baseUrl.concat(REGISTER_PAGE), search: '?host=http://localhost/host-website' };
|
|
717
|
+
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
|
|
718
|
+
|
|
719
|
+
const usernameInput = container.querySelector('input#username');
|
|
720
|
+
fireEvent.blur(usernameInput, { target: { value: '', name: 'username' } });
|
|
721
|
+
expect(container.querySelector('div[feedback-for="username"]')).toBeFalsy();
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it('should set errors in temporary state when validations are returned by registration api', () => {
|
|
725
|
+
delete window.location;
|
|
726
|
+
window.location = { href: getSiteConfig().baseUrl.concat(REGISTER_PAGE), search: '?host=http://localhost/host-website' };
|
|
727
|
+
|
|
728
|
+
const usernameError = 'It looks like this username is already taken';
|
|
729
|
+
const emailError = 'This email is already associated with an existing or previous account';
|
|
730
|
+
store = mockStore({
|
|
731
|
+
...initialState,
|
|
732
|
+
register: {
|
|
733
|
+
...initialState.register,
|
|
734
|
+
registrationError: {
|
|
735
|
+
username: [{ userMessage: usernameError }],
|
|
736
|
+
email: [{ userMessage: emailError }],
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
});
|
|
740
|
+
const { container } = render(routerWrapper(reduxWrapper(
|
|
741
|
+
<IntlRegistrationPage {...props} />
|
|
742
|
+
)));
|
|
743
|
+
|
|
744
|
+
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
|
745
|
+
const emailFeedback = container.querySelector('div[feedback-for="email"]');
|
|
746
|
+
|
|
747
|
+
expect(usernameFeedback).toBeNull();
|
|
748
|
+
expect(emailFeedback).toBeNull();
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
it('should clear error on focus for embedded experience also', () => {
|
|
752
|
+
delete window.location;
|
|
753
|
+
window.location = {
|
|
754
|
+
href: getSiteConfig().baseUrl.concat(REGISTER_PAGE),
|
|
755
|
+
search: '?host=http://localhost/host-website',
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
759
|
+
const submitButton = container.querySelector('button.btn-brand');
|
|
760
|
+
fireEvent.click(submitButton);
|
|
761
|
+
|
|
762
|
+
const passwordFeedback = container.querySelector('div[feedback-for="password"]');
|
|
763
|
+
expect(passwordFeedback.textContent).toContain(emptyFieldValidation.password);
|
|
764
|
+
|
|
765
|
+
const passwordField = container.querySelector('input#password');
|
|
766
|
+
fireEvent.focus(passwordField);
|
|
767
|
+
|
|
768
|
+
const updatedPasswordFeedback = container.querySelector('div[feedback-for="password"]');
|
|
769
|
+
expect(updatedPasswordFeedback).toBeNull();
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
it('should show spinner instead of form while registering if autoSubmitRegForm is true', () => {
|
|
773
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
774
|
+
getLocale.mockImplementation(() => ('en-us'));
|
|
775
|
+
|
|
776
|
+
store = mockStore({
|
|
777
|
+
...initialState,
|
|
778
|
+
register: {
|
|
779
|
+
...initialState.register,
|
|
780
|
+
userPipelineDataLoaded: false,
|
|
781
|
+
},
|
|
782
|
+
commonComponents: {
|
|
783
|
+
...initialState.commonComponents,
|
|
784
|
+
thirdPartyAuthApiStatus: COMPLETE_STATE,
|
|
785
|
+
thirdPartyAuthContext: {
|
|
786
|
+
...initialState.commonComponents.thirdPartyAuthContext,
|
|
787
|
+
pipelineUserDetails: {
|
|
788
|
+
name: 'John Doe',
|
|
789
|
+
username: 'john_doe',
|
|
790
|
+
email: 'john.doe@example.com',
|
|
791
|
+
},
|
|
792
|
+
autoSubmitRegForm: true,
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
797
|
+
|
|
798
|
+
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
799
|
+
const spinnerElement = container.querySelector('#tpa-spinner');
|
|
800
|
+
const registrationFormElement = container.querySelector('#registration-form');
|
|
801
|
+
|
|
802
|
+
expect(spinnerElement).toBeTruthy();
|
|
803
|
+
expect(registrationFormElement).toBeFalsy();
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
it('should auto register if autoSubmitRegForm is true and pipeline details are loaded', () => {
|
|
807
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
|
808
|
+
getLocale.mockImplementation(() => ('en-us'));
|
|
809
|
+
|
|
810
|
+
store = mockStore({
|
|
811
|
+
...initialState,
|
|
812
|
+
register: {
|
|
813
|
+
...initialState.register,
|
|
814
|
+
userPipelineDataLoaded: true,
|
|
815
|
+
registrationFormData: {
|
|
816
|
+
...registrationFormData,
|
|
817
|
+
formFields: {
|
|
818
|
+
name: 'John Doe',
|
|
819
|
+
username: 'john_doe',
|
|
820
|
+
email: 'john.doe@example.com',
|
|
821
|
+
},
|
|
822
|
+
configurableFormFields: {
|
|
823
|
+
marketingEmailsOptIn: true,
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
},
|
|
827
|
+
commonComponents: {
|
|
828
|
+
...initialState.commonComponents,
|
|
829
|
+
thirdPartyAuthApiStatus: COMPLETE_STATE,
|
|
830
|
+
thirdPartyAuthContext: {
|
|
831
|
+
...initialState.commonComponents.thirdPartyAuthContext,
|
|
832
|
+
currentProvider: 'Apple',
|
|
833
|
+
pipelineUserDetails: {
|
|
834
|
+
name: 'John Doe',
|
|
835
|
+
username: 'john_doe',
|
|
836
|
+
email: 'john.doe@example.com',
|
|
837
|
+
},
|
|
838
|
+
autoSubmitRegForm: true,
|
|
839
|
+
},
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
store.dispatch = jest.fn(store.dispatch);
|
|
843
|
+
|
|
844
|
+
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
|
845
|
+
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({
|
|
846
|
+
name: 'John Doe',
|
|
847
|
+
username: 'john_doe',
|
|
848
|
+
email: 'john.doe@example.com',
|
|
849
|
+
social_auth_provider: 'Apple',
|
|
850
|
+
total_registration_time: 0,
|
|
851
|
+
}));
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
});
|