@jahia/cypress 8.0.0 → 8.1.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/CHANGELOG.md +14 -0
- package/README.md +65 -0
- package/dist/injections/bash-data.d.ts +1 -0
- package/dist/injections/bash-data.js +57 -0
- package/dist/injections/chars-data.d.ts +1 -0
- package/dist/injections/chars-data.js +25 -0
- package/dist/injections/htmlentities-data.d.ts +1 -0
- package/dist/injections/htmlentities-data.js +22 -0
- package/dist/injections/numbers-data.d.ts +1 -0
- package/dist/injections/numbers-data.js +66 -0
- package/dist/injections/sql-data.d.ts +1 -0
- package/dist/injections/sql-data.js +82 -0
- package/dist/injections/xss-data.d.ts +1 -0
- package/dist/injections/xss-data.js +740 -0
- package/dist/support/apollo/apollo.d.ts +2 -0
- package/dist/support/apollo/apollo.js +77 -15
- package/dist/support/browserHelper.d.ts +10 -0
- package/dist/support/browserHelper.js +167 -0
- package/dist/support/index.d.ts +3 -0
- package/dist/support/index.js +3 -0
- package/dist/support/jfaker.d.ts +60 -0
- package/dist/support/jfaker.js +241 -0
- package/dist/support/modSince.d.ts +52 -0
- package/dist/support/modSince.js +180 -0
- package/dist/support/provisioning/executeGroovy.js +41 -2
- package/dist/support/provisioning/runProvisioningScript.d.ts +1 -1
- package/dist/support/provisioning/runProvisioningScript.js +84 -7
- package/dist/support/registerSupport.js +34 -0
- package/docs/browser-helper.md +158 -0
- package/docs/jfaker.md +450 -0
- package/package.json +3 -1
- package/src/injections/bash-data.ts +54 -0
- package/src/injections/chars-data.ts +22 -0
- package/src/injections/htmlentities-data.ts +19 -0
- package/src/injections/numbers-data.ts +63 -0
- package/src/injections/sql-data.ts +79 -0
- package/src/injections/xss-data.ts +737 -0
- package/src/support/apollo/apollo.ts +74 -11
- package/src/support/browserHelper.ts +186 -0
- package/src/support/index.ts +3 -0
- package/src/support/jfaker.ts +245 -0
- package/src/support/modSince.ts +222 -0
- package/src/support/provisioning/executeGroovy.md +7 -1
- package/src/support/provisioning/executeGroovy.ts +46 -2
- package/src/support/provisioning/runProvisioningScript.ts +89 -12
- package/src/support/registerSupport.ts +29 -0
- package/tests/cypress/e2e/jfaker.spec.ts +411 -0
- package/tests/cypress/e2e/modSince.spec.ts +306 -0
- package/tests/cypress.config.ts +23 -0
- package/tests/package.json +41 -0
- package/tests/reporter-config.json +13 -0
- package/tests/yarn.lock +8578 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {compare, validate} from 'compare-versions';
|
|
2
|
+
// Intentionally keep explicit path to avoid edge case errors in runtime
|
|
3
|
+
import {getJahiaVersion} from '../utils/JahiaPlatformHelper';
|
|
4
|
+
|
|
5
|
+
/** Cypress environment variable key used to store the current Jahia version. */
|
|
6
|
+
export const JAHIA_VERSION_ENV_VAR = 'CYPRESS_JAHIA_VERSION';
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
|
+
namespace Mocha {
|
|
11
|
+
interface TestFunction {
|
|
12
|
+
since(requiredVersion: string, title: string, fn?: Func): Test;
|
|
13
|
+
since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ExclusiveTestFunction {
|
|
17
|
+
since(requiredVersion: string, title: string, fn?: Func): Test;
|
|
18
|
+
since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PendingTestFunction {
|
|
22
|
+
since(requiredVersion: string, title: string, fn?: Func): Test;
|
|
23
|
+
since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface SuiteFunction {
|
|
27
|
+
since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface ExclusiveSuiteFunction {
|
|
31
|
+
since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PendingSuiteFunction {
|
|
35
|
+
since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ─── Internal helpers ────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns `true` when `current` satisfies `>= required`.
|
|
44
|
+
* Treats missing, empty, or unparseable versions as unsupported.
|
|
45
|
+
* @param current - The running Jahia version read from `Cypress.env`.
|
|
46
|
+
* @param required - Minimum version the test or suite needs.
|
|
47
|
+
*/
|
|
48
|
+
const isSupported = (current: string | undefined, required: string): boolean => {
|
|
49
|
+
if (!current?.trim()) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
return compare(String(current), required, '>=');
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Validates `since(...)` arguments and throws a descriptive error on misuse.
|
|
62
|
+
* Detects the common mistake of swapping `requiredVersion` and `title`.
|
|
63
|
+
* @param version - Version string passed as the first argument.
|
|
64
|
+
* @param title - Title string passed as the second argument.
|
|
65
|
+
* @param scope - Label used in the error message (e.g. `"it.since"`).
|
|
66
|
+
*/
|
|
67
|
+
const assertArgs = (version: string, title: string, scope: string): void => {
|
|
68
|
+
if (!validate(version)) {
|
|
69
|
+
const hint = validate(title) ? ' (arguments appear swapped)' : '';
|
|
70
|
+
throw new Error(`[${scope}] Invalid version: "${version}"${hint}.`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Builds a human-readable message explaining why a test or suite was skipped.
|
|
76
|
+
* @param scope - Label for the helper (e.g. `"it.since"` or `"describe.since"`).
|
|
77
|
+
* @param title - Original test or suite title.
|
|
78
|
+
* @param required - Minimum version the test or suite needs.
|
|
79
|
+
* @param current - The running Jahia version; `undefined` when not yet fetched.
|
|
80
|
+
*/
|
|
81
|
+
const skipReason = (scope: string, title: string, required: string, current?: string): string =>
|
|
82
|
+
current ?
|
|
83
|
+
`[${scope}] Skipping "${title}" — ${JAHIA_VERSION_ENV_VAR}="${current}" < required ${required}.` :
|
|
84
|
+
`[${scope}] Skipping "${title}" — ${JAHIA_VERSION_ENV_VAR} is not set. Required: ${required}.`;
|
|
85
|
+
|
|
86
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Fetches the Jahia version from the GraphQL API, strips the `-SNAPSHOT` suffix,
|
|
90
|
+
* and caches the result in `Cypress.env(JAHIA_VERSION_ENV_VAR)`.
|
|
91
|
+
*/
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
+
export const initializeVersionSupport = (): Cypress.Chainable<any> =>
|
|
94
|
+
getJahiaVersion().then(jahiaVersion => {
|
|
95
|
+
const version = jahiaVersion.release.replace('-SNAPSHOT', '');
|
|
96
|
+
Cypress.env(JAHIA_VERSION_ENV_VAR, version);
|
|
97
|
+
return version;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Attaches `.since()` to `it`, `it.only`, `it.skip`, `describe`, `describe.only`,
|
|
102
|
+
* and `describe.skip`. Safe to call multiple times — subsequent calls are no-ops.
|
|
103
|
+
*/
|
|
104
|
+
export const registerVersionSupport = (): void => {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
const mochaIt = globalThis.it as any;
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
|
+
const mochaDescribe = globalThis.describe as any;
|
|
109
|
+
|
|
110
|
+
if (!mochaIt) {
|
|
111
|
+
throw new Error('Unable to register version support because Mocha `it` is not available.');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!mochaDescribe) {
|
|
115
|
+
throw new Error('Unable to register version support because Mocha `describe` is not available.');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Attach .since() to it / it.only / it.skip
|
|
119
|
+
for (const target of [mochaIt, mochaIt.only, mochaIt.skip]) {
|
|
120
|
+
if (typeof target.since === 'function') {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const isSkip = target === mochaIt.skip;
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
126
|
+
target.since = (version: string, title: string, configOrFn?: any, maybeFn?: any) => {
|
|
127
|
+
assertArgs(version, title, 'it.since');
|
|
128
|
+
|
|
129
|
+
if (isSkip) {
|
|
130
|
+
// It.skip.since: always skip unconditionally, preserve the title
|
|
131
|
+
return typeof configOrFn === 'function' || configOrFn === undefined ?
|
|
132
|
+
target(title, configOrFn) :
|
|
133
|
+
target(title, configOrFn, maybeFn);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const userFn = typeof configOrFn === 'function' ? configOrFn : maybeFn;
|
|
137
|
+
const wrappedFn = function (this: Mocha.Context) {
|
|
138
|
+
const current = Cypress.env(JAHIA_VERSION_ENV_VAR);
|
|
139
|
+
if (!isSupported(current, version)) {
|
|
140
|
+
console.warn(skipReason('it.since', title, version, current));
|
|
141
|
+
this.skip();
|
|
142
|
+
} else if (typeof userFn === 'function') {
|
|
143
|
+
return userFn.call(this);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return typeof configOrFn === 'object' && configOrFn !== null ?
|
|
148
|
+
target(title, configOrFn, wrappedFn) :
|
|
149
|
+
target(title, wrappedFn);
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Attach .since() to describe / describe.only / describe.skip
|
|
154
|
+
for (const target of [mochaDescribe, mochaDescribe.only, mochaDescribe.skip]) {
|
|
155
|
+
if (typeof target.since === 'function') {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const isSkip = target === mochaDescribe.skip;
|
|
160
|
+
target.since = (version: string, title: string, fn: (this: Mocha.Suite) => void) => {
|
|
161
|
+
assertArgs(version, title, 'describe.since');
|
|
162
|
+
|
|
163
|
+
if (isSkip) {
|
|
164
|
+
// Describe.skip.since: always skip unconditionally, preserve the title
|
|
165
|
+
return target(title, fn);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return target(title, function (this: Mocha.Suite) {
|
|
169
|
+
// Suite-level runtime check runs after the global before() has fetched the version
|
|
170
|
+
before(function (this: Mocha.Context) {
|
|
171
|
+
const current = Cypress.env(JAHIA_VERSION_ENV_VAR);
|
|
172
|
+
if (!isSupported(current, version)) {
|
|
173
|
+
console.warn(skipReason('describe.since', title, version, current));
|
|
174
|
+
this.skip();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
fn.call(this);
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Compatibility shim: redirect accidental it.skip(version, title, fn) → it.skip.since(...)
|
|
184
|
+
const origItSkip = mochaIt.skip;
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
mochaIt.skip = Object.assign((title: string, configOrTitle?: any, maybeFn?: any) => {
|
|
187
|
+
if (validate(title) && typeof configOrTitle === 'string' && typeof maybeFn === 'function') {
|
|
188
|
+
return origItSkip.since(title, configOrTitle, maybeFn);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return typeof configOrTitle === 'function' || configOrTitle === undefined ?
|
|
192
|
+
origItSkip(title, configOrTitle) :
|
|
193
|
+
origItSkip(title, configOrTitle, maybeFn);
|
|
194
|
+
}, {since: origItSkip.since});
|
|
195
|
+
|
|
196
|
+
const origDescribeSkip = mochaDescribe.skip;
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
198
|
+
mochaDescribe.skip = Object.assign((title: string, fnOrTitle?: any, maybeFn?: any) => {
|
|
199
|
+
if (validate(title) && typeof fnOrTitle === 'string' && typeof maybeFn === 'function') {
|
|
200
|
+
return origDescribeSkip.since(title, fnOrTitle, maybeFn);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return origDescribeSkip(title, fnOrTitle);
|
|
204
|
+
}, {since: origDescribeSkip.since});
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Enables version-gated testing for the Cypress suite.
|
|
209
|
+
* Registers `it.since`, `describe.since` (and their `.only`/`.skip` variants),
|
|
210
|
+
* then fetches the running Jahia version in a root `before()` hook.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* it.since('8.2.0', 'works on 8.2+', () => { ... });
|
|
214
|
+
* describe.since('8.2.0', 'suite for 8.2+', () => { ... });
|
|
215
|
+
*/
|
|
216
|
+
function enable(): void {
|
|
217
|
+
registerVersionSupport();
|
|
218
|
+
before(() => initializeVersionSupport());
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Public API for Jahia version-gated testing. */
|
|
222
|
+
export const modSince = {enable};
|
|
@@ -51,4 +51,10 @@ cy.executeGroovy("script.groovy").then(result => { console.log(result) })
|
|
|
51
51
|
|
|
52
52
|
## Command Log
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
When clicking on `groovy` within the command log, the console outputs the following:
|
|
55
|
+
|
|
56
|
+
- **Script**: The name of the Groovy script file executed.
|
|
57
|
+
- **Replacements**: The replacement map applied to the script, if any.
|
|
58
|
+
- **Server**: The Jahia server URL targeted.
|
|
59
|
+
- **Duration**: Elapsed time from invocation to completion.
|
|
60
|
+
- **Result**: The first operation result returned by the provisioning API.
|
|
@@ -25,6 +25,41 @@ const serverDefaults = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
export const executeGroovy = function (scriptFile: string, replacements?: { [key: string]: string }, jahiaServer: JahiaServer = serverDefaults): void {
|
|
28
|
+
let result: any;
|
|
29
|
+
let duration: number;
|
|
30
|
+
let scriptContent: string;
|
|
31
|
+
const startTime = Date.now();
|
|
32
|
+
|
|
33
|
+
const replacementsLabel = replacements && Object.keys(replacements).length > 0 ?
|
|
34
|
+
` — ${JSON.stringify(replacements)}` :
|
|
35
|
+
'';
|
|
36
|
+
|
|
37
|
+
const logger = Cypress.log({
|
|
38
|
+
autoEnd: false,
|
|
39
|
+
name: 'executeGroovy',
|
|
40
|
+
displayName: 'groovy',
|
|
41
|
+
message: `${scriptFile}${replacementsLabel}`,
|
|
42
|
+
consoleProps: () => ({
|
|
43
|
+
Script: scriptFile,
|
|
44
|
+
'Script Content': scriptContent ?? '(loading...)',
|
|
45
|
+
Replacements: replacements ?? {},
|
|
46
|
+
Server: jahiaServer.url,
|
|
47
|
+
Duration: duration === undefined ? 'pending' : `${duration}ms`,
|
|
48
|
+
Result: result
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
cy.fixture(scriptFile, 'utf-8').then((content: string) => {
|
|
53
|
+
let processed = content;
|
|
54
|
+
if (replacements) {
|
|
55
|
+
Object.keys(replacements).forEach(k => {
|
|
56
|
+
processed = processed.replaceAll(k, replacements[k]);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
scriptContent = processed;
|
|
61
|
+
});
|
|
62
|
+
|
|
28
63
|
cy.runProvisioningScript({
|
|
29
64
|
script: {
|
|
30
65
|
fileContent: '- executeScript: "' + scriptFile + '"',
|
|
@@ -36,6 +71,15 @@ export const executeGroovy = function (scriptFile: string, replacements?: { [key
|
|
|
36
71
|
type: 'text/plain',
|
|
37
72
|
encoding: 'utf-8'
|
|
38
73
|
}],
|
|
39
|
-
jahiaServer
|
|
40
|
-
|
|
74
|
+
jahiaServer,
|
|
75
|
+
options: {log: false}
|
|
76
|
+
}).then(r => {
|
|
77
|
+
result = (r as any)?.[0];
|
|
78
|
+
duration = Date.now() - startTime;
|
|
79
|
+
const hasFailed = typeof result === 'string' && result.includes('.failed');
|
|
80
|
+
const prefix = hasFailed ? '❌ ' : '✅ ';
|
|
81
|
+
logger.set('message', `${prefix}${scriptFile}${replacementsLabel}`);
|
|
82
|
+
logger?.end();
|
|
83
|
+
return result;
|
|
84
|
+
});
|
|
41
85
|
};
|
|
@@ -82,16 +82,74 @@ const serverDefaults: JahiaServer = {
|
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
function isFormFile(script: FormFile | StringDictionary[]): script is FormFile {
|
|
85
|
-
return Boolean((script as FormFile)
|
|
85
|
+
return Boolean((script as FormFile)?.fileContent || (script as FormFile)?.fileName);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
script
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
function getScriptSummary(script: FormFile | StringDictionary[]): string {
|
|
89
|
+
if (isFormFile(script)) {
|
|
90
|
+
if (script.fileName) {
|
|
91
|
+
return script.fileName;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (script.fileContent) {
|
|
95
|
+
// Parse first operation and its value from YAML list: "- operationName: value"
|
|
96
|
+
const yamlMatch = script.fileContent.match(/^\s*-\s+(\w+)\s*:\s*"?([^"\n]+)"?/m);
|
|
97
|
+
if (yamlMatch) {
|
|
98
|
+
return `${yamlMatch[1]}: ${yamlMatch[2].trim()}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Parse first operation name from JSON array: [{"operationName": ...}]
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(script.fileContent);
|
|
104
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
105
|
+
const ops = parsed.map((op: Record<string, string>) => Object.keys(op)[0] ?? 'unknown');
|
|
106
|
+
return ops.length === 1 ? ops[0] : `[${ops.join(', ')}]`;
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
// Not valid JSON, fall through
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return 'inline script';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!script || script.length === 0) {
|
|
117
|
+
return 'empty script';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const ops = script.map(op => Object.keys(op)[0] ?? 'unknown');
|
|
121
|
+
return ops.length === 1 ? ops[0] : `[${ops.join(', ')}]`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
125
|
+
export const runProvisioningScript = (paramsOrScript: RunProvisioningScriptParams | FormFile | StringDictionary[], ...rest: any[]): void => {
|
|
126
|
+
// Backward-compatible: support old positional signature
|
|
127
|
+
// runProvisioningScript(script, files, jahiaServer, options, timeout)
|
|
128
|
+
let script: FormFile | StringDictionary[];
|
|
129
|
+
let files: FormFile[];
|
|
130
|
+
let jahiaServer: JahiaServer;
|
|
131
|
+
let options: Cypress.Loggable;
|
|
132
|
+
let requestOptions: Partial<Cypress.RequestOptions>;
|
|
133
|
+
|
|
134
|
+
const isLegacyCall = Array.isArray(paramsOrScript) ||
|
|
135
|
+
(paramsOrScript as FormFile).fileContent !== undefined ||
|
|
136
|
+
(paramsOrScript as FormFile).fileName !== undefined;
|
|
137
|
+
|
|
138
|
+
if (isLegacyCall) {
|
|
139
|
+
script = paramsOrScript as FormFile | StringDictionary[];
|
|
140
|
+
files = rest[0];
|
|
141
|
+
jahiaServer = rest[1] ?? serverDefaults;
|
|
142
|
+
options = rest[2] ?? {log: true};
|
|
143
|
+
requestOptions = {};
|
|
144
|
+
} else {
|
|
145
|
+
const params = paramsOrScript as RunProvisioningScriptParams;
|
|
146
|
+
script = params.script;
|
|
147
|
+
files = params.files;
|
|
148
|
+
jahiaServer = params.jahiaServer ?? serverDefaults;
|
|
149
|
+
options = params.options ?? {log: true};
|
|
150
|
+
requestOptions = params.requestOptions ?? {};
|
|
151
|
+
}
|
|
152
|
+
|
|
95
153
|
const formData = new FormData();
|
|
96
154
|
|
|
97
155
|
if (isFormFile(script)) {
|
|
@@ -115,18 +173,30 @@ export const runProvisioningScript = ({
|
|
|
115
173
|
let result: any;
|
|
116
174
|
let logger: Cypress.Log;
|
|
117
175
|
|
|
176
|
+
const scriptSummary = getScriptSummary(script);
|
|
177
|
+
const replacementsFromFiles = files
|
|
178
|
+
?.filter(f => f.replacements && Object.keys(f.replacements).length > 0)
|
|
179
|
+
.map(f => `${f.fileName}: ${JSON.stringify(f.replacements)}`);
|
|
180
|
+
|
|
118
181
|
if (options.log) {
|
|
119
182
|
logger = Cypress.log({
|
|
120
183
|
autoEnd: false,
|
|
121
184
|
name: 'runProvisioningScript',
|
|
122
185
|
displayName: 'provScript',
|
|
123
|
-
message:
|
|
186
|
+
message: `${scriptSummary} @ ${jahiaServer.url}`,
|
|
124
187
|
consoleProps: () => {
|
|
125
188
|
return {
|
|
126
189
|
Script: script,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
190
|
+
Operations: isFormFile(script) ?
|
|
191
|
+
undefined :
|
|
192
|
+
script?.map(op => `${Object.keys(op)[0]}: ${Object.values(op)[0]}`),
|
|
193
|
+
Files: files?.map(f => f.fileName ?? 'inline file') ?? [],
|
|
194
|
+
Replacements: replacementsFromFiles?.length > 0 ? replacementsFromFiles : undefined,
|
|
195
|
+
Server: jahiaServer.url,
|
|
196
|
+
'HTTP Status': response ? `${response.status} ${response.statusText}` : 'pending',
|
|
197
|
+
Duration: response ? `${response.duration}ms` : 'pending',
|
|
198
|
+
Result: result,
|
|
199
|
+
Response: response
|
|
130
200
|
};
|
|
131
201
|
}
|
|
132
202
|
});
|
|
@@ -161,6 +231,13 @@ export const runProvisioningScript = ({
|
|
|
161
231
|
}
|
|
162
232
|
|
|
163
233
|
logger?.end();
|
|
234
|
+
if (logger) {
|
|
235
|
+
const hasFailed = res.status !== 200 ||
|
|
236
|
+
(Array.isArray(result) && result.some((r: any) => typeof r === 'string' && r.includes('.failed'))); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
237
|
+
const prefix = hasFailed ? '❌ ' : '✅ ';
|
|
238
|
+
logger.set('message', `${prefix}${scriptSummary} @ ${jahiaServer.url}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
164
241
|
return result;
|
|
165
242
|
});
|
|
166
243
|
};
|
|
@@ -5,6 +5,8 @@ import {logout} from './logout';
|
|
|
5
5
|
import {fixture} from './fixture';
|
|
6
6
|
import {repeatUntil} from './repeatUntil';
|
|
7
7
|
import {step} from './testStep';
|
|
8
|
+
import {jfaker} from './jfaker';
|
|
9
|
+
import {modSince} from './modSince';
|
|
8
10
|
|
|
9
11
|
export const registerSupport = (): void => {
|
|
10
12
|
Cypress.Commands.add('apolloClient', apolloClient);
|
|
@@ -24,4 +26,31 @@ export const registerSupport = (): void => {
|
|
|
24
26
|
Cypress.Commands.overwrite('fixture', fixture);
|
|
25
27
|
|
|
26
28
|
Cypress.Commands.add('step', step);
|
|
29
|
+
|
|
30
|
+
// Register it.since()/describe.since()
|
|
31
|
+
modSince.enable();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Override Cypress `type()` command to interpret special characters (e.g., {, }, etc.) either literally or as commands.
|
|
35
|
+
* The behavior is controlled by the `parseSpecialCharSequences` option, which can be set to `true`
|
|
36
|
+
* to enable command parsing or `false` to treat special characters as literal input.
|
|
37
|
+
*
|
|
38
|
+
* Since Cypress `clear()` command is an alias for `.type('{selectall}{del}')`,
|
|
39
|
+
* such case has to be handled to ensure that the special character sequences are properly interpreted when clearing the input.
|
|
40
|
+
* Also cover older Cypress versions which were using {backspace} was used instead of {del} .
|
|
41
|
+
*/
|
|
42
|
+
Cypress.Commands.overwrite<'type', 'element'>(
|
|
43
|
+
'type',
|
|
44
|
+
(originalFn, element, text: string, options: Partial<Cypress.TypeOptions> = {}) => {
|
|
45
|
+
// Check if this is Cypress `.clear() call
|
|
46
|
+
const isCypressClearSequence = ['{selectall}{del}', '{selectall}{backspace}'].includes(text.toString());
|
|
47
|
+
|
|
48
|
+
// Do not override if this is `.clear()` call or data type is `faker`
|
|
49
|
+
const parseSpecialCharSequences = isCypressClearSequence || jfaker.getDataType() === 'faker';
|
|
50
|
+
|
|
51
|
+
// Merge options with passed ones (if any)
|
|
52
|
+
const newOptions: Partial<Cypress.TypeOptions> = {parseSpecialCharSequences, ...options};
|
|
53
|
+
return originalFn(element, text, newOptions);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
27
56
|
};
|