@jahia/cypress 7.4.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.
Files changed (135) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +69 -2
  3. package/dist/index.js +6 -2
  4. package/dist/injections/bash-data.d.ts +1 -0
  5. package/dist/injections/bash-data.js +57 -0
  6. package/dist/injections/chars-data.d.ts +1 -0
  7. package/dist/injections/chars-data.js +25 -0
  8. package/dist/injections/htmlentities-data.d.ts +1 -0
  9. package/dist/injections/htmlentities-data.js +22 -0
  10. package/dist/injections/numbers-data.d.ts +1 -0
  11. package/dist/injections/numbers-data.js +66 -0
  12. package/dist/injections/sql-data.d.ts +1 -0
  13. package/dist/injections/sql-data.js +82 -0
  14. package/dist/injections/xss-data.d.ts +1 -0
  15. package/dist/injections/xss-data.js +740 -0
  16. package/dist/page-object/baseComponent.d.ts +1 -2
  17. package/dist/page-object/baseComponent.js +10 -6
  18. package/dist/page-object/basePage.js +1 -1
  19. package/dist/page-object/html/iframe.d.ts +0 -1
  20. package/dist/page-object/html/iframe.js +2 -2
  21. package/dist/page-object/html/index.js +6 -2
  22. package/dist/page-object/index.js +6 -2
  23. package/dist/page-object/material/index.js +6 -2
  24. package/dist/page-object/material/muiinput.d.ts +0 -1
  25. package/dist/page-object/material/muiinput.js +1 -1
  26. package/dist/page-object/material/muiradio.js +1 -1
  27. package/dist/page-object/moonstone/accordion.d.ts +0 -1
  28. package/dist/page-object/moonstone/accordion.js +2 -2
  29. package/dist/page-object/moonstone/button.js +1 -1
  30. package/dist/page-object/moonstone/collapsible.js +1 -1
  31. package/dist/page-object/moonstone/dropdown.js +2 -2
  32. package/dist/page-object/moonstone/index.js +6 -2
  33. package/dist/page-object/moonstone/menu.js +9 -9
  34. package/dist/page-object/moonstone/pagination.js +3 -3
  35. package/dist/page-object/moonstone/primaryNav.js +2 -2
  36. package/dist/page-object/moonstone/secondaryNav.js +1 -1
  37. package/dist/page-object/moonstone/table.d.ts +0 -1
  38. package/dist/page-object/moonstone/table.js +5 -5
  39. package/dist/page-object/utils.d.ts +0 -1
  40. package/dist/page-object/utils.js +11 -12
  41. package/dist/plugins/env.js +2 -2
  42. package/dist/plugins/index.js +6 -2
  43. package/dist/plugins/registerPlugins.js +2 -2
  44. package/dist/support/apollo/apollo.d.ts +5 -4
  45. package/dist/support/apollo/apollo.js +80 -18
  46. package/dist/support/apollo/apolloClient.d.ts +1 -2
  47. package/dist/support/apollo/apolloClient.js +7 -7
  48. package/dist/support/apollo/index.js +6 -2
  49. package/dist/support/apollo/links.d.ts +1 -1
  50. package/dist/support/apollo/links.js +5 -6
  51. package/dist/support/browserHelper.d.ts +10 -0
  52. package/dist/support/browserHelper.js +167 -0
  53. package/dist/support/commands.js +1 -1
  54. package/dist/support/fixture.d.ts +1 -1
  55. package/dist/support/fixture.js +11 -7
  56. package/dist/support/index.d.ts +3 -0
  57. package/dist/support/index.js +9 -2
  58. package/dist/support/jfaker.d.ts +60 -0
  59. package/dist/support/jfaker.js +241 -0
  60. package/dist/support/jsErrorsLogger.js +13 -9
  61. package/dist/support/login.d.ts +0 -1
  62. package/dist/support/login.js +2 -2
  63. package/dist/support/logout.d.ts +0 -1
  64. package/dist/support/logout.js +1 -1
  65. package/dist/support/modSince.d.ts +52 -0
  66. package/dist/support/modSince.js +180 -0
  67. package/dist/support/provisioning/executeGroovy.d.ts +1 -1
  68. package/dist/support/provisioning/executeGroovy.js +42 -3
  69. package/dist/support/provisioning/index.js +6 -2
  70. package/dist/support/provisioning/installConfig.d.ts +0 -1
  71. package/dist/support/provisioning/installConfig.js +3 -3
  72. package/dist/support/provisioning/installModule.d.ts +0 -1
  73. package/dist/support/provisioning/installModule.js +1 -1
  74. package/dist/support/provisioning/runProvisioningScript.d.ts +4 -5
  75. package/dist/support/provisioning/runProvisioningScript.js +86 -9
  76. package/dist/support/provisioning/uninstallModule.d.ts +0 -1
  77. package/dist/support/provisioning/uninstallModule.js +1 -1
  78. package/dist/support/registerSupport.js +35 -1
  79. package/dist/support/repeatUntil.d.ts +1 -2
  80. package/dist/support/repeatUntil.js +2 -2
  81. package/dist/support/testStep.js +2 -2
  82. package/dist/utils/ClusterHelper.js +1 -1
  83. package/dist/utils/ExportHelper.d.ts +2 -2
  84. package/dist/utils/ExportHelper.js +14 -10
  85. package/dist/utils/GraphQLHelper.js +21 -17
  86. package/dist/utils/JCRHelper.d.ts +1 -1
  87. package/dist/utils/JCRHelper.js +1 -1
  88. package/dist/utils/JahiaPlatformHelper.js +2 -2
  89. package/dist/utils/Logger.js +6 -6
  90. package/dist/utils/PublicationAndWorkflowHelper.js +3 -3
  91. package/dist/utils/SAMHelper.d.ts +1 -1
  92. package/dist/utils/SAMHelper.js +4 -4
  93. package/dist/utils/SiteHelper.js +2 -2
  94. package/dist/utils/UsersHelper.js +2 -2
  95. package/dist/utils/VanityUrlHelper.js +1 -1
  96. package/dist/utils/index.js +6 -2
  97. package/docs/browser-helper.md +158 -0
  98. package/docs/jfaker.md +450 -0
  99. package/package.json +13 -10
  100. package/src/injections/bash-data.ts +54 -0
  101. package/src/injections/chars-data.ts +22 -0
  102. package/src/injections/htmlentities-data.ts +19 -0
  103. package/src/injections/numbers-data.ts +63 -0
  104. package/src/injections/sql-data.ts +79 -0
  105. package/src/injections/xss-data.ts +737 -0
  106. package/src/page-object/baseComponent.ts +6 -6
  107. package/src/page-object/html/iframe.ts +3 -3
  108. package/src/page-object/material/muiinput.ts +1 -1
  109. package/src/page-object/material/muiradio.ts +1 -1
  110. package/src/page-object/moonstone/accordion.ts +1 -1
  111. package/src/page-object/moonstone/button.ts +1 -1
  112. package/src/page-object/moonstone/collapsible.ts +1 -1
  113. package/src/page-object/moonstone/dropdown.ts +1 -1
  114. package/src/page-object/moonstone/menu.ts +1 -1
  115. package/src/page-object/moonstone/pagination.ts +1 -1
  116. package/src/page-object/moonstone/primaryNav.ts +1 -1
  117. package/src/page-object/moonstone/secondaryNav.ts +1 -1
  118. package/src/page-object/moonstone/table.ts +2 -2
  119. package/src/support/apollo/apollo.ts +74 -11
  120. package/src/support/apollo/links.ts +1 -2
  121. package/src/support/browserHelper.ts +186 -0
  122. package/src/support/index.ts +3 -0
  123. package/src/support/jfaker.ts +245 -0
  124. package/src/support/modSince.ts +222 -0
  125. package/src/support/provisioning/executeGroovy.md +7 -1
  126. package/src/support/provisioning/executeGroovy.ts +46 -2
  127. package/src/support/provisioning/runProvisioningScript.ts +89 -12
  128. package/src/support/registerSupport.ts +29 -0
  129. package/tests/cypress/e2e/jfaker.spec.ts +411 -0
  130. package/tests/cypress/e2e/modSince.spec.ts +306 -0
  131. package/tests/cypress.config.ts +23 -0
  132. package/tests/package.json +41 -0
  133. package/tests/reporter-config.json +13 -0
  134. package/tests/yarn.lock +8578 -0
  135. package/tsconfig.json +3 -0
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ /* eslint-disable no-else-return */
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ /**
5
+ * jfaker - A flexible data generator for Cypress tests, supporting both faker.js generated data and custom injection payloads.
6
+ *
7
+ * This module provides a unified interface to generate either faker data or custom injection payloads based on the method called and global settings.
8
+ * It uses a dynamic Proxy to handle method calls and determine whether to generate faker data or injection data.
9
+ *
10
+ * IMPORTANT:
11
+ * When using the generated strings from jfaker in Cypress commands like `.type()`, make sure to:
12
+ * use `parseSpecialCharSequences: false`, e.g.: `<input>.type(text, {parseSpecialCharSequences: false})`
13
+ * to prevent Cypress from interpreting special characters in the generated strings (e.g., {, }, [, ], etc.) as commands,
14
+ * which is especially important for injection payloads that may contain such characters.
15
+ */
16
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
17
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
18
+ if (ar || !(i in from)) {
19
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
20
+ ar[i] = from[i];
21
+ }
22
+ }
23
+ return to.concat(ar || Array.prototype.slice.call(from));
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.jfaker = void 0;
27
+ var faker_1 = require("@faker-js/faker");
28
+ // Import injection data from corresponding files in injections-ts directory
29
+ var xss_data_1 = require("../injections/xss-data");
30
+ var sql_data_1 = require("../injections/sql-data");
31
+ var bash_data_1 = require("../injections/bash-data");
32
+ var chars_data_1 = require("../injections/chars-data");
33
+ var htmlentities_data_1 = require("../injections/htmlentities-data");
34
+ var numbers_data_1 = require("../injections/numbers-data");
35
+ var injectionData = {
36
+ xss: xss_data_1.xssData,
37
+ sql: sql_data_1.sqlData,
38
+ bash: bash_data_1.bashData,
39
+ chars: chars_data_1.charsData,
40
+ htmlentities: htmlentities_data_1.htmlentitiesData,
41
+ numbers: numbers_data_1.numbersData
42
+ };
43
+ // Environment variable key for storing injection type in Cypress env
44
+ // Can be set either using corresponding FakeData method or as an env var from CI/CD pipeline
45
+ var ENV_INJECTIONS_TYPE = 'JAHIA_CYPRESS_INJECTION_TYPE';
46
+ // Default range for random length of injection payloads; used when length is undefined
47
+ // Random items within the range will be picked and joined into a single string
48
+ var injectionsDefaultLength = { min: 2, max: 5 };
49
+ /**
50
+ * Store FakeData type in Cypress env for persistence across specs
51
+ * @param {string} type FakeData type: 'faker' | 'xss' | 'sql' | 'bash' | 'chars' | 'htmlentities' | 'numbers'
52
+ * @returns void
53
+ */
54
+ function setDataType(type) {
55
+ Cypress.env(ENV_INJECTIONS_TYPE, type);
56
+ }
57
+ /**
58
+ * Retrieve FakeData type from Cypress env (defaults to 'faker' if not set)
59
+ * @returns {string} Type of FakeData to use
60
+ */
61
+ function getDataType() {
62
+ return Cypress.env(ENV_INJECTIONS_TYPE) || 'faker';
63
+ }
64
+ /**
65
+ * Generate injection data based on the specified type and length
66
+ * @param {string} type Injection type to generate (xss, sql, bash, chars, htmlentities, numbers)
67
+ * @param {number} length Length of the generated injection (optional)
68
+ * @returns {string} Generated injection string
69
+ */
70
+ function generateInjection(type, length) {
71
+ var result = [];
72
+ // Type is specified and exists in injectionData, use it to generate data
73
+ var data = injectionData[type];
74
+ if (!data || data.length === 0) {
75
+ throw new Error("[jFaker EXCEPTION] No injection data found for type: ".concat(type, "."));
76
+ }
77
+ if (length === -1) {
78
+ // If length is -1, use all available items from the data array
79
+ result = data;
80
+ }
81
+ else if (length && length > 0) {
82
+ // If length is specified and greater than 0, pick random items until the combined length meets the requirement
83
+ while (result.join('').length < length) {
84
+ var randomIndex = Math.floor(Math.random() * data.length);
85
+ result.push(data[randomIndex]);
86
+ }
87
+ // Trim the combined string to the specified length
88
+ var combined = result.join('');
89
+ result = [combined.substring(0, length)];
90
+ }
91
+ else {
92
+ // If length is not specified, pick a random number of items within the default range
93
+ var itemsCount = Math.floor(Math.random() * injectionsDefaultLength.max) + injectionsDefaultLength.min;
94
+ for (var i = 0; i < itemsCount; i++) {
95
+ var randomIndex = Math.floor(Math.random() * data.length);
96
+ result.push(data[randomIndex]);
97
+ }
98
+ }
99
+ return result.join('');
100
+ }
101
+ /**
102
+ * Generate faker data based on the specified entity and options
103
+ * @param {string} entity Faker entity to generate (e.g., "person.firstName")
104
+ * @param {Record<string, unknown> | string | number | boolean | undefined} options Options to pass to the faker method (optional)
105
+ * @returns {string} Generated faker string
106
+ */
107
+ function generateFake(entity, options) {
108
+ var generator;
109
+ var result = [];
110
+ var parts = entity.split('.');
111
+ var fakerMethod = faker_1.faker;
112
+ for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
113
+ var part = parts_1[_i];
114
+ if (fakerMethod && typeof fakerMethod[part] !== 'undefined') {
115
+ fakerMethod = fakerMethod[part];
116
+ }
117
+ else {
118
+ throw new Error("[jFaker EXCEPTION] Invalid faker method: ".concat(entity));
119
+ }
120
+ }
121
+ if (typeof fakerMethod === 'function') {
122
+ generator = (options && Object.keys(options).length > 0) ? function () { return fakerMethod(options); } : function () { return fakerMethod(); };
123
+ }
124
+ else {
125
+ throw new Error("[jFaker EXCEPTION] ".concat(entity, " is not a function"));
126
+ }
127
+ result.push(generator());
128
+ return result.join('');
129
+ }
130
+ /**
131
+ * Escape string to prevent issues when used in contexts like HTML or JavaScript
132
+ * @param str
133
+ */
134
+ function escape(str) {
135
+ return JSON.stringify(str).slice(1, -1);
136
+ }
137
+ /**
138
+ * Simple DeepApi class to create a dynamic nested Proxy for generating fake data using faker or injection data based on method calls
139
+ */
140
+ var DeepApi = /** @class */ (function () {
141
+ function DeepApi(handler) {
142
+ this.handler = handler;
143
+ return this.createProxy([]);
144
+ }
145
+ DeepApi.prototype.createProxy = function (path) {
146
+ var _this = this;
147
+ return new Proxy(
148
+ // The target is a function, so the proxy itself is callable
149
+ function () { }, {
150
+ // Handle property access - go deeper
151
+ get: function (target, prop) {
152
+ return _this.createProxy(__spreadArray(__spreadArray([], path, true), [String(prop)], false));
153
+ },
154
+ // Handle function call - execute handler
155
+ apply: function (target, thisArg, args) {
156
+ return _this.handler(path.join('.'), args);
157
+ }
158
+ });
159
+ };
160
+ return DeepApi;
161
+ }());
162
+ /**
163
+ * Interface to Fake Data generator (using DeepApi proxy to handle dynamic method calls)
164
+ * @param {Record<string, unknown>} options Options for data generation (length for injections, faker options, safe flag), \
165
+ * e.g.: `{length: 100}` for injections to specify desired length of the generated string, \
166
+ * or `{provider: 'example.com'}` for faker to pass options to the faker method. \
167
+ * For faker data generation, an additional option `safe` can be set to `true` \
168
+ * to force faker generation regardless of global type settings \
169
+ * (useful for specific cases where faker data is needed even when global type is set to injection).
170
+ * @remarks
171
+ * Available injection methods:
172
+ * - `.xss()` - Generate XSS injection payloads
173
+ * - `.sql()` - Generate SQL injection payloads
174
+ * - `.bash()` - Generate Bash injection payloads
175
+ * - `.chars()` - Generate random special characters
176
+ * - `.htmlentities()` - Generate HTML entities
177
+ * - `.numbers()` - Generate random numbers entities and edge cases
178
+ * - or any faker.js method can also be called (e.g., `person.firstName()`, `internet.email()`)
179
+ *
180
+ * @returns {string} Generated data string based on the method called and options provided
181
+ *
182
+ * @see https://fakerjs.dev/api/ for available faker methods and options
183
+ * @example
184
+ * ```typescript
185
+ *
186
+ * // Generate faker data with entity.
187
+ * const name = jfaker.person.firstName();
188
+ *
189
+ * // Entity will always be generated using faker (safe: true)
190
+ * const name = jfaker.person.firstName({safe: true});
191
+ *
192
+ * // Generate faker data with options.
193
+ * const email = jfaker.internet.email({provider: 'example.com'});
194
+ *
195
+ * // Generate injection payloads (random between min and max items joined into a single string)..
196
+ * // Entity will always be generated using 'xss'.
197
+ * const xssName = jfaker.xss();
198
+ *
199
+ * // Generate injection payloads with specific length.
200
+ * // Entity will always be generated using 'xss'.
201
+ * const xssName = jfaker.xss({length: 100});
202
+ *
203
+ * // Use all SQL injections.
204
+ * // Entity will always be generated using 'sql'.
205
+ * const allSql = jfaker.sql({length: -1});
206
+ * ```
207
+ */
208
+ var jfaker = new DeepApi(function (path, args) {
209
+ var _a, _b, _c, _d;
210
+ // Handle non-faker methods first (escape, setFakeDataType, getFakeDataType)
211
+ switch (path) {
212
+ case 'escape':
213
+ return escape(args[0]);
214
+ case 'setDataType':
215
+ return setDataType(args[0]);
216
+ case 'getDataType':
217
+ return getDataType();
218
+ case Object.prototype.hasOwnProperty.call(injectionData, path) ? path : 'default':
219
+ // If the path corresponds to a valid injection type, generate data using that type,
220
+ // or fallback to default case which treats the path as a faker entity.
221
+ // Keep (safe === true) logic in "default" case for a readability.
222
+ return generateInjection(path, (_a = args[0]) === null || _a === void 0 ? void 0 : _a.length);
223
+ default: {
224
+ // For faker data generation, check if the generation should be persistent based on global settings and options passed.
225
+ var safe = ((_b = args[0]) === null || _b === void 0 ? void 0 : _b.safe) === true;
226
+ // Delete the 'safe' property from options to avoid passing it to faker methods
227
+ (_c = args[0]) === null || _c === void 0 ? true : delete _c.safe;
228
+ // Here path represents a faker entity.
229
+ // Check desired data type and 'safe' option to determine whether to generate faker data or injection data.
230
+ // If global type is set to injection (to override faker data) but safe is explicitly set to true in options -
231
+ // generate faker data for this specific call regardless of global settings.
232
+ if (getDataType() === 'faker' || safe) {
233
+ return generateFake(path, args[0]);
234
+ }
235
+ else {
236
+ return generateInjection(getDataType(), (_d = args[0]) === null || _d === void 0 ? void 0 : _d.length);
237
+ }
238
+ }
239
+ }
240
+ });
241
+ exports.jfaker = jfaker;
@@ -1,12 +1,16 @@
1
1
  "use strict";
