@jahia/cypress 8.1.0 → 8.2.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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @jahia/cypress Changelog
2
2
 
3
+ ## 8.2.0
4
+
5
+ * Add `context.tag()` function for adding tags (user-defined labels) that can be attached to test suites and individual tests to provide metadata about test characteristics, scope, and purpose (#221)
6
+
7
+ ## 8.1.1
8
+
9
+ * Use default Jahia ref. while fetching version; fail safe when version can't be fetched.
10
+
3
11
  ## 8.1.0
4
12
 
5
13
  ### New Features
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Tag a test suite or individual test.
3
+ *
4
+ * Tags are user-defined labels that provide metadata about tests. They are collected during
5
+ * test execution and synchronized to TestRail test cases by jahia-reporter, enabling filtering,
6
+ * categorization, and custom dashboard reporting.
7
+ *
8
+ * - Call inside `describe()` to tag every test in the suite (tags are inherited by all nested tests).
9
+ * - Call inside `it()` to tag only that specific test.
10
+ *
11
+ * Tags are:
12
+ * - Collected and stored in the mochawesome report under each test's `context` field
13
+ * - Automatically synced to TestRail by jahia-reporter for dashboard and filtering
14
+ * - Deduplicated (each unique tag appears once per test)
15
+ * - Inherited by nested describe blocks
16
+ *
17
+ * @param {string[]} tags - array of tags to be added
18
+ * @return {void}
19
+ *
20
+ * @example
21
+ * import {context} from '@jahia/cypress';
22
+ * describe('My suite', () => {
23
+ * context.tag('smoke', 'regression', 'p0');
24
+ *
25
+ * it('my test', () => {
26
+ * context.tag('critical');
27
+ * // effective tags: ['smoke', 'regression', 'p0', 'critical']
28
+ * });
29
+ * });
30
+ *
31
+ * @see docs/context-reporter.md for details
32
+ */
33
+ declare function tag(...tags: string[]): void;
34
+ /** Public export */
35
+ export declare const context: {
36
+ tag: typeof tag;
37
+ };
38
+ export {};
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.context = void 0;
16
+ exports.collect = collect;
17
+ /* eslint-disable @typescript-eslint/no-explicit-any */
18
+ var addContext_1 = __importDefault(require("mochawesome/addContext"));
19
+ /**
20
+ * Tag a test suite or individual test.
21
+ *
22
+ * Tags are user-defined labels that provide metadata about tests. They are collected during
23
+ * test execution and synchronized to TestRail test cases by jahia-reporter, enabling filtering,
24
+ * categorization, and custom dashboard reporting.
25
+ *
26
+ * - Call inside `describe()` to tag every test in the suite (tags are inherited by all nested tests).
27
+ * - Call inside `it()` to tag only that specific test.
28
+ *
29
+ * Tags are:
30
+ * - Collected and stored in the mochawesome report under each test's `context` field
31
+ * - Automatically synced to TestRail by jahia-reporter for dashboard and filtering
32
+ * - Deduplicated (each unique tag appears once per test)
33
+ * - Inherited by nested describe blocks
34
+ *
35
+ * @param {string[]} tags - array of tags to be added
36
+ * @return {void}
37
+ *
38
+ * @example
39
+ * import {context} from '@jahia/cypress';
40
+ * describe('My suite', () => {
41
+ * context.tag('smoke', 'regression', 'p0');
42
+ *
43
+ * it('my test', () => {
44
+ * context.tag('critical');
45
+ * // effective tags: ['smoke', 'regression', 'p0', 'critical']
46
+ * });
47
+ * });
48
+ *
49
+ * @see docs/context-reporter.md for details
50
+ */
51
+ function tag() {
52
+ var _a;
53
+ var tags = [];
54
+ for (var _i = 0; _i < arguments.length; _i++) {
55
+ tags[_i] = arguments[_i];
56
+ }
57
+ if (Cypress.currentTest) {
58
+ // Inside it() — Cypress is running a test, attach tags directly to the Mocha runnable
59
+ var runnable = cy.state('runnable');
60
+ runnable._tags = __spreadArray(__spreadArray([], ((_a = runnable._tags) !== null && _a !== void 0 ? _a : []), true), tags, true);
61
+ }
62
+ else {
63
+ // Inside describe() — collection phase, schedule a before() hook to tag the suite
64
+ before(function () {
65
+ var _a, _b;
66
+ var suite = (_a = this.currentTest) === null || _a === void 0 ? void 0 : _a.parent;
67
+ if (suite) {
68
+ var taggedSuite = suite;
69
+ taggedSuite._tags = __spreadArray(__spreadArray([], ((_b = taggedSuite._tags) !== null && _b !== void 0 ? _b : []), true), tags, true);
70
+ }
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * Internal function to collect all tags upon 'test:after:run' event and add them to the mochawesome context.
76
+ *
77
+ * Walks up the suite chain to collect inherited tags and combines them with test-specific tags.
78
+ * The collected tags are added to the test context in the mochawesome report, where jahia-reporter
79
+ * can extract them and sync to the corresponding TestRail test case.
80
+ *
81
+ * @param test
82
+ * @param runnable
83
+ * @internal to be used in registerSupport only
84
+ */
85
+ function collect(test, runnable) {
86
+ var _a, _b;
87
+ var taggedRunnable = runnable;
88
+ // Add video context
89
+ // addContext({test}, {title: 'video', value: `videos/${Cypress.spec.relative.replace('/.cy.*', '').replace('cypress/e2e/', '')}.mp4`});
90
+ // Walk up the suite chain (outermost first) to collect inherited suite tags
91
+ var suiteTags = [];
92
+ var parent = taggedRunnable.parent;
93
+ while (parent) {
94
+ if ((_a = parent._tags) === null || _a === void 0 ? void 0 : _a.length) {
95
+ suiteTags.unshift.apply(suiteTags, parent._tags);
96
+ }
97
+ parent = parent.parent;
98
+ }
99
+ // Collect all unique tags (suite + test) and add to context
100
+ var allTags = Array.from(new Set(__spreadArray(__spreadArray([], suiteTags, true), ((_b = taggedRunnable._tags) !== null && _b !== void 0 ? _b : []), true)));
101
+ if (allTags.length > 0) {
102
+ (0, addContext_1.default)({ test: test }, { title: 'tags', value: allTags });
103
+ }
104
+ // Add screenshot context if test failed
105
+ // if (test.state === 'failed') {
106
+ // addContext({test}, {title: 'screenshot', value: `screenshots/${Cypress.spec.relative.replace('cypress/e2e/', '')}/${runnable.parent.title} -- ${test.title} (failed).png`});
107
+ // }
108
+ }
109
+ /** Public export */
110
+ exports.context = { tag: tag };
@@ -8,3 +8,4 @@ export * from './jsErrorsLogger';
8
8
  export * from './jfaker';
9
9
  export * from './browserHelper';
10
10
  export * from './modSince';
11
+ export * from './contextReporter';
@@ -24,3 +24,4 @@ __exportStar(require("./jsErrorsLogger"), exports);
24
24
  __exportStar(require("./jfaker"), exports);
25
25
  __exportStar(require("./browserHelper"), exports);
26
26
  __exportStar(require("./modSince"), exports);
27
+ __exportStar(require("./contextReporter"), exports);
@@ -56,8 +56,13 @@ var skipReason = function (scope, title, required, current) {
56
56
  */
57
57
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
58
  var initializeVersionSupport = function () {
59
+ var cachedVersion = Cypress.env(exports.JAHIA_VERSION_ENV_VAR);
60
+ if (typeof cachedVersion === 'string' && cachedVersion.trim() !== '') {
61
+ return cy.wrap(cachedVersion, { log: false });
62
+ }
59
63
  return (0, JahiaPlatformHelper_1.getJahiaVersion)().then(function (jahiaVersion) {
60
- var version = jahiaVersion.release.replace('-SNAPSHOT', '');
64
+ var _a;
65
+ var version = ((_a = jahiaVersion === null || jahiaVersion === void 0 ? void 0 : jahiaVersion.release) === null || _a === void 0 ? void 0 : _a.replace('-SNAPSHOT', '')) || '0.0.0.1';
61
66
  Cypress.env(exports.JAHIA_VERSION_ENV_VAR, version);
62
67
  return version;
63
68
  });
@@ -21,6 +21,7 @@ var repeatUntil_1 = require("./repeatUntil");
21
21
  var testStep_1 = require("./testStep");
22
22
  var jfaker_1 = require("./jfaker");
23
23
  var modSince_1 = require("./modSince");
24
+ var contextReporter_1 = require("./contextReporter");
24
25
  var registerSupport = function () {
25
26
  Cypress.Commands.add('apolloClient', apollo_1.apolloClient);
26
27
  Cypress.Commands.add('apollo', { prevSubject: 'optional' }, apollo_1.apollo);
@@ -56,5 +57,11 @@ var registerSupport = function () {
56
57
  var newOptions = __assign({ parseSpecialCharSequences: parseSpecialCharSequences }, options);
57
58
  return originalFn(element, text, newOptions);
58
59
  });
60
+ /**
61
+ * Listen to the 'test:after:run' event to collect tags and other context information after each test execution.
62
+ */
63
+ Cypress.on('test:after:run', function (test, runnable) {
64
+ (0, contextReporter_1.collect)(test, runnable);
65
+ });
59
66
  };
60
67
  exports.registerSupport = registerSupport;
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Fetches the Jahia version using a GraphQL query.
3
+ * @returns Cypress.Chainable that resolves to the Jahia version record (e.g., release: "8.0.0", ...).
4
+ * @note In rare cases tests might override baseUrl (e.g. when Jahia is configured with custom context path,
5
+ * but spec want to use just a host, without the context path), e.g.:
6
+ * it('Crawl pages', {baseUrl: serverURL.origin}, () => { ... })
7
+ * In such case(s) this call will fail because the GraphQL endpoint will not be found at the root of the host.
8
+ * To prevent such failure, we ensure GraphQL client uses full Jahia url as configured in env variable.
9
+ */
1
10
  export declare const getJahiaVersion: () => Cypress.Chainable;
2
11
  export declare const getStartedModulesVersion: () => Cypress.Chainable;
3
12
  export declare const getStartedModuleVersion: (moduleId: string) => Cypress.Chainable;
@@ -1,13 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getStartedModuleVersion = exports.getStartedModulesVersion = exports.getJahiaVersion = void 0;
4
+ /**
5
+ * Fetches the Jahia version using a GraphQL query.
6
+ * @returns Cypress.Chainable that resolves to the Jahia version record (e.g., release: "8.0.0", ...).
7
+ * @note In rare cases tests might override baseUrl (e.g. when Jahia is configured with custom context path,
8
+ * but spec want to use just a host, without the context path), e.g.:
9
+ * it('Crawl pages', {baseUrl: serverURL.origin}, () => { ... })
10
+ * In such case(s) this call will fail because the GraphQL endpoint will not be found at the root of the host.
11
+ * To prevent such failure, we ensure GraphQL client uses full Jahia url as configured in env variable.
12
+ */
4
13
  var getJahiaVersion = function () {
5
- return cy.apollo({
6
- fetchPolicy: 'no-cache',
7
- queryFile: 'graphql/jcr/query/getJahiaVersion.graphql'
8
- }).then(function (result) {
9
- var _a;
10
- return (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.admin.jahia.version;
14
+ return cy.apolloClient({ url: Cypress.env('JAHIA_URL') || Cypress.config().baseUrl }).then(function () {
15
+ return cy.apollo({
16
+ fetchPolicy: 'no-cache',
17
+ queryFile: 'graphql/jcr/query/getJahiaVersion.graphql'
18
+ }).then(function (result) {
19
+ var _a;
20
+ return (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.admin.jahia.version;
21
+ });
11
22
  });
12
23
  };
13
24
  exports.getJahiaVersion = getJahiaVersion;
@@ -0,0 +1,104 @@
1
+ # Context Reporter: Test Tags and Integration with TestRail
2
+
3
+ ## Overview
4
+
5
+ Test tags are user-defined labels that can be attached to test suites and individual tests to provide metadata about test characteristics, scope, and purpose. Tags are collected during test execution and included in the mochawesome test report.
6
+
7
+ ## Integration with TestRail and jahia-reporter
8
+
9
+ Tags defined in Cypress tests are **automatically synchronized to TestRail test cases** by the `jahia-reporter` tool during the test reporting phase. This enables:
10
+
11
+ - **Test categorization** in TestRail for better organization
12
+ - **Dashboard filtering** based on test characteristics
13
+ - **Reporting dashboards** that slice data by tag combinations (e.g., smoke tests, regression, performance, critical path)
14
+ - **Traceability** linking test runs to business requirements or feature areas
15
+
16
+ ## Usage
17
+
18
+ ### Basic Syntax
19
+
20
+ Use the `tag()` function to attach one or more tags:
21
+
22
+ ```typescript
23
+ import {context} from '@jahia/cypress';
24
+
25
+ describe('Authentication', () => {
26
+ context.tag('smoke', 'critical');
27
+
28
+ it('should login successfully', () => {
29
+ context.tag('p1'); // Add P1 severity
30
+ cy.login();
31
+ cy.url().should('include', '/home');
32
+ });
33
+
34
+ it('should logout successfully', () => {
35
+ cy.logout();
36
+ });
37
+ });
38
+ ```
39
+
40
+ ### Where to Call
41
+
42
+ - **In `describe()`**: Tags apply to **all nested tests** in the suite (inherited by child suites and tests)
43
+ - **In `it()`**: Tags apply to **only that specific test**
44
+ - **Both**: Combine suite-level and test-level tags (both are collected)
45
+
46
+ ### Example: Multi-Level Tagging
47
+
48
+ ```typescript
49
+ import {context} from '@jahia/cypress';
50
+
51
+ describe('Content Management', () => {
52
+ context.tag('regression', 'content'); // Suite-level tags
53
+
54
+ describe('Publishing Workflow', () => {
55
+ context.tag('critical'); // Additional suite-level tag
56
+
57
+ it('should publish page', () => {
58
+ context.tag('p0', 'smoke'); // Test-level tags
59
+ // effective tags: ['regression', 'content', 'critical', 'p0', 'smoke']
60
+ });
61
+
62
+ it('should unpublish page', () => {
63
+ // effective tags: ['regression', 'content', 'critical']
64
+ });
65
+ });
66
+ });
67
+ ```
68
+
69
+ ## Implementation Details
70
+ - Tags are collected during test execution via Mocha hooks and then added to the test's `context`.
71
+ - Suite tags are inherited by nested describe blocks and tests.
72
+ - All unique tags are deduplicated.
73
+
74
+ Tags are stored as an object (`{title: <title>, value: <value>}`) in order to be properly parsed by mocha html-reporter.
75
+ Example:
76
+ ```json
77
+ {title: 'tags', value: ['tag1', 'tag2', 'tag3']}
78
+ ```
79
+
80
+ Finally, the `context` field in Cypress report will contain a stringified JSON array of tags meta-info along with other context information added by the user.
81
+
82
+ Example of `context` field in the report (note - array contains both tags meta-info and user-added context info like video path; array is stringified by `mochawesome` reporter):
83
+ ```json
84
+ "context": "[\n {\n \"title\": \"tags\",\n \"value\": [\n \"graphql-api-upa\",\n \"upa\",\n \"custom-factor\",\n \"P1\",\n \"authentication\"\n ]\n },\n \"videos/graphQL.mfa.customFactor.cy.ts.mp4\"\n]",
85
+ ```
86
+ This `context` field will be parsed by `jahia-reporter` afterward to extract the tags and sync them to `TestRail`. If the `context` field doesn't contain tags in expected format, it will be ignored by `jahia-reporter` and labels in `TestRail` won't be updated.
87
+
88
+
89
+ ## Best Practices
90
+
91
+ 1. **Use consistent tag names** across your test suite
92
+ 2. **Keep tag values simple** (lowercase, no spaces, use hyphens for multi-word tags)
93
+ 3. **Avoid overtagging** — use a reasonable number of tags (3-5 per test)
94
+ 4. **Combine categories** — mix priority, type, and feature tags for flexibility
95
+ 5. **Use suite-level tags** for common characteristics (saves repetition)
96
+ 6. **Add test-level tags** for exceptions or special cases
97
+
98
+ ## Troubleshooting
99
+
100
+ ### Tags not appearing in TestRail
101
+ - Ensure `context.tag()` is called at the right scope (in `describe()` or `it()`)
102
+ - Check that jahia-reporter is configured to sync tags to TestRail
103
+ - Verify the test report is being generated and contains `context` attribute with tags
104
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jahia/cypress",
3
- "version": "8.1.0",
3
+ "version": "8.2.0",
4
4
  "scripts": {
5
5
  "build": "tsc",
6
6
  "lint": "eslint src -c .eslintrc.json --ext .ts --max-warnings=0"
@@ -31,6 +31,7 @@
31
31
  "eslint-plugin-jest": "^29.15.0",
32
32
  "eslint-plugin-react": "^7.32.2",
33
33
  "eslint-plugin-react-hooks": "^4.6.0",
34
+ "mochawesome": "^6.3.1",
34
35
  "typescript": "^5.9.3"
35
36
  },
36
37
  "dependencies": {
@@ -0,0 +1,96 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import addContext from 'mochawesome/addContext';
3
+
4
+ type TaggedRunnable = Mocha.Runnable & {_tags?: string[]};
5
+ type TaggedSuite = Mocha.Suite & {_tags?: string[]};
6
+
7
+ /**
8
+ * Tag a test suite or individual test.
9
+ *
10
+ * Tags are user-defined labels that provide metadata about tests. They are collected during
11
+ * test execution and synchronized to TestRail test cases by jahia-reporter, enabling filtering,
12
+ * categorization, and custom dashboard reporting.
13
+ *
14
+ * - Call inside `describe()` to tag every test in the suite (tags are inherited by all nested tests).
15
+ * - Call inside `it()` to tag only that specific test.
16
+ *
17
+ * Tags are:
18
+ * - Collected and stored in the mochawesome report under each test's `context` field
19
+ * - Automatically synced to TestRail by jahia-reporter for dashboard and filtering
20
+ * - Deduplicated (each unique tag appears once per test)
21
+ * - Inherited by nested describe blocks
22
+ *
23
+ * @param {string[]} tags - array of tags to be added
24
+ * @return {void}
25
+ *
26
+ * @example
27
+ * import {context} from '@jahia/cypress';
28
+ * describe('My suite', () => {
29
+ * context.tag('smoke', 'regression', 'p0');
30
+ *
31
+ * it('my test', () => {
32
+ * context.tag('critical');
33
+ * // effective tags: ['smoke', 'regression', 'p0', 'critical']
34
+ * });
35
+ * });
36
+ *
37
+ * @see docs/context-reporter.md for details
38
+ */
39
+ function tag(...tags: string[]): void {
40
+ if (Cypress.currentTest) {
41
+ // Inside it() — Cypress is running a test, attach tags directly to the Mocha runnable
42
+ const runnable = (cy as any).state('runnable') as TaggedRunnable;
43
+ runnable._tags = [...(runnable._tags ?? []), ...tags];
44
+ } else {
45
+ // Inside describe() — collection phase, schedule a before() hook to tag the suite
46
+ before(function () {
47
+ const suite = this.currentTest?.parent;
48
+ if (suite) {
49
+ const taggedSuite = suite as TaggedSuite;
50
+ taggedSuite._tags = [...(taggedSuite._tags ?? []), ...tags];
51
+ }
52
+ });
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Internal function to collect all tags upon 'test:after:run' event and add them to the mochawesome context.
58
+ *
59
+ * Walks up the suite chain to collect inherited tags and combines them with test-specific tags.
60
+ * The collected tags are added to the test context in the mochawesome report, where jahia-reporter
61
+ * can extract them and sync to the corresponding TestRail test case.
62
+ *
63
+ * @param test
64
+ * @param runnable
65
+ * @internal to be used in registerSupport only
66
+ */
67
+ export function collect(test: any, runnable: any): void {
68
+ const taggedRunnable = runnable as TaggedRunnable;
69
+ // Add video context
70
+ // addContext({test}, {title: 'video', value: `videos/${Cypress.spec.relative.replace('/.cy.*', '').replace('cypress/e2e/', '')}.mp4`});
71
+
72
+ // Walk up the suite chain (outermost first) to collect inherited suite tags
73
+ const suiteTags: string[] = [];
74
+ let parent = taggedRunnable.parent as TaggedSuite | undefined;
75
+ while (parent) {
76
+ if (parent._tags?.length) {
77
+ suiteTags.unshift(...parent._tags);
78
+ }
79
+
80
+ parent = parent.parent as TaggedSuite | undefined;
81
+ }
82
+
83
+ // Collect all unique tags (suite + test) and add to context
84
+ const allTags = Array.from(new Set([...suiteTags, ...(taggedRunnable._tags ?? [])]));
85
+ if (allTags.length > 0) {
86
+ addContext({test}, {title: 'tags', value: allTags});
87
+ }
88
+
89
+ // Add screenshot context if test failed
90
+ // if (test.state === 'failed') {
91
+ // addContext({test}, {title: 'screenshot', value: `screenshots/${Cypress.spec.relative.replace('cypress/e2e/', '')}/${runnable.parent.title} -- ${test.title} (failed).png`});
92
+ // }
93
+ }
94
+
95
+ /** Public export */
96
+ export const context = {tag};
@@ -8,3 +8,4 @@ export * from './jsErrorsLogger';
8
8
  export * from './jfaker';
9
9
  export * from './browserHelper';
10
10
  export * from './modSince';
11
+ export * from './contextReporter';
@@ -90,12 +90,19 @@ const skipReason = (scope: string, title: string, required: string, current?: st
90
90
  * and caches the result in `Cypress.env(JAHIA_VERSION_ENV_VAR)`.
91
91
  */
92
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', '');
93
+ export const initializeVersionSupport = (): Cypress.Chainable<any> => {
94
+ const cachedVersion = Cypress.env(JAHIA_VERSION_ENV_VAR);
95
+
96
+ if (typeof cachedVersion === 'string' && cachedVersion.trim() !== '') {
97
+ return cy.wrap(cachedVersion, {log: false});
98
+ }
99
+
100
+ return getJahiaVersion().then(jahiaVersion => {
101
+ const version = jahiaVersion?.release?.replace('-SNAPSHOT', '') || '0.0.0.1';
96
102
  Cypress.env(JAHIA_VERSION_ENV_VAR, version);
97
103
  return version;
98
104
  });
105
+ };
99
106
 
100
107
  /**
101
108
  * Attaches `.since()` to `it`, `it.only`, `it.skip`, `describe`, `describe.only`,
@@ -7,6 +7,7 @@ import {repeatUntil} from './repeatUntil';
7
7
  import {step} from './testStep';
8
8
  import {jfaker} from './jfaker';
9
9
  import {modSince} from './modSince';
10
+ import {collect as contextCollector} from './contextReporter';
10
11
 
11
12
  export const registerSupport = (): void => {
12
13
  Cypress.Commands.add('apolloClient', apolloClient);
@@ -53,4 +54,11 @@ export const registerSupport = (): void => {
53
54
  return originalFn(element, text, newOptions);
54
55
  }
55
56
  );
57
+
58
+ /**
59
+ * Listen to the 'test:after:run' event to collect tags and other context information after each test execution.
60
+ */
61
+ Cypress.on('test:after:run', (test, runnable) => {
62
+ contextCollector(test, runnable);
63
+ });
56
64
  };
@@ -1,9 +1,20 @@
1
+ /**
2
+ * Fetches the Jahia version using a GraphQL query.
3
+ * @returns Cypress.Chainable that resolves to the Jahia version record (e.g., release: "8.0.0", ...).
4
+ * @note In rare cases tests might override baseUrl (e.g. when Jahia is configured with custom context path,
5
+ * but spec want to use just a host, without the context path), e.g.:
6
+ * it('Crawl pages', {baseUrl: serverURL.origin}, () => { ... })
7
+ * In such case(s) this call will fail because the GraphQL endpoint will not be found at the root of the host.
8
+ * To prevent such failure, we ensure GraphQL client uses full Jahia url as configured in env variable.
9
+ */
1
10
  export const getJahiaVersion = (): Cypress.Chainable => {
2
- return cy.apollo({
3
- fetchPolicy: 'no-cache',
4
- queryFile: 'graphql/jcr/query/getJahiaVersion.graphql'
5
- }).then(result => {
6
- return result?.data?.admin.jahia.version;
11
+ return cy.apolloClient({url: Cypress.env('JAHIA_URL') || Cypress.config().baseUrl}).then(() => {
12
+ return cy.apollo({
13
+ fetchPolicy: 'no-cache',
14
+ queryFile: 'graphql/jcr/query/getJahiaVersion.graphql'
15
+ }).then(result => {
16
+ return result?.data?.admin.jahia.version;
17
+ });
7
18
  });
8
19
  };
9
20
 
@@ -1,11 +1,19 @@
1
1
  import '../../../src/support/apollo/apollo';
2
+ import '../../../src/support/apollo/apolloClient';
2
3
  import {modSince, initializeVersionSupport, JAHIA_VERSION_ENV_VAR} from '../../../src/support/modSince';
3
4
 
5
+ type ItSinceCall = (requiredVersion: string, title: string, fn?: (...args: unknown[]) => unknown) => Mocha.Test;
6
+ type DescribeSinceCall = (requiredVersion: string, title: string, fn: (this: Mocha.Suite) => void) => Mocha.Suite;
7
+
4
8
  // Enable version gating
5
9
  modSince.enable();
6
10
 
7
11
  // Stub apollo command
8
- Cypress.Commands.add('apollo', {prevSubject: 'optional'}, () => {
12
+ Cypress.Commands.add('apolloClient', (() => {
13
+ return cy.wrap({} as unknown);
14
+ }) as Cypress.CommandFn<'apolloClient'>);
15
+
16
+ Cypress.Commands.add('apollo', (() => {
9
17
  return cy.wrap({
10
18
  data: {
11
19
  admin: {
@@ -17,7 +25,7 @@ Cypress.Commands.add('apollo', {prevSubject: 'optional'}, () => {
17
25
  }
18
26
  }
19
27
  });
20
- });
28
+ }) as Cypress.CommandFn<'apollo'>);
21
29
 
22
30
  describe('itSince support', () => {
23
31
  describe('registration', () => {
@@ -38,7 +46,7 @@ describe('itSince support', () => {
38
46
 
39
47
  it('throws clear error when it.since args are swapped', () => {
40
48
  expect(() => {
41
- (it.since as unknown as (requiredVersion: string, title: string, fn?: Mocha.Func) => Mocha.Test)(
49
+ (it.since as unknown as ItSinceCall)(
42
50
  'my test title',
43
51
  '8.2.0',
44
52
  () => {
@@ -100,7 +108,7 @@ describe('itSince support', () => {
100
108
  let compatItRan = false;
101
109
  let compatDescribeRan = false;
102
110
 
103
- const compatIt = (it.skip as unknown as (requiredVersion: string, title: string, fn?: Mocha.Func) => Mocha.Test)(
111
+ const compatIt = (it.skip as unknown as ItSinceCall)(
104
112
  '8.3.5.0',
105
113
  compatItTitle,
106
114
  () => {
@@ -108,7 +116,7 @@ describe('itSince support', () => {
108
116
  }
109
117
  );
110
118
 
111
- const compatDescribe = (describe.skip as unknown as (requiredVersion: string, title: string, fn: (this: Mocha.Suite) => void) => Mocha.Suite)(
119
+ const compatDescribe = (describe.skip as unknown as DescribeSinceCall)(
112
120
  '8.3.5.0',
113
121
  compatDescribeTitle,
114
122
  () => {
@@ -136,6 +144,26 @@ describe('itSince support', () => {
136
144
  });
137
145
 
138
146
  describe('version initialization', () => {
147
+ beforeEach(() => {
148
+ Cypress.env(JAHIA_VERSION_ENV_VAR, '');
149
+ });
150
+
151
+ it('returns cached env version without fetching from GraphQL', () => {
152
+ Cypress.env(JAHIA_VERSION_ENV_VAR, '9.9.9');
153
+ // Use `any` here because custom commands are not part of Cypress's typed EventEmitter keys.
154
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
155
+ const cyAny = cy as any;
156
+ const apolloClientSpy = cy.spy(cyAny, 'apolloClient').as('apolloClientSpy');
157
+ const apolloSpy = cy.spy(cyAny, 'apollo').as('apolloSpy');
158
+
159
+ return initializeVersionSupport().then(version => {
160
+ expect(version).to.equal('9.9.9');
161
+ expect(Cypress.env(JAHIA_VERSION_ENV_VAR)).to.equal('9.9.9');
162
+ expect(apolloClientSpy).to.not.have.been.called;
163
+ expect(apolloSpy).to.not.have.been.called;
164
+ });
165
+ });
166
+
139
167
  it('stores normalized Jahia version in Cypress.env', () => {
140
168
  return initializeVersionSupport().then(version => {
141
169
  expect(version).to.equal('8.2.0');
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "outDir": "./dist",
5
5
  "module": "commonjs",
6
6
  "declaration": true,
7
+ "stripInternal": true,
7
8
  "moduleResolution": "node",
8
9
  "allowSyntheticDefaultImports": true,
9
10
  "esModuleInterop": true,