@commercetools-frontend/cypress 0.0.0-FEC-157-preview-releases-20241126230331
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 +21 -0
- package/README.md +7 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.d.ts +2 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.d.ts.map +1 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.dev.js +492 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.js +7 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.cjs.prod.js +492 -0
- package/add-commands/dist/commercetools-frontend-cypress-add-commands.esm.js +474 -0
- package/add-commands/index.d.ts +68 -0
- package/add-commands/package.json +5 -0
- package/dist/commercetools-frontend-cypress.cjs.d.ts +2 -0
- package/dist/commercetools-frontend-cypress.cjs.d.ts.map +1 -0
- package/dist/commercetools-frontend-cypress.cjs.dev.js +12 -0
- package/dist/commercetools-frontend-cypress.cjs.js +7 -0
- package/dist/commercetools-frontend-cypress.cjs.prod.js +12 -0
- package/dist/commercetools-frontend-cypress.esm.js +6 -0
- package/dist/constants-18b165fc.esm.js +10 -0
- package/dist/constants-8ad2a50e.cjs.prod.js +13 -0
- package/dist/constants-c657705e.cjs.dev.js +13 -0
- package/dist/declarations/src/add-commands/index.d.ts +5 -0
- package/dist/declarations/src/add-commands/login.d.ts +62 -0
- package/dist/declarations/src/add-commands/real-hover.d.ts +41 -0
- package/dist/declarations/src/constants.d.ts +8 -0
- package/dist/declarations/src/index.d.ts +2 -0
- package/dist/declarations/src/task/index.d.ts +13 -0
- package/dist/declarations/src/version.d.ts +2 -0
- package/package.json +59 -0
- package/task/dist/commercetools-frontend-cypress-task.cjs.d.ts +3 -0
- package/task/dist/commercetools-frontend-cypress-task.cjs.d.ts.map +1 -0
- package/task/dist/commercetools-frontend-cypress-task.cjs.dev.js +126 -0
- package/task/dist/commercetools-frontend-cypress-task.cjs.js +7 -0
- package/task/dist/commercetools-frontend-cypress-task.cjs.prod.js +126 -0
- package/task/dist/commercetools-frontend-cypress-task.esm.js +106 -0
- package/task/package.json +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 commercetools GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @commercetools-frontend/cypress
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@commercetools-frontend/cypress"><img src="https://badgen.net/npm/v/@commercetools-frontend/cypress" alt="Latest release (latest dist-tag)" /></a> <a href="https://www.npmjs.com/package/@commercetools-frontend/cypress"><img src="https://badgen.net/npm/v/@commercetools-frontend/cypress/next" alt="Latest release (next dist-tag)" /></a> <a href="https://bundlephobia.com/result?p=@commercetools-frontend/cypress"><img src="https://badgen.net/bundlephobia/minzip/@commercetools-frontend/cypress" alt="Minified + GZipped size" /></a> <a href="https://github.com/commercetools/merchant-center-application-kit/blob/main/LICENSE"><img src="https://badgen.net/github/license/commercetools/merchant-center-application-kit" alt="GitHub license" /></a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Check out the [documentation](https://docs.commercetools.com/merchant-center-customizations/api-reference/commercetools-frontend-cypress) for more information.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commercetools-frontend-cypress-add-commands.cjs.d.ts","sourceRoot":"","sources":["../../dist/declarations/src/add-commands/index.d.ts"],"names":[],"mappings":"AAAA"}
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
|
|
4
|
+
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
5
|
+
var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
|
|
6
|
+
var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
|
|
7
|
+
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
|
|
8
|
+
var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
|
|
9
|
+
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
|
|
10
|
+
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
11
|
+
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
12
|
+
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
13
|
+
var constants$1 = require('@commercetools-frontend/constants');
|
|
14
|
+
var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
|
|
15
|
+
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
16
|
+
var semver = require('semver');
|
|
17
|
+
var uuid = require('uuid');
|
|
18
|
+
var ssr = require('@commercetools-frontend/application-shell/ssr');
|
|
19
|
+
var constants = require('../../dist/constants-c657705e.cjs.dev.js');
|
|
20
|
+
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
21
|
+
var _reduceRightInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/reduce-right');
|
|
22
|
+
|
|
23
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
24
|
+
|
|
25
|
+
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
26
|
+
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
27
|
+
var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
|
|
28
|
+
var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
|
|
29
|
+
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
|
|
30
|
+
var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
|
|
31
|
+
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
32
|
+
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
33
|
+
var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
|
|
34
|
+
var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
|
|
35
|
+
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
36
|
+
var semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
37
|
+
var _reduceRightInstanceProperty__default = /*#__PURE__*/_interopDefault(_reduceRightInstanceProperty);
|
|
38
|
+
|
|
39
|
+
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; }
|
|
40
|
+
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
41
|
+
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
|
|
46
|
+
// Alias for backwards compatibility
|
|
47
|
+
|
|
48
|
+
function isFeatureSupported(expectedVersion) {
|
|
49
|
+
return semver__default["default"].gte(Cypress.version, expectedVersion);
|
|
50
|
+
}
|
|
51
|
+
function loginByForm(commandOptions) {
|
|
52
|
+
if (isLocalhost()) {
|
|
53
|
+
throw new Error(`At the moment, the "loginByForm" command only works when testing a Merchant Center production URL. Using form login in an application running on localhost is not supported due to issues with "cy.origin".`);
|
|
54
|
+
}
|
|
55
|
+
const projectKey = commandOptions.projectKey ?? Cypress.env('PROJECT_KEY');
|
|
56
|
+
cy.task('customApplicationConfig', {
|
|
57
|
+
entryPointUriPath: commandOptions.entryPointUriPath,
|
|
58
|
+
dotfiles: commandOptions.dotfiles
|
|
59
|
+
},
|
|
60
|
+
// Do not show log, as it may contain sensible information.
|
|
61
|
+
{
|
|
62
|
+
log: false
|
|
63
|
+
}).then(appConfig => {
|
|
64
|
+
let url = `/${projectKey}/${commandOptions.entryPointUriPath}`;
|
|
65
|
+
if (commandOptions.entryPointUriPath === 'account') {
|
|
66
|
+
url = `/${commandOptions.entryPointUriPath}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Log loaded application config for debugging purposes.
|
|
70
|
+
Cypress.log({
|
|
71
|
+
displayName: 'task',
|
|
72
|
+
name: 'customApplicationConfig',
|
|
73
|
+
message: appConfig
|
|
74
|
+
});
|
|
75
|
+
const userCredentials = commandOptions.login ?? {
|
|
76
|
+
email: Cypress.env('LOGIN_EMAIL') || Cypress.env('LOGIN_USER'),
|
|
77
|
+
password: Cypress.env('LOGIN_PASSWORD')
|
|
78
|
+
};
|
|
79
|
+
const sessionKey = ['loginByForm', userCredentials.email, commandOptions.entryPointUriPath];
|
|
80
|
+
// const mcUrl = new URL(appConfig.mcApiUrl);
|
|
81
|
+
// const mcFrontendHostname = mcUrl.hostname.replace('mc-api', 'mc');
|
|
82
|
+
|
|
83
|
+
function authCallback() {
|
|
84
|
+
cy.visit(url, {
|
|
85
|
+
onBeforeLoad: commandOptions.onBeforeLoad
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// NOTE: using `cy.origin` is currently disabled as it does not seem to properly work.
|
|
89
|
+
// Interestingly, starting an application locally using Vite works, however not when using Webpack.
|
|
90
|
+
// For now we keep it disabled until we find a solution.
|
|
91
|
+
|
|
92
|
+
// // https://cypress.io/blog/2022/04/25/cypress-9-6-0-easily-test-multi-domain-workflows-with-cy-origin/
|
|
93
|
+
// cy.origin(
|
|
94
|
+
// mcFrontendHostname,
|
|
95
|
+
// { args: userCredentials },
|
|
96
|
+
// fillLoginForm
|
|
97
|
+
// );
|
|
98
|
+
fillLoginForm(userCredentials);
|
|
99
|
+
|
|
100
|
+
// Wait for the route to be loaded so that the session can be saved.
|
|
101
|
+
cy.url().should('include', url);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// For backwards compatibility.
|
|
105
|
+
if (isFeatureSupported('12.0.0') || Cypress.config('experimentalSessionAndOrigin')) {
|
|
106
|
+
// https://www.cypress.io/blog/2021/08/04/authenticate-faster-in-tests-cy-session-command/
|
|
107
|
+
cy.session(sessionKey, authCallback, isFeatureSupported('10.9.0') ? {
|
|
108
|
+
cacheAcrossSpecs: typeof commandOptions.disableCacheAcrossSpecs === 'boolean' ? !commandOptions.disableCacheAcrossSpecs : true
|
|
109
|
+
} : undefined);
|
|
110
|
+
} else {
|
|
111
|
+
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.`);
|
|
112
|
+
authCallback();
|
|
113
|
+
}
|
|
114
|
+
if (commandOptions.initialRoute) {
|
|
115
|
+
cy.visit(`${Cypress.config('baseUrl')}${commandOptions.initialRoute}`);
|
|
116
|
+
cy.url().should('include', commandOptions.initialRoute);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const isCustomView = commandOptions => commandOptions.entryPointUriPath === constants$1.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH;
|
|
121
|
+
function loginByOidc(commandOptions) {
|
|
122
|
+
const isCustomViewConfigCommand = isCustomView(commandOptions);
|
|
123
|
+
if (!isLocalhost()) {
|
|
124
|
+
throw new Error(`The "loginByOidc" command only works when testing a Custom ${isCustomViewConfigCommand ? 'View' : 'Application'} running on localhost.`);
|
|
125
|
+
}
|
|
126
|
+
const sessionNonce = uuid.v4();
|
|
127
|
+
let projectKey = undefined;
|
|
128
|
+
if (commandOptions.entryPointUriPath !== 'account') {
|
|
129
|
+
projectKey = commandOptions.projectKey ?? Cypress.env('PROJECT_KEY');
|
|
130
|
+
}
|
|
131
|
+
const customEntityConfigCommand = isCustomViewConfigCommand ? 'customViewConfig' : 'customApplicationConfig';
|
|
132
|
+
const packageName = commandOptions.packageName ?? Cypress.env('PACKAGE_NAME');
|
|
133
|
+
if (isCustomViewConfigCommand && !packageName) {
|
|
134
|
+
throw new Error(`Missing required option "packageName" when using the "loginToMerchantCenterForCustomView" command.`);
|
|
135
|
+
}
|
|
136
|
+
cy.task(customEntityConfigCommand, _objectSpread$1({
|
|
137
|
+
entryPointUriPath: commandOptions.entryPointUriPath,
|
|
138
|
+
dotfiles: commandOptions.dotfiles
|
|
139
|
+
}, isCustomViewConfigCommand ? {
|
|
140
|
+
packageName
|
|
141
|
+
} : {}),
|
|
142
|
+
// Do not show log, as it may contain sensible information.
|
|
143
|
+
{
|
|
144
|
+
log: false
|
|
145
|
+
}).then(appConfig => {
|
|
146
|
+
// Log loaded application config for debugging purposes.
|
|
147
|
+
Cypress.log({
|
|
148
|
+
displayName: 'task',
|
|
149
|
+
name: customEntityConfigCommand,
|
|
150
|
+
message: appConfig
|
|
151
|
+
});
|
|
152
|
+
const applicationId = appConfig.applicationId;
|
|
153
|
+
const sessionScope = ssr.buildOidcScope({
|
|
154
|
+
projectKey,
|
|
155
|
+
oAuthScopes: appConfig.__DEVELOPMENT__?.oidc?.oAuthScopes,
|
|
156
|
+
additionalOAuthScopes: appConfig.__DEVELOPMENT__?.oidc?.additionalOAuthScopes,
|
|
157
|
+
teamId: appConfig.__DEVELOPMENT__?.oidc?.teamId,
|
|
158
|
+
applicationId: appConfig.__DEVELOPMENT__?.oidc?.applicationId
|
|
159
|
+
});
|
|
160
|
+
const userCredentials = commandOptions.login ?? {
|
|
161
|
+
email: Cypress.env('LOGIN_EMAIL') || Cypress.env('LOGIN_USER'),
|
|
162
|
+
password: Cypress.env('LOGIN_PASSWORD')
|
|
163
|
+
};
|
|
164
|
+
// Perform the login using the API, then store some required values into the browser storage
|
|
165
|
+
// and redirect to the auth callback route.
|
|
166
|
+
const requestOptions = {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
url: `${appConfig.mcApiUrl}/tokens`,
|
|
169
|
+
body: _objectSpread$1(_objectSpread$1({}, userCredentials), {}, {
|
|
170
|
+
client_id: applicationId,
|
|
171
|
+
response_type: constants.OIDC_RESPONSE_TYPES.ID_TOKEN,
|
|
172
|
+
scope: sessionScope,
|
|
173
|
+
state: sessionNonce,
|
|
174
|
+
nonce: sessionNonce
|
|
175
|
+
}),
|
|
176
|
+
followRedirect: false
|
|
177
|
+
};
|
|
178
|
+
cy.request(requestOptions).then(res => {
|
|
179
|
+
const sessionKey = ['loginByOidc', userCredentials.email, commandOptions.entryPointUriPath];
|
|
180
|
+
function authCallback() {
|
|
181
|
+
cy.visit(res.body.redirectTo, {
|
|
182
|
+
onBeforeLoad(win) {
|
|
183
|
+
if (projectKey) {
|
|
184
|
+
win.localStorage.setItem(constants.STORAGE_KEYS.ACTIVE_PROJECT_KEY, projectKey);
|
|
185
|
+
}
|
|
186
|
+
win.sessionStorage.setItem(`${constants.STORAGE_KEYS.NONCE}_${sessionNonce}`, _JSON$stringify__default["default"]({
|
|
187
|
+
applicationId,
|
|
188
|
+
query: {}
|
|
189
|
+
}));
|
|
190
|
+
win.sessionStorage.setItem(constants.STORAGE_KEYS.SESSION_SCOPE, sessionScope);
|
|
191
|
+
if (commandOptions.onBeforeLoad) {
|
|
192
|
+
commandOptions.onBeforeLoad(win);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
// Wait for the application to be loaded so that the session can be saved.
|
|
197
|
+
cy.get('#app-loader').should('not.exist');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// For backwards compatibility.
|
|
201
|
+
if (isFeatureSupported('12.0.0') || Cypress.config('experimentalSessionAndOrigin')) {
|
|
202
|
+
// https://www.cypress.io/blog/2021/08/04/authenticate-faster-in-tests-cy-session-command/
|
|
203
|
+
cy.session(sessionKey, authCallback, isFeatureSupported('10.9.0') ? {
|
|
204
|
+
cacheAcrossSpecs: typeof commandOptions.disableCacheAcrossSpecs === 'boolean' ? !commandOptions.disableCacheAcrossSpecs : true
|
|
205
|
+
} : undefined);
|
|
206
|
+
} else {
|
|
207
|
+
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.`);
|
|
208
|
+
authCallback();
|
|
209
|
+
}
|
|
210
|
+
if (commandOptions.initialRoute) {
|
|
211
|
+
cy.visit(`${Cypress.config('baseUrl')}${commandOptions.initialRoute}`);
|
|
212
|
+
cy.url().should('include', commandOptions.initialRoute);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* Utilities */
|
|
219
|
+
|
|
220
|
+
function fillLoginForm(userCredentials) {
|
|
221
|
+
cy.get('input[name=email]').type(userCredentials.email);
|
|
222
|
+
cy.get('input[name=password]').type(userCredentials.password, {
|
|
223
|
+
log: false
|
|
224
|
+
});
|
|
225
|
+
cy.get('button').contains('Sign in').click();
|
|
226
|
+
}
|
|
227
|
+
function isLocalhost() {
|
|
228
|
+
const baseUrl = new _URL__default["default"](Cypress.config('baseUrl'));
|
|
229
|
+
return baseUrl.hostname === 'localhost';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* NOTE: the `realHover` command is originally being implemented in `cypress-real-events` package.
|
|
234
|
+
* https://github.com/dmtrKovalenko/cypress-real-events/blob/develop/src/commands/realHover.ts
|
|
235
|
+
*
|
|
236
|
+
* However, due to known issues with conflicting types between Cypress and Jest, importing the `cypress-real-events`
|
|
237
|
+
* package here will cause such issues with TypeScript as our `@commercetools-frontend/cypress` package
|
|
238
|
+
* is checked and built together with all other packages and not in isolation.
|
|
239
|
+
* See https://docs.cypress.io/guides/tooling/typescript-support#Clashing-types-with-Jest.
|
|
240
|
+
*
|
|
241
|
+
* Therefore, we are porting here the implementation of `realHover` to avoid importing it from the
|
|
242
|
+
* original package `cypress-real-events`.
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
246
|
+
|
|
247
|
+
async function fireCdpCommand(command, params) {
|
|
248
|
+
return Cypress.automation('remote:debugger:protocol', {
|
|
249
|
+
command,
|
|
250
|
+
params
|
|
251
|
+
}).catch(error => {
|
|
252
|
+
throw new Error(`Failed request to chrome devtools protocol. This can happen if cypress lost connection to the browser or the command itself is not valid. Original cypress error: ${error}`);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function getPositionedCoordinates(x0, y0, width, height, position, frameScale) {
|
|
256
|
+
if (typeof position === 'object' && position !== null) {
|
|
257
|
+
const x = position.x,
|
|
258
|
+
y = position.y;
|
|
259
|
+
// scale the position coordinates according to the viewport scale
|
|
260
|
+
return [x0 + x * frameScale, y0 + y * frameScale];
|
|
261
|
+
}
|
|
262
|
+
switch (position) {
|
|
263
|
+
case 'topLeft':
|
|
264
|
+
return [x0, y0];
|
|
265
|
+
case 'top':
|
|
266
|
+
return [x0 + width / 2, y0];
|
|
267
|
+
case 'topRight':
|
|
268
|
+
return [x0 + width - 1, y0];
|
|
269
|
+
case 'left':
|
|
270
|
+
return [x0, y0 + height / 2];
|
|
271
|
+
case 'right':
|
|
272
|
+
return [x0 + width - 1, y0 + height / 2];
|
|
273
|
+
case 'bottomLeft':
|
|
274
|
+
return [x0, y0 + height - 1];
|
|
275
|
+
case 'bottom':
|
|
276
|
+
return [x0 + width / 2, y0 + height - 1];
|
|
277
|
+
case 'bottomRight':
|
|
278
|
+
return [x0 + width - 1, y0 + height - 1];
|
|
279
|
+
// center by default
|
|
280
|
+
default:
|
|
281
|
+
return [x0 + width / 2, y0 + height / 2];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Scrolls the given htmlElement into view on the page.
|
|
286
|
+
* The position the element is scrolled to can be customized with scrollBehavior.
|
|
287
|
+
*/
|
|
288
|
+
function scrollIntoView(htmlElement) {
|
|
289
|
+
let scrollBehavior = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'center';
|
|
290
|
+
let block;
|
|
291
|
+
if (scrollBehavior === 'top') {
|
|
292
|
+
block = 'start';
|
|
293
|
+
} else if (scrollBehavior === 'bottom') {
|
|
294
|
+
block = 'end';
|
|
295
|
+
} else {
|
|
296
|
+
block = scrollBehavior;
|
|
297
|
+
}
|
|
298
|
+
htmlElement.scrollIntoView({
|
|
299
|
+
block
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// for cross origin domains .frameElement returns null so query using parentWindow
|
|
304
|
+
// but when running using --disable-web-security it will return the frame element
|
|
305
|
+
function getFrameElement(currentWindow) {
|
|
306
|
+
var _context;
|
|
307
|
+
if (currentWindow.frameElement) {
|
|
308
|
+
// accessible for same-origin iframes
|
|
309
|
+
// or when running with --disable-web-security
|
|
310
|
+
return currentWindow.frameElement;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// fallback to querying using the parent window, mainly to grab the AUT iframe
|
|
314
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
315
|
+
return _findInstanceProperty__default["default"](_context = [...currentWindow.parent.document.querySelectorAll('iframe')]).call(_context, iframe => iframe.contentWindow === currentWindow);
|
|
316
|
+
}
|
|
317
|
+
function getIframesPositionShift(element) {
|
|
318
|
+
let currentWindow = element.ownerDocument.defaultView;
|
|
319
|
+
const noPositionShift = {
|
|
320
|
+
frameScale: 1,
|
|
321
|
+
frameX: 0,
|
|
322
|
+
frameY: 0
|
|
323
|
+
};
|
|
324
|
+
if (!currentWindow) {
|
|
325
|
+
return noPositionShift;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// eslint-disable-next-line prefer-const
|
|
329
|
+
const iframes = [];
|
|
330
|
+
while (currentWindow !== window.top) {
|
|
331
|
+
iframes.push(getFrameElement(currentWindow));
|
|
332
|
+
currentWindow = currentWindow.parent;
|
|
333
|
+
}
|
|
334
|
+
return _reduceRightInstanceProperty__default["default"](iframes).call(iframes, (_ref, frame) => {
|
|
335
|
+
let frameX = _ref.frameX,
|
|
336
|
+
frameY = _ref.frameY,
|
|
337
|
+
frameScale = _ref.frameScale;
|
|
338
|
+
const _frame$getBoundingCli = frame.getBoundingClientRect(),
|
|
339
|
+
x = _frame$getBoundingCli.x,
|
|
340
|
+
y = _frame$getBoundingCli.y,
|
|
341
|
+
width = _frame$getBoundingCli.width;
|
|
342
|
+
return {
|
|
343
|
+
frameX: frameX + x * frameScale,
|
|
344
|
+
frameY: frameY + y * frameScale,
|
|
345
|
+
frameScale: frameScale * (width / frame.offsetWidth)
|
|
346
|
+
};
|
|
347
|
+
}, noPositionShift);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Returns the coordinates and size of a given Element, relative to the Cypress app <iframe>.
|
|
352
|
+
* Accounts for any scaling on the iframes.
|
|
353
|
+
*/
|
|
354
|
+
function getElementPositionXY(htmlElement) {
|
|
355
|
+
const _htmlElement$getBound = htmlElement.getBoundingClientRect(),
|
|
356
|
+
elementX = _htmlElement$getBound.x,
|
|
357
|
+
elementY = _htmlElement$getBound.y,
|
|
358
|
+
width = _htmlElement$getBound.width,
|
|
359
|
+
height = _htmlElement$getBound.height;
|
|
360
|
+
const _getIframesPositionSh = getIframesPositionShift(htmlElement),
|
|
361
|
+
frameScale = _getIframesPositionSh.frameScale,
|
|
362
|
+
frameX = _getIframesPositionSh.frameX,
|
|
363
|
+
frameY = _getIframesPositionSh.frameY;
|
|
364
|
+
return {
|
|
365
|
+
x: frameX + elementX * frameScale,
|
|
366
|
+
y: frameY + elementY * frameScale,
|
|
367
|
+
width: width * frameScale,
|
|
368
|
+
height: height * frameScale,
|
|
369
|
+
frameScale: frameScale
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function getCypressElementCoordinates(
|
|
373
|
+
// @ts-ignore
|
|
374
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
375
|
+
jqueryEl, position, scrollBehavior) {
|
|
376
|
+
const htmlElement = jqueryEl.get(0);
|
|
377
|
+
const cypressAppFrame = window.parent.document.querySelector('iframe');
|
|
378
|
+
if (!cypressAppFrame) {
|
|
379
|
+
throw new Error('Can not find cypress application iframe, it looks like critical issue. Please rise an issue on GitHub.');
|
|
380
|
+
}
|
|
381
|
+
const effectiveScrollBehavior = scrollBehavior ?? Cypress.config('scrollBehavior') ?? 'center';
|
|
382
|
+
if (effectiveScrollBehavior && typeof effectiveScrollBehavior !== 'object') {
|
|
383
|
+
scrollIntoView(htmlElement, effectiveScrollBehavior);
|
|
384
|
+
}
|
|
385
|
+
const _getElementPositionXY = getElementPositionXY(htmlElement),
|
|
386
|
+
x = _getElementPositionXY.x,
|
|
387
|
+
y = _getElementPositionXY.y,
|
|
388
|
+
width = _getElementPositionXY.width,
|
|
389
|
+
height = _getElementPositionXY.height,
|
|
390
|
+
frameScale = _getElementPositionXY.frameScale;
|
|
391
|
+
const _getPositionedCoordin = getPositionedCoordinates(x, y, width, height, position ?? 'center', frameScale),
|
|
392
|
+
_getPositionedCoordin2 = _slicedToArray(_getPositionedCoordin, 2),
|
|
393
|
+
posX = _getPositionedCoordin2[0],
|
|
394
|
+
posY = _getPositionedCoordin2[1];
|
|
395
|
+
return {
|
|
396
|
+
x: posX,
|
|
397
|
+
y: posY,
|
|
398
|
+
frameScale: frameScale
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const keyToModifierBitMap = {
|
|
402
|
+
Alt: 1,
|
|
403
|
+
Control: 2,
|
|
404
|
+
Meta: 4,
|
|
405
|
+
Shift: 8
|
|
406
|
+
};
|
|
407
|
+
async function realHover(
|
|
408
|
+
// @ts-ignore
|
|
409
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
410
|
+
subject) {
|
|
411
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
412
|
+
const _getCypressElementCoo = getCypressElementCoordinates(subject, options.position, options.scrollBehavior),
|
|
413
|
+
x = _getCypressElementCoo.x,
|
|
414
|
+
y = _getCypressElementCoo.y;
|
|
415
|
+
const log = Cypress.log({
|
|
416
|
+
$el: subject,
|
|
417
|
+
name: 'realHover',
|
|
418
|
+
consoleProps: () => ({
|
|
419
|
+
'Applied To': subject.get(0),
|
|
420
|
+
'Absolute Coordinates': {
|
|
421
|
+
x,
|
|
422
|
+
y
|
|
423
|
+
}
|
|
424
|
+
})
|
|
425
|
+
});
|
|
426
|
+
await fireCdpCommand('Input.dispatchMouseEvent', {
|
|
427
|
+
x,
|
|
428
|
+
y,
|
|
429
|
+
type: 'mouseMoved',
|
|
430
|
+
button: 'none',
|
|
431
|
+
pointerType: options.pointer ?? 'mouse',
|
|
432
|
+
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0
|
|
433
|
+
});
|
|
434
|
+
log.snapshot().end();
|
|
435
|
+
return subject;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function ownKeys(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; }
|
|
439
|
+
function _objectSpread(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(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(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
440
|
+
|
|
441
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
442
|
+
|
|
443
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
444
|
+
|
|
445
|
+
Cypress.Commands.add('loginToMerchantCenter', commandOptions => {
|
|
446
|
+
Cypress.log({
|
|
447
|
+
name: 'loginToMerchantCenter'
|
|
448
|
+
});
|
|
449
|
+
if (isLocalhost()) {
|
|
450
|
+
loginByOidc(commandOptions);
|
|
451
|
+
} else {
|
|
452
|
+
loginByForm(commandOptions);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
Cypress.Commands.add('loginToMerchantCenterForCustomView', commandOptions => {
|
|
456
|
+
Cypress.log({
|
|
457
|
+
name: 'loginToMerchantCenterForCustomView'
|
|
458
|
+
});
|
|
459
|
+
const projectKey = Cypress.env('PROJECT_KEY');
|
|
460
|
+
loginByOidc(_objectSpread(_objectSpread({}, commandOptions), {}, {
|
|
461
|
+
entryPointUriPath: constants$1.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH,
|
|
462
|
+
initialRoute: `/${projectKey}/${constants$1.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH}`
|
|
463
|
+
}));
|
|
464
|
+
});
|
|
465
|
+
Cypress.Commands.add('loginByOidc', commandOptions => {
|
|
466
|
+
Cypress.log({
|
|
467
|
+
name: 'loginByOidc'
|
|
468
|
+
});
|
|
469
|
+
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.');
|
|
470
|
+
loginByOidc(commandOptions);
|
|
471
|
+
});
|
|
472
|
+
Cypress.Commands.add('hover', {
|
|
473
|
+
prevSubject: true
|
|
474
|
+
}, realHover);
|
|
475
|
+
Cypress.Commands.add('showNavigationSubmenuItems', menuItemTextMatcher => {
|
|
476
|
+
cy.findByTestId('left-navigation').findByText(menuItemTextMatcher).parents('[role="menuitem"]').first()
|
|
477
|
+
// Refers to the custom command "hover"
|
|
478
|
+
.hover();
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// https://github.com/cypress-io/cypress/issues/136#issuecomment-342391119
|
|
482
|
+
Cypress.Commands.add('getIframeBody', {
|
|
483
|
+
prevSubject: 'element'
|
|
484
|
+
},
|
|
485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
486
|
+
$iframe => {
|
|
487
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
488
|
+
return new Cypress.Promise(resolve => {
|
|
489
|
+
var _context;
|
|
490
|
+
resolve(_findInstanceProperty__default["default"](_context = $iframe.contents()).call(_context, 'body'));
|
|
491
|
+
});
|
|
492
|
+
});
|