2
2
  /* eslint-disable brace-style */
3
3
  /* eslint-disable max-statements-per-line */
4
- var __spreadArray = (this && this.__spreadArray) || function (to, from) {
5
- for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
6
- to[j] = from[i];
7
- return to;
4
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
5
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
6
+ if (ar || !(i in from)) {
7
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
8
+ ar[i] = from[i];
9
+ }
10
+ }
11
+ return to.concat(ar || Array.prototype.slice.call(from));
8
12
  };
9
- exports.__esModule = true;
13
+ Object.defineProperty(exports, "__esModule", { value: true });
10
14
  exports.jsErrorsLogger = void 0;
11
15
  /**
12
16
  * Module for monitoring and reporting JavaScript errors and warnings in Cypress tests.
@@ -152,9 +156,9 @@ function collectIssues(win) {
152
156
  .then(function () {
153
157
  // Update the Cypress environment variable with the collected issues
154
158
  if (consoleIssues.length > 0) {
155
- setCollectedIssues(__spreadArray(__spreadArray([], getCollectedIssues()), [
159
+ setCollectedIssues(__spreadArray(__spreadArray([], getCollectedIssues(), true), [
156
160
  { url: win.location.href, test: Cypress.currentTest.title, errors: consoleIssues }
157
- ]));
161
+ ], false));
158
162
  }
159
163
  });
160
164
  }
@@ -174,12 +178,12 @@ function analyzeIssues() {
174
178
  var errorMessage = Object.entries(groupedByTest).map(function (_a) {
175
179
  var test = _a[0], items = _a[1];
176
180
  var urlsAndErrors = items.map(function (item) {
177
- return "URL: " + item.url + "\nISSUES:\n" + item.errors.map(function (e) { return "- " + (e.type === 'warn' ? getEmoji('warn') : getEmoji('error')) + " " + e.msg; }).join('\n');
181
+ return "URL: ".concat(item.url, "\nISSUES:\n").concat(item.errors.map(function (e) { return "- ".concat(e.type === 'warn' ? getEmoji('warn') : getEmoji('error'), " ").concat(e.msg); }).join('\n'));
178
182
  }).join('\n\n');
179
183
  // Return the formatted message for the test;
180
184
  // Intentionally use fixed-width (50 chars) separators for better readability,
181
185
  // when the message might be wrapped
182
- return getEmoji('error') + "\uFE0F TEST: " + test.trim() + " " + getEmoji('error') + "\uFE0F\n" + '-'.repeat(50) + "\n" + urlsAndErrors + "\n" + '='.repeat(50);
186
+ return "".concat(getEmoji('error'), "\uFE0F TEST: ").concat(test.trim(), " ").concat(getEmoji('error'), "\uFE0F\n").concat('-'.repeat(50), "\n").concat(urlsAndErrors, "\n").concat('='.repeat(50));
183
187
  }).join('\n\n');
184
188
  // Reset the collector for the next test run
185
189
  setCollectedIssues([]);
@@ -1,4 +1,3 @@
1
- /// <reference types="cypress" />
2
1
  declare global {
3
2
  namespace Cypress {
4
3
  interface Chainable<Subject> {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-namespace */
