@commercetools-frontend/cypress 24.3.0 → 24.5.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/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.dev.js +257 -148
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.prod.js +257 -148
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.esm.js +254 -144
- package/dist/commercetools-frontend-cypress.cjs.dev.js +1 -1
- package/dist/commercetools-frontend-cypress.cjs.prod.js +1 -1
- package/dist/commercetools-frontend-cypress.esm.js +1 -1
- package/dist/declarations/src/add-commands/login.d.ts +17 -3
- package/package.json +4 -4
|
@@ -10,13 +10,10 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
10
10
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
11
11
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
12
12
|
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
13
|
-
var constants
|
|
14
|
-
var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
|
|
13
|
+
var constants = require('@commercetools-frontend/constants');
|
|
15
14
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
16
15
|
var semver = require('semver');
|
|
17
|
-
var
|
|
18
|
-
var ssr = require('@commercetools-frontend/application-shell/ssr');
|
|
19
|
-
var constants = require('../../dist/constants-009cb682.cjs.dev.js');
|
|
16
|
+
var constants$1 = require('../../dist/constants-009cb682.cjs.dev.js');
|
|
20
17
|
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
21
18
|
var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
|
|
22
19
|
var _Array$from = require('@babel/runtime-corejs3/core-js-stable/array/from');
|
|
@@ -34,7 +31,6 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
34
31
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
35
32
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
36
33
|
var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
|
|
37
|
-
var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
|
|
38
34
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
39
35
|
var semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
40
36
|
var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
|
|
@@ -43,7 +39,7 @@ var _entriesInstanceProperty__default = /*#__PURE__*/_interopDefault(_entriesIns
|
|
|
43
39
|
var _reduceRightInstanceProperty__default = /*#__PURE__*/_interopDefault(_reduceRightInstanceProperty);
|
|
44
40
|
|
|
45
41
|
function ownKeys$1(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
46
|
-
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
42
|
+
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context3 = ownKeys$1(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
47
43
|
|
|
48
44
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
45
|
|
|
@@ -51,18 +47,34 @@ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _
|
|
|
51
47
|
|
|
52
48
|
// Alias for backwards compatibility
|
|
53
49
|
|
|
50
|
+
const defaultTimeouts = {
|
|
51
|
+
waitForEmailInput: 4000,
|
|
52
|
+
waitForPasswordInput: 8000
|
|
53
|
+
};
|
|
54
54
|
function isFeatureSupported(expectedVersion) {
|
|
55
55
|
return semver__default["default"].gte(Cypress.version, expectedVersion);
|
|
56
56
|
}
|
|
57
|
+
function isRunningOnLocalhost() {
|
|
58
|
+
const baseUrl = new _URL__default["default"](Cypress.config('baseUrl'));
|
|
59
|
+
return baseUrl.hostname === 'localhost';
|
|
60
|
+
}
|
|
61
|
+
const isCustomView = commandOptions => commandOptions.entryPointUriPath === constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH;
|
|
57
62
|
function loginByForm(commandOptions) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
const isLocalhost = isRunningOnLocalhost();
|
|
64
|
+
Cypress.log({
|
|
65
|
+
name: 'isLocalhost',
|
|
66
|
+
message: isLocalhost
|
|
67
|
+
});
|
|
61
68
|
const projectKey = commandOptions.projectKey ?? Cypress.env('PROJECT_KEY');
|
|
62
|
-
|
|
69
|
+
const isCustomViewConfigCommand = isCustomView(commandOptions);
|
|
70
|
+
const customEntityConfigCommand = isCustomViewConfigCommand ? 'customViewConfig' : 'customApplicationConfig';
|
|
71
|
+
const packageName = commandOptions.packageName ?? Cypress.env('PACKAGE_NAME');
|
|
72
|
+
cy.task(customEntityConfigCommand, _objectSpread$1({
|
|
63
73
|
entryPointUriPath: commandOptions.entryPointUriPath,
|
|
64
74
|
dotfiles: commandOptions.dotfiles
|
|
65
|
-
},
|
|
75
|
+
}, isCustomViewConfigCommand ? {
|
|
76
|
+
packageName
|
|
77
|
+
} : {}),
|
|
66
78
|
// Do not show log, as it may contain sensible information.
|
|
67
79
|
{
|
|
68
80
|
log: false
|
|
@@ -75,7 +87,7 @@ function loginByForm(commandOptions) {
|
|
|
75
87
|
// Log loaded application config for debugging purposes.
|
|
76
88
|
Cypress.log({
|
|
77
89
|
displayName: 'task',
|
|
78
|
-
name:
|
|
90
|
+
name: customEntityConfigCommand,
|
|
79
91
|
message: appConfig
|
|
80
92
|
});
|
|
81
93
|
const userCredentials = commandOptions.login ?? {
|
|
@@ -83,28 +95,217 @@ function loginByForm(commandOptions) {
|
|
|
83
95
|
password: Cypress.env('LOGIN_PASSWORD')
|
|
84
96
|
};
|
|
85
97
|
const sessionKey = ['loginByForm', userCredentials.email, commandOptions.entryPointUriPath];
|
|
86
|
-
// const mcUrl = new URL(appConfig.mcApiUrl);
|
|
87
|
-
// const mcFrontendHostname = mcUrl.hostname.replace('mc-api', 'mc');
|
|
88
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The function is used by Cypress `session` command to store the
|
|
101
|
+
* browser state after executing the authentication flow.
|
|
102
|
+
*/
|
|
89
103
|
function authCallback() {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
// Get the feature flags from the Merchant Center API so we can
|
|
105
|
+
// check whether Identity is enabled
|
|
106
|
+
cy.request({
|
|
107
|
+
method: 'POST',
|
|
108
|
+
url: `${appConfig.mcApiUrl}/graphql`,
|
|
109
|
+
body: {
|
|
110
|
+
operationName: 'AllFeatures',
|
|
111
|
+
query: `query AllFeatures { allFeatures { name value reason } }`
|
|
112
|
+
},
|
|
113
|
+
headers: {
|
|
114
|
+
'content-type': 'application/json',
|
|
115
|
+
'x-graphql-target': constants.GRAPHQL_TARGETS.MERCHANT_CENTER_BACKEND,
|
|
116
|
+
'x-graphql-operation-name': 'AllFeatures',
|
|
117
|
+
'x-project-key': projectKey
|
|
118
|
+
}
|
|
119
|
+
}).then(res => {
|
|
120
|
+
var _context;
|
|
121
|
+
const enableIdentity = _findInstanceProperty__default["default"](_context = res.body.data.allFeatures).call(_context, feature => feature.name === 'enableGlobalIdentity');
|
|
122
|
+
const isGlobalIdentityEnabled = Boolean(enableIdentity?.value);
|
|
123
|
+
Cypress.log({
|
|
124
|
+
name: 'isGlobalIdentityEnabled',
|
|
125
|
+
message: isGlobalIdentityEnabled
|
|
126
|
+
});
|
|
127
|
+
const identityUrl = Cypress.env('IDENTITY_URL') || 'https://identity.commercetools.com';
|
|
128
|
+
|
|
129
|
+
// Visit the application URL, which triggers then the login flow.
|
|
130
|
+
cy.visit(url, {
|
|
131
|
+
onBeforeLoad: commandOptions.onBeforeLoad
|
|
132
|
+
});
|
|
93
133
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
134
|
+
/**
|
|
135
|
+
* There are different scenarios and variations on the flow depending
|
|
136
|
+
* on the environment (localhost, production) and if Identity is enabled.
|
|
137
|
+
*
|
|
138
|
+
* # When the application runs on localhost:3001.
|
|
139
|
+
*
|
|
140
|
+
* ## When Identity is enabled
|
|
141
|
+
* - The test visits the application at localhost:3001.
|
|
142
|
+
* - Cypress registers the default origin being localhost:3001.
|
|
143
|
+
* - The application is redirected to the Identity URL.
|
|
144
|
+
* - Cypress interacts with the Identity URL via `cy.origin`.
|
|
145
|
+
* - At the end of the flow, the test interacts with the application at localhost:3001.
|
|
146
|
+
* ## When Identity is disabled
|
|
147
|
+
* - The test visits the application at localhost:3001.
|
|
148
|
+
* - Cypress registers the default origin being localhost:3001.
|
|
149
|
+
* - The application is redirected to the Merchant Center login page.
|
|
150
|
+
* - Cypress interacts with the Merchant Center login page via `cy.origin`.
|
|
151
|
+
* - At the end of the flow, the test interacts with the application at localhost:3001.
|
|
152
|
+
*
|
|
153
|
+
* # When the application runs on a production URL.
|
|
154
|
+
*
|
|
155
|
+
* ## When Identity is enabled
|
|
156
|
+
* - The test visits the application at the production URL.
|
|
157
|
+
* - The MC Proxy performs a server-side redirect to the Identity URL.
|
|
158
|
+
* - Cypress registers the default origin being the Identity URL.
|
|
159
|
+
* - Cypress interacts with the Identity URL.
|
|
160
|
+
* - At the end of the flow, the test interacts with the application at the production URL via `cy.origin`.
|
|
161
|
+
*
|
|
162
|
+
* ## When Identity is disabled
|
|
163
|
+
* - The test visits the application at the production URL.
|
|
164
|
+
* - The MC Proxy renders the Merchant Center login page.
|
|
165
|
+
* - Cypress registers the default origin being the Merchant Center URL.
|
|
166
|
+
* - Cypress interacts with the Merchant Center login page.
|
|
167
|
+
* - At the end of the flow, the test interacts with the application at the production URL.
|
|
168
|
+
*/
|
|
97
169
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
170
|
+
if (isLocalhost) {
|
|
171
|
+
if (isGlobalIdentityEnabled) {
|
|
172
|
+
// Cypress gets confused when switching between origins, likely because
|
|
173
|
+
// the redirect to Identity doesn't happen immediately.
|
|
174
|
+
// If we don't wait, Cypress fails as it tries to interact with `cy.origin`
|
|
175
|
+
// but the test is still in the initial origin URL.
|
|
176
|
+
// This is a bit unexpected and to be considered a workaround.
|
|
177
|
+
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
178
|
+
cy.wait(1000);
|
|
105
179
|
|
|
106
|
-
|
|
107
|
-
|
|
180
|
+
// Use cy.origin to handle the identity domain
|
|
181
|
+
cy.origin(identityUrl, {
|
|
182
|
+
args: {
|
|
183
|
+
userCredentials,
|
|
184
|
+
identityUrl,
|
|
185
|
+
timeouts: commandOptions.timeouts,
|
|
186
|
+
defaultTimeouts
|
|
187
|
+
}
|
|
188
|
+
}, _ref => {
|
|
189
|
+
let userCredentials = _ref.userCredentials,
|
|
190
|
+
identityUrl = _ref.identityUrl,
|
|
191
|
+
timeouts = _ref.timeouts,
|
|
192
|
+
defaultTimeouts = _ref.defaultTimeouts;
|
|
193
|
+
cy.url().should('include', `${identityUrl}/login`);
|
|
194
|
+
// Fill in the email and click Next
|
|
195
|
+
cy.get('input[name="identifier"]', {
|
|
196
|
+
timeout: timeouts?.waitForEmailInput ?? defaultTimeouts.waitForEmailInput
|
|
197
|
+
}).type(userCredentials.email);
|
|
198
|
+
cy.get('button').contains('Next').click();
|
|
199
|
+
|
|
200
|
+
// Wait for the password form to appear
|
|
201
|
+
cy.get('input[name="password"]', {
|
|
202
|
+
timeout: timeouts?.waitForPasswordInput ?? defaultTimeouts.waitForPasswordInput
|
|
203
|
+
}).should('be.visible');
|
|
204
|
+
// Fill in the password and submit
|
|
205
|
+
cy.get('input[name="password"]').type(userCredentials.password, {
|
|
206
|
+
log: false
|
|
207
|
+
});
|
|
208
|
+
cy.get('button').contains('Submit').click();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Wait for the flow to redirect back to the application.
|
|
212
|
+
cy.get('[role="main"]').should('exist');
|
|
213
|
+
cy.url().should('include', url);
|
|
214
|
+
} else {
|
|
215
|
+
const mcUrl = appConfig.mcApiUrl.replace('mc-api', 'mc');
|
|
216
|
+
// See similar comment above regarding the usage of `cy.wait`.
|
|
217
|
+
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
218
|
+
cy.wait(1000);
|
|
219
|
+
cy.origin(mcUrl, {
|
|
220
|
+
args: {
|
|
221
|
+
userCredentials,
|
|
222
|
+
mcUrl,
|
|
223
|
+
timeouts: commandOptions.timeouts,
|
|
224
|
+
defaultTimeouts
|
|
225
|
+
}
|
|
226
|
+
}, _ref2 => {
|
|
227
|
+
let userCredentials = _ref2.userCredentials,
|
|
228
|
+
mcUrl = _ref2.mcUrl,
|
|
229
|
+
timeouts = _ref2.timeouts,
|
|
230
|
+
defaultTimeouts = _ref2.defaultTimeouts;
|
|
231
|
+
cy.url().should('include', `${mcUrl}/login`);
|
|
232
|
+
|
|
233
|
+
// Same as `fillLegacyLoginFormWithRetry`.
|
|
234
|
+
// eslint-disable-next-line cypress/unsafe-to-chain-command
|
|
235
|
+
cy.get('input[name=email]', {
|
|
236
|
+
timeout: timeouts?.waitForEmailInput ?? defaultTimeouts.waitForEmailInput
|
|
237
|
+
})
|
|
238
|
+
// We use `force` as the MC login UI (production) in tests renders the
|
|
239
|
+
// cookie banner overlapping the input fields.
|
|
240
|
+
// To allow Cypress to interact with the input fields, we use `force`.
|
|
241
|
+
.clear({
|
|
242
|
+
force: true
|
|
243
|
+
}).type(userCredentials.email, {
|
|
244
|
+
force: true
|
|
245
|
+
});
|
|
246
|
+
// eslint-disable-next-line cypress/unsafe-to-chain-command
|
|
247
|
+
cy.get('input[name=password]', {
|
|
248
|
+
timeout: timeouts?.waitForPasswordInput ?? defaultTimeouts.waitForPasswordInput
|
|
249
|
+
})
|
|
250
|
+
// We use `force` as the MC login UI (production) in tests renders the
|
|
251
|
+
// cookie banner overlapping the input fields.
|
|
252
|
+
// To allow Cypress to interact with the input fields, we use `force`.
|
|
253
|
+
.clear({
|
|
254
|
+
force: true
|
|
255
|
+
}).type(userCredentials.password, {
|
|
256
|
+
log: false,
|
|
257
|
+
force: true
|
|
258
|
+
});
|
|
259
|
+
cy.get('button').contains('Sign in').click({
|
|
260
|
+
force: true
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
264
|
+
cy.wait(1000);
|
|
265
|
+
|
|
266
|
+
// Wait for the flow to redirect back to the application.
|
|
267
|
+
cy.get('[role="main"]').should('exist');
|
|
268
|
+
cy.url().should('include', url);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
if (isGlobalIdentityEnabled) {
|
|
272
|
+
cy.url().should('include', `${identityUrl}/login`);
|
|
273
|
+
// Fill in the email and click Next
|
|
274
|
+
cy.get('input[name="identifier"]', {
|
|
275
|
+
timeout: commandOptions.timeouts?.waitForEmailInput ?? defaultTimeouts.waitForEmailInput
|
|
276
|
+
}).type(userCredentials.email);
|
|
277
|
+
cy.get('button').contains('Next').click();
|
|
278
|
+
|
|
279
|
+
// Wait for the password form to appear
|
|
280
|
+
cy.get('input[name="password"]', {
|
|
281
|
+
timeout: commandOptions.timeouts?.waitForPasswordInput ?? defaultTimeouts.waitForPasswordInput
|
|
282
|
+
}).should('be.visible');
|
|
283
|
+
// Fill in the password and submit
|
|
284
|
+
cy.get('input[name="password"]').type(userCredentials.password, {
|
|
285
|
+
log: false
|
|
286
|
+
});
|
|
287
|
+
cy.get('button').contains('Submit').click();
|
|
288
|
+
|
|
289
|
+
// Wait for the flow to redirect back to the application.
|
|
290
|
+
cy.origin(Cypress.config('baseUrl'), {
|
|
291
|
+
args: {
|
|
292
|
+
url
|
|
293
|
+
}
|
|
294
|
+
}, _ref3 => {
|
|
295
|
+
let url = _ref3.url;
|
|
296
|
+
cy.get('[role="main"]').should('exist');
|
|
297
|
+
cy.url().should('include', url);
|
|
298
|
+
});
|
|
299
|
+
} else {
|
|
300
|
+
// Legacy login flow.
|
|
301
|
+
fillLegacyLoginFormWithRetry(userCredentials, commandOptions.timeouts);
|
|
302
|
+
|
|
303
|
+
// Wait for the flow to redirect back to the application.
|
|
304
|
+
cy.get('[role="main"]').should('exist');
|
|
305
|
+
cy.url().should('include', url);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
108
309
|
}
|
|
109
310
|
|
|
110
311
|
// For backwards compatibility.
|
|
@@ -123,108 +324,11 @@ function loginByForm(commandOptions) {
|
|
|
123
324
|
}
|
|
124
325
|
});
|
|
125
326
|
}
|
|
126
|
-
const isCustomView = commandOptions => commandOptions.entryPointUriPath === constants$1.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH;
|
|
127
|
-
function loginByOidc(commandOptions) {
|
|
128
|
-
const isCustomViewConfigCommand = isCustomView(commandOptions);
|
|
129
|
-
if (!isLocalhost()) {
|
|
130
|
-
throw new Error(`The "loginByOidc" command only works when testing a Custom ${isCustomViewConfigCommand ? 'View' : 'Application'} running on localhost.`);
|
|
131
|
-
}
|
|
132
|
-
const sessionNonce = uuid.v4();
|
|
133
|
-
let projectKey = undefined;
|
|
134
|
-
if (commandOptions.entryPointUriPath !== 'account') {
|
|
135
|
-
projectKey = commandOptions.projectKey ?? Cypress.env('PROJECT_KEY');
|
|
136
|
-
}
|
|
137
|
-
const customEntityConfigCommand = isCustomViewConfigCommand ? 'customViewConfig' : 'customApplicationConfig';
|
|
138
|
-
const packageName = commandOptions.packageName ?? Cypress.env('PACKAGE_NAME');
|
|
139
|
-
if (isCustomViewConfigCommand && !packageName) {
|
|
140
|
-
throw new Error(`Missing required option "packageName" when using the "loginToMerchantCenterForCustomView" command.`);
|
|
141
|
-
}
|
|
142
|
-
cy.task(customEntityConfigCommand, _objectSpread$1({
|
|
143
|
-
entryPointUriPath: commandOptions.entryPointUriPath,
|
|
144
|
-
dotfiles: commandOptions.dotfiles
|
|
145
|
-
}, isCustomViewConfigCommand ? {
|
|
146
|
-
packageName
|
|
147
|
-
} : {}),
|
|
148
|
-
// Do not show log, as it may contain sensible information.
|
|
149
|
-
{
|
|
150
|
-
log: false
|
|
151
|
-
}).then(appConfig => {
|
|
152
|
-
// Log loaded application config for debugging purposes.
|
|
153
|
-
Cypress.log({
|
|
154
|
-
displayName: 'task',
|
|
155
|
-
name: customEntityConfigCommand,
|
|
156
|
-
message: appConfig
|
|
157
|
-
});
|
|
158
|
-
const applicationId = appConfig.applicationId;
|
|
159
|
-
const sessionScope = ssr.buildOidcScope({
|
|
160
|
-
projectKey,
|
|
161
|
-
oAuthScopes: appConfig.__DEVELOPMENT__?.oidc?.oAuthScopes,
|
|
162
|
-
additionalOAuthScopes: appConfig.__DEVELOPMENT__?.oidc?.additionalOAuthScopes,
|
|
163
|
-
teamId: appConfig.__DEVELOPMENT__?.oidc?.teamId,
|
|
164
|
-
applicationId: appConfig.__DEVELOPMENT__?.oidc?.applicationId
|
|
165
|
-
});
|
|
166
|
-
const userCredentials = commandOptions.login ?? {
|
|
167
|
-
email: Cypress.env('LOGIN_EMAIL') || Cypress.env('LOGIN_USER'),
|
|
168
|
-
password: Cypress.env('LOGIN_PASSWORD')
|
|
169
|
-
};
|
|
170
|
-
// Perform the login using the API, then store some required values into the browser storage
|
|
171
|
-
// and redirect to the auth callback route.
|
|
172
|
-
const requestOptions = {
|
|
173
|
-
method: 'POST',
|
|
174
|
-
url: `${appConfig.mcApiUrl}/tokens`,
|
|
175
|
-
body: _objectSpread$1(_objectSpread$1({}, userCredentials), {}, {
|
|
176
|
-
client_id: applicationId,
|
|
177
|
-
response_type: constants.OIDC_RESPONSE_TYPES.ID_TOKEN,
|
|
178
|
-
scope: sessionScope,
|
|
179
|
-
state: sessionNonce,
|
|
180
|
-
nonce: sessionNonce
|
|
181
|
-
}),
|
|
182
|
-
followRedirect: false
|
|
183
|
-
};
|
|
184
|
-
cy.request(requestOptions).then(res => {
|
|
185
|
-
const sessionKey = ['loginByOidc', userCredentials.email, commandOptions.entryPointUriPath];
|
|
186
|
-
function authCallback() {
|
|
187
|
-
cy.visit(res.body.redirectTo, {
|
|
188
|
-
onBeforeLoad(win) {
|
|
189
|
-
if (projectKey) {
|
|
190
|
-
win.localStorage.setItem(constants.STORAGE_KEYS.ACTIVE_PROJECT_KEY, projectKey);
|
|
191
|
-
}
|
|
192
|
-
win.sessionStorage.setItem(`${constants.STORAGE_KEYS.NONCE}_${sessionNonce}`, _JSON$stringify__default["default"]({
|
|
193
|
-
applicationId,
|
|
194
|
-
query: {}
|
|
195
|
-
}));
|
|
196
|
-
win.sessionStorage.setItem(constants.STORAGE_KEYS.SESSION_SCOPE, sessionScope);
|
|
197
|
-
if (commandOptions.onBeforeLoad) {
|
|
198
|
-
commandOptions.onBeforeLoad(win);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
// Wait for the application to be loaded so that the session can be saved.
|
|
203
|
-
cy.get('#app-loader').should('not.exist');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// For backwards compatibility.
|
|
207
|
-
if (isFeatureSupported('12.0.0') || Cypress.config('experimentalSessionAndOrigin')) {
|
|
208
|
-
// https://www.cypress.io/blog/2021/08/04/authenticate-faster-in-tests-cy-session-command/
|
|
209
|
-
cy.session(sessionKey, authCallback, isFeatureSupported('10.9.0') ? {
|
|
210
|
-
cacheAcrossSpecs: typeof commandOptions.disableCacheAcrossSpecs === 'boolean' ? !commandOptions.disableCacheAcrossSpecs : true
|
|
211
|
-
} : undefined);
|
|
212
|
-
} else {
|
|
213
|
-
cy.log(`We recommend to use "cy.session" to reduce the time to log in between tests. Make sure to have at least Cypress v12 or enable it via "experimentalSessionAndOrigin" for older Cypress versions.`);
|
|
214
|
-
authCallback();
|
|
215
|
-
}
|
|
216
|
-
if (commandOptions.initialRoute) {
|
|
217
|
-
cy.visit(`${Cypress.config('baseUrl')}${commandOptions.initialRoute}`);
|
|
218
|
-
cy.url().should('include', commandOptions.initialRoute);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
327
|
|
|
224
328
|
/* Utilities */
|
|
225
329
|
|
|
226
|
-
const
|
|
227
|
-
function
|
|
330
|
+
const legacyMaxLoginAttempts = Cypress.config('maxLoginAttempts') ?? 3;
|
|
331
|
+
function fillLegacyLoginFormWithRetry(userCredentials, timeouts) {
|
|
228
332
|
// Intercept the login request so we can retry it if we receive a TOO_MANY_REQUESTS status code
|
|
229
333
|
cy.intercept('POST', '**/tokens').as('loginRequest');
|
|
230
334
|
function getRandomDelayInSeconds() {
|
|
@@ -239,18 +343,31 @@ function fillLoginForm(userCredentials) {
|
|
|
239
343
|
cy.log(`Attempts left: ${attemptsLeft}`);
|
|
240
344
|
|
|
241
345
|
// eslint-disable-next-line cypress/unsafe-to-chain-command
|
|
242
|
-
cy.get('input[name=email]'
|
|
346
|
+
cy.get('input[name=email]', {
|
|
347
|
+
timeout: timeouts?.waitForEmailInput ?? defaultTimeouts.waitForEmailInput
|
|
348
|
+
}).clear({
|
|
349
|
+
force: true
|
|
350
|
+
}).type(userCredentials.email, {
|
|
351
|
+
force: true
|
|
352
|
+
});
|
|
243
353
|
// eslint-disable-next-line cypress/unsafe-to-chain-command
|
|
244
|
-
cy.get('input[name=password]'
|
|
245
|
-
|
|
354
|
+
cy.get('input[name=password]', {
|
|
355
|
+
timeout: timeouts?.waitForPasswordInput ?? defaultTimeouts.waitForPasswordInput
|
|
356
|
+
}).clear({
|
|
357
|
+
force: true
|
|
358
|
+
}).type(userCredentials.password, {
|
|
359
|
+
log: false,
|
|
360
|
+
force: true
|
|
361
|
+
});
|
|
362
|
+
cy.get('button').contains('Sign in').click({
|
|
363
|
+
force: true
|
|
246
364
|
});
|
|
247
|
-
cy.get('button').contains('Sign in').click();
|
|
248
365
|
|
|
249
366
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
250
367
|
cy.wait('@loginRequest').then(interception => {
|
|
251
368
|
const statusCode = interception.response.statusCode;
|
|
252
369
|
cy.log('Login request status code:', statusCode);
|
|
253
|
-
if (statusCode === constants.HTTP_STATUS_CODES.TOO_MANY_REQUESTS) {
|
|
370
|
+
if (statusCode === constants$1.HTTP_STATUS_CODES.TOO_MANY_REQUESTS) {
|
|
254
371
|
// We wait for something between 0.5 and 1.5 seconds before retrying
|
|
255
372
|
cy.wait(getRandomDelayInSeconds());
|
|
256
373
|
attemptLogin(attemptsLeft - 1);
|
|
@@ -259,11 +376,7 @@ function fillLoginForm(userCredentials) {
|
|
|
259
376
|
}
|
|
260
377
|
});
|
|
261
378
|
}
|
|
262
|
-
attemptLogin(
|
|
263
|
-
}
|
|
264
|
-
function isLocalhost() {
|
|
265
|
-
const baseUrl = new _URL__default["default"](Cypress.config('baseUrl'));
|
|
266
|
-
return baseUrl.hostname === 'localhost';
|
|
379
|
+
attemptLogin(legacyMaxLoginAttempts);
|
|
267
380
|
}
|
|
268
381
|
|
|
269
382
|
/**
|
|
@@ -490,20 +603,16 @@ Cypress.Commands.add('loginToMerchantCenter', commandOptions => {
|
|
|
490
603
|
Cypress.log({
|
|
491
604
|
name: 'loginToMerchantCenter'
|
|
492
605
|
});
|
|
493
|
-
|
|
494
|
-
loginByOidc(commandOptions);
|
|
495
|
-
} else {
|
|
496
|
-
loginByForm(commandOptions);
|
|
497
|
-
}
|
|
606
|
+
loginByForm(commandOptions);
|
|
498
607
|
});
|
|
499
608
|
Cypress.Commands.add('loginToMerchantCenterForCustomView', commandOptions => {
|
|
500
609
|
Cypress.log({
|
|
501
610
|
name: 'loginToMerchantCenterForCustomView'
|
|
502
611
|
});
|
|
503
612
|
const projectKey = Cypress.env('PROJECT_KEY');
|
|
504
|
-
|
|
505
|
-
entryPointUriPath: constants
|
|
506
|
-
initialRoute: `/${projectKey}/${constants
|
|
613
|
+
loginByForm(_objectSpread(_objectSpread({}, commandOptions), {}, {
|
|
614
|
+
entryPointUriPath: constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH,
|
|
615
|
+
initialRoute: `/${projectKey}/${constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH}`
|
|
507
616
|
}));
|
|
508
617
|
});
|
|
509
618
|
Cypress.Commands.add('loginByOidc', commandOptions => {
|
|
@@ -511,7 +620,7 @@ Cypress.Commands.add('loginByOidc', commandOptions => {
|
|
|
511
620
|
name: 'loginByOidc'
|
|
512
621
|
});
|
|
513
622
|
cy.log('We recommend not to use the command "cy.loginByOidc" directly. Instead, use the more generic "cy.loginToMerchantCenter" command as it automatically detects which login mechanism to use.');
|
|
514
|
-
|
|
623
|
+
loginByForm(commandOptions);
|
|
515
624
|
});
|
|
516
625
|
Cypress.Commands.add('hover', {
|
|
517
626
|
prevSubject: true
|