3
- exports.__esModule = true;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.loginAndStoreSession = exports.login = void 0;
5
5
  /// <reference types="cypress" />
6
6
  // Disable linter to keep as this for backward compatibility
@@ -11,7 +11,7 @@ var login = function (username, password, config) {
11
11
  if (password === void 0) { password = Cypress.env('SUPER_USER_PASSWORD'); }
12
12
  Cypress.log({
13
13
  name: 'login',
14
- message: "Login with " + username,
14
+ message: "Login with ".concat(username),
15
15
  consoleProps: function () {
16
16
  return {
17
17
  User: username
@@ -1,4 +1,3 @@
1
- /// <reference types="cypress" />
2
1
  declare global {
3
2
  namespace Cypress {
4
3
  interface Chainable<Subject> {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-namespace */
3
- exports.__esModule = true;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.logout = void 0;
5
5
  /// <reference types="cypress" />
6
6
  var logout = function () {
@@ -0,0 +1,52 @@
1
+ /** Cypress environment variable key used to store the current Jahia version. */
2
+ export declare const JAHIA_VERSION_ENV_VAR = "CYPRESS_JAHIA_VERSION";
3
+ declare global {
4
+ namespace Mocha {
5
+ interface TestFunction {
6
+ since(requiredVersion: string, title: string, fn?: Func): Test;
7
+ since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
8
+ }
9
+ interface ExclusiveTestFunction {
10
+ since(requiredVersion: string, title: string, fn?: Func): Test;
11
+ since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
12
+ }
13
+ interface PendingTestFunction {
14
+ since(requiredVersion: string, title: string, fn?: Func): Test;
15
+ since(requiredVersion: string, title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test;
16
+ }
17
+ interface SuiteFunction {
18
+ since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
19
+ }
20
+ interface ExclusiveSuiteFunction {
21
+ since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
22
+ }
23
+ interface PendingSuiteFunction {
24
+ since(requiredVersion: string, title: string, fn: (this: Suite) => void): Suite;
25
+ }
26
+ }
27
+ }
28
+ /**
29
+ * Fetches the Jahia version from the GraphQL API, strips the `-SNAPSHOT` suffix,
30
+ * and caches the result in `Cypress.env(JAHIA_VERSION_ENV_VAR)`.
31
+ */
32
+ export declare const initializeVersionSupport: () => Cypress.Chainable<any>;
33
+ /**
34
+ * Attaches `.since()` to `it`, `it.only`, `it.skip`, `describe`, `describe.only`,
35
+ * and `describe.skip`. Safe to call multiple times — subsequent calls are no-ops.
36
+ */
37
+ export declare const registerVersionSupport: () => void;
38
+ /**
39
+ * Enables version-gated testing for the Cypress suite.
40
+ * Registers `it.since`, `describe.since` (and their `.only`/`.skip` variants),
41
+ * then fetches the running Jahia version in a root `before()` hook.
42
+ *
43
+ * @example
44
+ * it.since('8.2.0', 'works on 8.2+', () => { ... });
45
+ * describe.since('8.2.0', 'suite for 8.2+', () => { ... });
46
+ */
47
+ declare function enable(): void;
48
+ /** Public API for Jahia version-gated testing. */
49
+ export declare const modSince: {
50
+ enable: typeof enable;
51
+ };
52
+ export {};
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.modSince = exports.registerVersionSupport = exports.initializeVersionSupport = exports.JAHIA_VERSION_ENV_VAR = void 0;
4
+ var compare_versions_1 = require("compare-versions");
5
+ // Intentionally keep explicit path to avoid edge case errors in runtime
6
+ var JahiaPlatformHelper_1 = require("../utils/JahiaPlatformHelper");
7
+ /** Cypress environment variable key used to store the current Jahia version. */
8
+ exports.JAHIA_VERSION_ENV_VAR = 'CYPRESS_JAHIA_VERSION';
9
+ // ─── Internal helpers ────────────────────────────────────────────────────────
10
+ /**
11
+ * Returns `true` when `current` satisfies `>= required`.
12
+ * Treats missing, empty, or unparseable versions as unsupported.
13
+ * @param current - The running Jahia version read from `Cypress.env`.
14
+ * @param required - Minimum version the test or suite needs.
15
+ */
16
+ var isSupported = function (current, required) {
17
+ if (!(current === null || current === void 0 ? void 0 : current.trim())) {
18
+ return false;
19
+ }
20
+ try {
21
+ return (0, compare_versions_1.compare)(String(current), required, '>=');
22
+ }
23
+ catch (_a) {
24
+ return false;
25
+ }
26
+ };
27
+ /**
28
+ * Validates `since(...)` arguments and throws a descriptive error on misuse.
29
+ * Detects the common mistake of swapping `requiredVersion` and `title`.
30
+ * @param version - Version string passed as the first argument.
31
+ * @param title - Title string passed as the second argument.
32
+ * @param scope - Label used in the error message (e.g. `"it.since"`).
33
+ */
34
+ var assertArgs = function (version, title, scope) {
35
+ if (!(0, compare_versions_1.validate)(version)) {
36
+ var hint = (0, compare_versions_1.validate)(title) ? ' (arguments appear swapped)' : '';
37
+ throw new Error("[".concat(scope, "] Invalid version: \"").concat(version, "\"").concat(hint, "."));
38
+ }
39
+ };
40
+ /**
41
+ * Builds a human-readable message explaining why a test or suite was skipped.
42
+ * @param scope - Label for the helper (e.g. `"it.since"` or `"describe.since"`).
43
+ * @param title - Original test or suite title.
44
+ * @param required - Minimum version the test or suite needs.
45
+ * @param current - The running Jahia version; `undefined` when not yet fetched.
46
+ */
47
+ var skipReason = function (scope, title, required, current) {
48
+ return current ?
49
+ "[".concat(scope, "] Skipping \"").concat(title, "\" \u2014 ").concat(exports.JAHIA_VERSION_ENV_VAR, "=\"").concat(current, "\" < required ").concat(required, ".") :
50
+ "[".concat(scope, "] Skipping \"").concat(title, "\" \u2014 ").concat(exports.JAHIA_VERSION_ENV_VAR, " is not set. Required: ").concat(required, ".");
51
+ };
52
+ // ─── Public API ───────────────────────────────────────────────────────────────
53
+ /**
54
+ * Fetches the Jahia version from the GraphQL API, strips the `-SNAPSHOT` suffix,
55
+ * and caches the result in `Cypress.env(JAHIA_VERSION_ENV_VAR)`.
56
+ */
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ var initializeVersionSupport = function () {
59
+ return (0, JahiaPlatformHelper_1.getJahiaVersion)().then(function (jahiaVersion) {
60
+ var version = jahiaVersion.release.replace('-SNAPSHOT', '');
61
+ Cypress.env(exports.JAHIA_VERSION_ENV_VAR, version);
62
+ return version;
63
+ });
64
+ };
65
+ exports.initializeVersionSupport = initializeVersionSupport;
66
+ /**
67
+ * Attaches `.since()` to `it`, `it.only`, `it.skip`, `describe`, `describe.only`,
68
+ * and `describe.skip`. Safe to call multiple times — subsequent calls are no-ops.
69
+ */
70
+ var registerVersionSupport = function () {
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ var mochaIt = globalThis.it;
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ var mochaDescribe = globalThis.describe;
75
+ if (!mochaIt) {
76
+ throw new Error('Unable to register version support because Mocha `it` is not available.');
77
+ }
78
+ if (!mochaDescribe) {
79
+ throw new Error('Unable to register version support because Mocha `describe` is not available.');
80
+ }
81
+ var _loop_1 = function (target) {
82
+ if (typeof target.since === 'function') {
83
+ return "continue";
84
+ }
85
+ var isSkip = target === mochaIt.skip;
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ target.since = function (version, title, configOrFn, maybeFn) {
88
+ assertArgs(version, title, 'it.since');
89
+ if (isSkip) {
90
+ // It.skip.since: always skip unconditionally, preserve the title
91
+ return typeof configOrFn === 'function' || configOrFn === undefined ?
92
+ target(title, configOrFn) :
93
+ target(title, configOrFn, maybeFn);
94
+ }
95
+ var userFn = typeof configOrFn === 'function' ? configOrFn : maybeFn;
96
+ var wrappedFn = function () {
97
+ var current = Cypress.env(exports.JAHIA_VERSION_ENV_VAR);
98
+ if (!isSupported(current, version)) {
99
+ console.warn(skipReason('it.since', title, version, current));
100
+ this.skip();
101
+ }
102
+ else if (typeof userFn === 'function') {
103
+ return userFn.call(this);
104
+ }
105
+ };
106
+ return typeof configOrFn === 'object' && configOrFn !== null ?
107
+ target(title, configOrFn, wrappedFn) :
108
+ target(title, wrappedFn);
109
+ };
110
+ };
111
+ // Attach .since() to it / it.only / it.skip
112
+ for (var _i = 0, _a = [mochaIt, mochaIt.only, mochaIt.skip]; _i < _a.length; _i++) {
113
+ var target = _a[_i];
114
+ _loop_1(target);
115
+ }
116
+ var _loop_2 = function (target) {
117
+ if (typeof target.since === 'function') {
118
+ return "continue";
119
+ }
120
+ var isSkip = target === mochaDescribe.skip;
121
+ target.since = function (version, title, fn) {
122
+ assertArgs(version, title, 'describe.since');
123
+ if (isSkip) {
124
+ // Describe.skip.since: always skip unconditionally, preserve the title
125
+ return target(title, fn);
126
+ }
127
+ return target(title, function () {
128
+ // Suite-level runtime check runs after the global before() has fetched the version
129
+ before(function () {
130
+ var current = Cypress.env(exports.JAHIA_VERSION_ENV_VAR);
131
+ if (!isSupported(current, version)) {
132
+ console.warn(skipReason('describe.since', title, version, current));
133
+ this.skip();
134
+ }
135
+ });
136
+ fn.call(this);
137
+ });
138
+ };
139
+ };
140
+ // Attach .since() to describe / describe.only / describe.skip
141
+ for (var _b = 0, _c = [mochaDescribe, mochaDescribe.only, mochaDescribe.skip]; _b < _c.length; _b++) {
142
+ var target = _c[_b];
143
+ _loop_2(target);
144
+ }
145
+ // Compatibility shim: redirect accidental it.skip(version, title, fn) → it.skip.since(...)
146
+ var origItSkip = mochaIt.skip;
147
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
148
+ mochaIt.skip = Object.assign(function (title, configOrTitle, maybeFn) {
149
+ if ((0, compare_versions_1.validate)(title) && typeof configOrTitle === 'string' && typeof maybeFn === 'function') {
150
+ return origItSkip.since(title, configOrTitle, maybeFn);
151
+ }
152
+ return typeof configOrTitle === 'function' || configOrTitle === undefined ?
153
+ origItSkip(title, configOrTitle) :
154
+ origItSkip(title, configOrTitle, maybeFn);
155
+ }, { since: origItSkip.since });
156
+ var origDescribeSkip = mochaDescribe.skip;
157
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
+ mochaDescribe.skip = Object.assign(function (title, fnOrTitle, maybeFn) {
159
+ if ((0, compare_versions_1.validate)(title) && typeof fnOrTitle === 'string' && typeof maybeFn === 'function') {
160
+ return origDescribeSkip.since(title, fnOrTitle, maybeFn);
161
+ }
162
+ return origDescribeSkip(title, fnOrTitle);
163
+ }, { since: origDescribeSkip.since });
164
+ };
165
+ exports.registerVersionSupport = registerVersionSupport;
166
+ /**
167
+ * Enables version-gated testing for the Cypress suite.
168
+ * Registers `it.since`, `describe.since` (and their `.only`/`.skip` variants),
169
+ * then fetches the running Jahia version in a root `before()` hook.
170
+ *
171
+ * @example
172
+ * it.since('8.2.0', 'works on 8.2+', () => { ... });
173
+ * describe.since('8.2.0', 'suite for 8.2+', () => { ... });
174
+ */
175
+ function enable() {
176
+ (0, exports.registerVersionSupport)();
177
+ before(function () { return (0, exports.initializeVersionSupport)(); });
178
+ }
179
+ /** Public API for Jahia version-gated testing. */
180
+ exports.modSince = { enable: enable };
@@ -7,7 +7,7 @@ declare global {
7
7
  }
8
8
  }
9
9
  }
10
- declare type JahiaServer = {
10
+ type JahiaServer = {
11
11
  url: string;
12
12
  username: string;
13
13
  password: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-namespace */
3
- exports.__esModule = true;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.executeGroovy = void 0;
5
5
  /// <reference types="cypress" />
6
6
  var serverDefaults = {
@@ -10,6 +10,36 @@ var serverDefaults = {
10
10
  };
11
11
  var executeGroovy = function (scriptFile, replacements, jahiaServer) {
12
12
  if (jahiaServer === void 0) { jahiaServer = serverDefaults; }
13
+ var result;
14
+ var duration;
15
+ var scriptContent;
16
+ var startTime = Date.now();
17
+ var replacementsLabel = replacements && Object.keys(replacements).length > 0 ?
18
+ " \u2014 ".concat(JSON.stringify(replacements)) :
19
+ '';
20
+ var logger = Cypress.log({
21
+ autoEnd: false,
22
+ name: 'executeGroovy',
23
+ displayName: 'groovy',
24
+ message: "".concat(scriptFile).concat(replacementsLabel),
25
+ consoleProps: function () { return ({
26
+ Script: scriptFile,
27
+ 'Script Content': scriptContent !== null && scriptContent !== void 0 ? scriptContent : '(loading...)',
28
+ Replacements: replacements !== null && replacements !== void 0 ? replacements : {},
29
+ Server: jahiaServer.url,
30
+ Duration: duration === undefined ? 'pending' : "".concat(duration, "ms"),
31
+ Result: result
32
+ }); }
33
+ });
34
+ cy.fixture(scriptFile, 'utf-8').then(function (content) {
35
+ var processed = content;
36
+ if (replacements) {
37
+ Object.keys(replacements).forEach(function (k) {
38
+ processed = processed.replaceAll(k, replacements[k]);
39
+ });
40
+ }
41
+ scriptContent = processed;
42
+ });
13
43
  cy.runProvisioningScript({
14
44
  script: {
15
45
  fileContent: '- executeScript: "' + scriptFile + '"',
@@ -21,7 +51,16 @@ var executeGroovy = function (scriptFile, replacements, jahiaServer) {
21
51
  type: 'text/plain',
22
52
  encoding: 'utf-8'
23
53
  }],
24
- jahiaServer: jahiaServer
25
- }).then(function (r) { return r[0]; });
54
+ jahiaServer: jahiaServer,
55
+ options: { log: false }
56
+ }).then(function (r) {
57
+ result = r === null || r === void 0 ? void 0 : r[0];
58
+ duration = Date.now() - startTime;
59
+ var hasFailed = typeof result === 'string' && result.includes('.failed');
60
+ var prefix = hasFailed ? '❌ ' : '✅ ';
61
+ logger.set('message', "".concat(prefix).concat(scriptFile).concat(replacementsLabel));
62
+ logger === null || logger === void 0 ? void 0 : logger.end();
63
+ return result;
64
+ });
26
65
  };
27
66
  exports.executeGroovy = executeGroovy;
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -9,7 +13,7 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
9
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
15
  };
12
- exports.__esModule = true;
16
+ Object.defineProperty(exports, "__esModule", { value: true });
13
17
  __exportStar(require("./executeGroovy"), exports);
14
18
  __exportStar(require("./runProvisioningScript"), exports);
15
19
  __exportStar(require("./installModule"), exports);
@@ -1,4 +1,3 @@
1
- /// <reference types="cypress" />
2
1
  declare global {
3
2
  namespace Cypress {
4
3
  interface Chainable<Subject> {