testit-adapter-cypress 3.7.5

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 (46) hide show
  1. package/README.md +240 -0
  2. package/dist/browser/commandLog.d.ts +10 -0
  3. package/dist/browser/commandLog.js +213 -0
  4. package/dist/browser/events/cypress.d.ts +2 -0
  5. package/dist/browser/events/cypress.js +38 -0
  6. package/dist/browser/events/index.d.ts +2 -0
  7. package/dist/browser/events/index.js +15 -0
  8. package/dist/browser/events/mocha.d.ts +3 -0
  9. package/dist/browser/events/mocha.js +80 -0
  10. package/dist/browser/index.d.ts +1 -0
  11. package/dist/browser/index.js +14 -0
  12. package/dist/browser/lifecycle.d.ts +21 -0
  13. package/dist/browser/lifecycle.js +227 -0
  14. package/dist/browser/patching.d.ts +5 -0
  15. package/dist/browser/patching.js +117 -0
  16. package/dist/browser/runtime.d.ts +31 -0
  17. package/dist/browser/runtime.js +284 -0
  18. package/dist/browser/serialize.d.ts +3 -0
  19. package/dist/browser/serialize.js +57 -0
  20. package/dist/browser/state.d.ts +28 -0
  21. package/dist/browser/state.js +80 -0
  22. package/dist/browser/steps.d.ts +14 -0
  23. package/dist/browser/steps.js +114 -0
  24. package/dist/browser/testplan.d.ts +2 -0
  25. package/dist/browser/testplan.js +55 -0
  26. package/dist/browser/types.d.ts +35 -0
  27. package/dist/browser/types.js +30 -0
  28. package/dist/browser/utils.d.ts +65 -0
  29. package/dist/browser/utils.js +187 -0
  30. package/dist/converter.d.ts +43 -0
  31. package/dist/converter.js +84 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +6 -0
  34. package/dist/models/index.d.ts +0 -0
  35. package/dist/models/index.js +1 -0
  36. package/dist/models/status.d.ts +5 -0
  37. package/dist/models/status.js +9 -0
  38. package/dist/models/types.d.ts +280 -0
  39. package/dist/models/types.js +2 -0
  40. package/dist/node-utils.d.ts +15 -0
  41. package/dist/node-utils.js +93 -0
  42. package/dist/reporter.d.ts +24 -0
  43. package/dist/reporter.js +382 -0
  44. package/dist/utils.d.ts +17 -0
  45. package/dist/utils.js +34 -0
  46. package/package.json +50 -0
package/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # Test IT TMS adapters for Cypress
2
+ ![Test IT](https://raw.githubusercontent.com/testit-tms/adapters-js/master/images/banner.png)
3
+
4
+ ## Getting Started
5
+
6
+ ### Installation
7
+ ```
8
+ npm install testit-adapter-cypress
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Configuration
14
+
15
+ | Description | File property | Environment variable |
16
+ |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|--------------------------------------------|
17
+ | Location of the TMS instance | url | TMS_URL |
18
+ | API secret key [How to getting API secret key?](https://github.com/testit-tms/.github/tree/main/configuration#privatetoken) | privateToken | TMS_PRIVATE_TOKEN |
19
+ | ID of project in TMS instance [How to getting project ID?](https://github.com/testit-tms/.github/tree/main/configuration#projectid) | projectId | TMS_PROJECT_ID |
20
+ | ID of configuration in TMS instance [How to getting configuration ID?](https://github.com/testit-tms/.github/tree/main/configuration#configurationid) | configurationId | TMS_CONFIGURATION_ID |
21
+ | ID of the created test run in TMS instance.<br/>It's necessary for **adapterMode** 1 | testRunId | TMS_TEST_RUN_ID |
22
+ | Parameter for specifying the name of test run in TMS instance (**It's optional**). If it is not provided, it is created automatically | testRunName | TMS_TEST_RUN_NAME |
23
+ | Adapter mode. Default value - 1. The adapter supports following modes:<br>1 - in this mode, the adapter sends all results to the test run without filtering or [with filtering CLI](#run-with-filter)<br/>2 - in this mode, the adapter creates a new test run and sends results to the new test run | adapterMode | TMS_ADAPTER_MODE |
24
+ | It enables/disables certificate validation (**It's optional**). Default value - true | certValidation | TMS_CERT_VALIDATION |
25
+ | Mode of automatic creation test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will create a test case linked to the created autotest (not to the updated autotest)<br/>false - in this mode, the adapter will not create a test case | automaticCreationTestCases | TMS_AUTOMATIC_CREATION_TEST_CASES |
26
+ | Mode of automatic updation links to test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will update links to test cases<br/>false - in this mode, the adapter will not update link to test cases | automaticUpdationLinksToTestCases | TMS_AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES |
27
+
28
+ Add Adapter to Cypress file configuration:
29
+
30
+ ```ts
31
+ import { tmsCypress } from "testit-adapter-cypress/reporter";
32
+
33
+ export default {
34
+ e2e: {
35
+ setupNodeEvents(on, config) {
36
+ tmsCypress(on, config);
37
+
38
+ return config;
39
+ },
40
+ },
41
+ };
42
+ ```
43
+
44
+ Add Adapter to `cypress/support/e2e.js`:
45
+ ```ts
46
+ import "testit-adapter-cypress";
47
+ ```
48
+
49
+ #### File
50
+
51
+ Create .env config or file config with default name tms.config.json in the root directory of the project
52
+
53
+ ```json
54
+ {
55
+ "url": "URL",
56
+ "privateToken": "USER_PRIVATE_TOKEN",
57
+ "projectId": "PROJECT_ID",
58
+ "configurationId": "CONFIGURATION_ID",
59
+ "testRunId": "TEST_RUN_ID",
60
+ "testRunName": "TEST_RUN_NAME",
61
+ "adapterMode": "ADAPTER_MODE",
62
+ "automaticCreationTestCases": "AUTOMATIC_CREATION_TEST_CASES",
63
+ "automaticUpdationLinksToTestCases": "AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES"
64
+ }
65
+ ```
66
+
67
+ #### Parallel run
68
+ To create and complete TestRun you can use the Test IT CLI (use adapterMode 1 for parallel run):
69
+
70
+ ```
71
+ $ export TMS_TOKEN=<YOUR_TOKEN>
72
+ $ testit testrun create
73
+ --url https://tms.testit.software \
74
+ --project-id 5236eb3f-7c05-46f9-a609-dc0278896464 \
75
+ --testrun-name "New test run" \
76
+ --output tmp/output.txt
77
+
78
+ $ export TMS_TEST_RUN_ID=$(cat tmp/output.txt)
79
+
80
+ $ npx cypress run
81
+
82
+ $ testit testrun complete
83
+ --url https://tms.testit.software \
84
+ --testrun-id $(cat tmp/output.txt)
85
+ ```
86
+
87
+ #### Run with filter
88
+ It is necessary to use test filtering in cypress. This example uses the "@cypress/grep" plugin.
89
+ To create filter by autotests you can use the Test IT CLI (use adapterMode 1 for run with filter):
90
+
91
+ ```
92
+ $ export TMS_TOKEN=<YOUR_TOKEN>
93
+ $ testit autotests_filter
94
+ --url https://tms.testit.software \
95
+ --configuration-id 5236eb3f-7c05-46f9-a609-dc0278896464 \
96
+ --testrun-id 6d4ac4b7-dd67-4805-b879-18da0b89d4a8 \
97
+ --framework cypress \
98
+ --output tmp/filter.txt
99
+
100
+ $ export TMS_TEST_RUN_ID=6d4ac4b7-dd67-4805-b879-18da0b89d4a8
101
+ $ export TMS_ADAPTER_MODE=1
102
+
103
+ $ npx cypress run --expose grep="$(cat tmp/filter.txt)"
104
+ ```
105
+
106
+ #### Launch using GitLab repository
107
+ To run your Cypress test's from GitLab to TestIT or in reverse order using "testit-adapter-cypress", you can take this .gitlab-ci.yml file example:
108
+
109
+ ```
110
+ image: node:latest
111
+
112
+ stages:
113
+ - run
114
+
115
+ first-job:
116
+ stage: run
117
+ script:
118
+ - npm install
119
+ - npx cypress run
120
+ artifacts:
121
+ paths:
122
+ - node_modules/
123
+ ```
124
+
125
+
126
+ ### Methods
127
+
128
+ Methods can be used to specify information about autotest.
129
+
130
+ Description of methods:
131
+ - `tms.addWorkItemIds` - a dynamic method that links autotests with manual tests. Receives the array of manual tests' IDs
132
+ - `tms.addDisplayName` - a dynamic method for adding internal autotest name (used in Test IT)
133
+ - `tms.addTitle` - a dynamic method for adding autotest name specified in the autotest card. If not specified, the name from the displayName method is used
134
+ - `tms.addDescription` - a dynamic method for adding autotest description specified in the autotest card
135
+ - `tms.addLabels` - a dynamic method for adding labels listed in the autotest card
136
+ - `tms.addTags` - a dynamic method for adding tags listed in the autotest card
137
+ - `tms.addLinks` - links in the autotest result
138
+ - `tms.addAttachments` - uploading files in the autotest result
139
+ - `tms.addMessage` - information about autotest in the autotest result
140
+ - `tms.addNameSpace` - a dynamic method for adding directory in the TMS system (default - file's name of test)
141
+ - `tms.addClassName` - a dynamic method for adding subdirectory in the TMS system (default - class's name of test)
142
+ - `tms.addParameter` - a dynamic method for adding parameter in the autotest result
143
+ - `tms.step` - usage in the "with" construct to designation a step in the body of the test
144
+
145
+ ### Examples
146
+
147
+ #### Simple test
148
+ ```ts
149
+ import { getTestRuntime } from "testit-adapter-cypress/runtime";
150
+
151
+ describe('example to-do app', () => {
152
+ it('displays two todo items by default', () => {
153
+ const tms = getTestRuntime();
154
+
155
+ tms.addWorkItemIds('123', '321');
156
+ tms.addDisplayName('display name');
157
+ tms.addTitle('test title');
158
+ tms.addDescription('Test description');
159
+ tms.addLabels('label1', 'label2');
160
+ tms.addTags('tag1', 'tag2');
161
+ tms.addLinks([
162
+ {
163
+ url: 'https://www.google.com',
164
+ title: 'Google',
165
+ description: 'This is a link to Google',
166
+ type: 'Related',
167
+ },
168
+ ]);
169
+ tms.addParameter("name", "value");
170
+ tms.addNameSpace("namespace");
171
+ tms.addClassName("classname");
172
+
173
+ tms.step("step title", () => {
174
+ // ...
175
+ }).then((user) => {
176
+ tms.step("inner step title", () => {
177
+ // ...
178
+ });
179
+ });
180
+ });
181
+ });
182
+ ```
183
+
184
+ ### Parameterized test
185
+
186
+ > [!WARNING]
187
+ > When linking a parameterized autotest to a parameterized test case, please consider the problematic points:
188
+ > - In TMS test cases have a table with parameters, but autotests do not. They are not equal entities, so there may be incompatibility in terms of parameters
189
+ > - Running a parameterized test case, TMS expects the results of all related autotests with all the parameters specified in the test case table
190
+ > - In TMS, the parameters are limited to the string type, so the adapter transmits absolutely all the autotest parameters as a string. This implies the following problematic point for the test case table
191
+ > - TMS expects a complete **textual** match of the name and value of the parameters of the test case table with the autotest parameters
192
+
193
+ ```ts
194
+ import { getTestRuntime } from "testit-adapter-cypress/runtime";
195
+
196
+ describe('example to-do app', () => {
197
+ const tests = [2, 3, "string", false];
198
+
199
+ tests.forEach((value) => {
200
+ it(`3 is ${value}`, () => {
201
+ const tms = getTestRuntime();
202
+
203
+ tms.addParameter("name", value);
204
+ // ...
205
+ });
206
+ });
207
+ });
208
+ ```
209
+
210
+ #### Content types
211
+ ```
212
+ TEXT = "text/plain",
213
+ XML = "application/xml",
214
+ HTML = "text/html",
215
+ CSV = "text/csv",
216
+ TSV = "text/tab-separated-values",
217
+ CSS = "text/css",
218
+ URI = "text/uri-list",
219
+ SVG = "image/svg+xml",
220
+ PNG = "image/png",
221
+ JSON = "application/json",
222
+ ZIP = "application/zip",
223
+ WEBM = "video/webm",
224
+ JPEG = "image/jpeg",
225
+ MP4 = "video/mp4",
226
+ ```
227
+
228
+ # Contributing
229
+
230
+ You can help to develop the project. Any contributions are **greatly appreciated**.
231
+
232
+ * If you have suggestions for adding or removing projects, feel free to [open an issue](https://github.com/testit-tms/adapters-js/issues/new) to discuss it, or directly create a pull request after you edit the *README.md* file with necessary changes.
233
+ * Please make sure you check your spelling and grammar.
234
+ * Create individual PR for each suggestion.
235
+ * Please also read through the [Code Of Conduct](https://github.com/testit-tms/adapters-js/blob/master/CODE_OF_CONDUCT.md) before posting your first idea as well.
236
+
237
+ # License
238
+
239
+ Distributed under the Apache-2.0 License. See [LICENSE](https://github.com/testit-tms/adapters-js/blob/master/LICENSE.md) for more information.
240
+
@@ -0,0 +1,10 @@
1
+ import type { CypressLogEntry } from "../models/types.js";
2
+ export declare const shouldCreateStepFromCommandLogEntry: (entry: CypressLogEntry) => boolean;
3
+ /**
4
+ * Checks if the current step represents a cy.screenshot command log entry. If this is the case, associates the name
5
+ * of the screenshot with the step. Later, that will allow converting the step with the attachment into the attachment
6
+ * step.
7
+ */
8
+ export declare const setupScreenshotAttachmentStep: (originalName: string | undefined, name: string) => void;
9
+ export declare const startCommandLogStep: (entry: CypressLogEntry) => void;
10
+ export declare const stopCommandLogStep: (entryId: string) => void;
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stopCommandLogStep = exports.startCommandLogStep = exports.setupScreenshotAttachmentStep = exports.shouldCreateStepFromCommandLogEntry = void 0;
7
+ const utils_js_1 = require("../utils.js");
8
+ const lifecycle_js_1 = require("./lifecycle.js");
9
+ const serialize_js_1 = __importDefault(require("./serialize.js"));
10
+ const state_js_1 = require("./state.js");
11
+ const steps_js_1 = require("./steps.js");
12
+ const utils_js_2 = require("./utils.js");
13
+ const shouldCreateStepFromCommandLogEntry = (entry) => {
14
+ const { event, instrument } = entry.attributes;
15
+ if (instrument !== "command") {
16
+ // We are interested in the "TEST BODY" panel only for now.
17
+ // Other instruments are logged in separate panels.
18
+ return false;
19
+ }
20
+ if (event) {
21
+ // Events are tricky to report as they may span across commands and even leave the test's scope.
22
+ // We ignore them for now.
23
+ return false;
24
+ }
25
+ if (isApiStepErrorLogEntry(entry)) {
26
+ // Cypress don't create a log message for 'cy.then' except when it throws an error.
27
+ // This is in particularly happens when the function passed to 'testit.step' throws. In such a case however,
28
+ // creating an extra step from the log entry is redundant because the error is already included in the report as
29
+ // a part of the step.
30
+ return false;
31
+ }
32
+ return true;
33
+ };
34
+ exports.shouldCreateStepFromCommandLogEntry = shouldCreateStepFromCommandLogEntry;
35
+ /**
36
+ * Checks if the current step represents a cy.screenshot command log entry. If this is the case, associates the name
37
+ * of the screenshot with the step. Later, that will allow converting the step with the attachment into the attachment
38
+ * step.
39
+ */
40
+ const setupScreenshotAttachmentStep = (originalName, name) => {
41
+ const step = (0, state_js_1.getCurrentStep)();
42
+ if (step && (0, steps_js_1.isLogStep)(step)) {
43
+ const { name: commandName, props: { name: nameFromProps }, } = (0, utils_js_2.resolveConsoleProps)(step.log);
44
+ if (commandName === "screenshot" && nameFromProps === originalName) {
45
+ step.attachmentName = name;
46
+ }
47
+ }
48
+ };
49
+ exports.setupScreenshotAttachmentStep = setupScreenshotAttachmentStep;
50
+ const startCommandLogStep = (entry) => {
51
+ const currentLogEntry = getCurrentLogEntry();
52
+ if (typeof currentLogEntry !== "undefined" && shouldStopCurrentLogStep(currentLogEntry.log, entry)) {
53
+ (0, exports.stopCommandLogStep)(currentLogEntry.log.attributes.id);
54
+ }
55
+ pushLogEntry(entry);
56
+ (0, lifecycle_js_1.reportStepStart)(entry.attributes.id, getCommandLogStepName(entry));
57
+ scheduleCommandLogStepStop(entry);
58
+ };
59
+ exports.startCommandLogStep = startCommandLogStep;
60
+ const stopCommandLogStep = (entryId) => (0, steps_js_1.findAndStopStepWithSubsteps)(({ id }) => id === entryId);
61
+ exports.stopCommandLogStep = stopCommandLogStep;
62
+ const pushLogEntry = (entry) => {
63
+ const id = entry.attributes.id;
64
+ const stepDescriptor = { id, type: "log", log: entry };
65
+ (0, state_js_1.pushStep)(stepDescriptor);
66
+ // Some properties of some Command Log entries are undefined at the time the entry is stopped. An example is the
67
+ // Yielded property of some queries. We defer converting them to Tms step parameters until the test/hook ends.
68
+ (0, state_js_1.setupStepFinalization)(stepDescriptor, (data) => {
69
+ data.parameters = getCommandLogStepParameters(entry);
70
+ if (stepDescriptor.attachmentName) {
71
+ // Rename the step to match the attachment name. Once the names are the same, Tms will render the
72
+ // attachment in the place of the step.
73
+ data.name = stepDescriptor.attachmentName;
74
+ }
75
+ });
76
+ };
77
+ /**
78
+ * Wraps `entry.endGroup` so that the Tms step created for a Command Log group
79
+ * is always stopped when Cypress finishes that group.
80
+ *
81
+ * Behavior:
82
+ * - Retains the original `entry.endGroup` handler.
83
+ * - Replaces it with a wrapper function that:
84
+ * - first calls `stopCommandLogStep(id)`, completing the step in our state;
85
+ * - then calls the original `entry.endGroup` with the same `this` so as not to break Cypress.
86
+ */
87
+ const overrideEntryEndGroup = (entry, id) => {
88
+ const originalEndGroup = entry.endGroup;
89
+ entry.endGroup = function () {
90
+ (0, exports.stopCommandLogStep)(id);
91
+ return originalEndGroup.call(this);
92
+ };
93
+ };
94
+ /**
95
+ * Wraps `entry.end` for single Command Log entries to synchronize
96
+ * the lifecycle of a step in Tms with the completion of a log entry in Cypress.
97
+ *
98
+ * Behavior:
99
+ * - Saves the original `entry.end` (without context binding).
100
+ * - Sets a new `entry.end`, which:
101
+ * - first calls `stopCommandLogStep(id)` to stop the step;
102
+ * - then calls the original `end` with the correct `this', while maintaining the standard behavior of Cypress.
103
+ */
104
+ const overrideEntryEnd = (entry, id) => {
105
+ // eslint-disable-next-line @typescript-eslint/unbound-method
106
+ const originalEnd = entry.end;
107
+ entry.end = function () {
108
+ (0, exports.stopCommandLogStep)(id);
109
+ return originalEnd.call(this);
110
+ };
111
+ };
112
+ const scheduleCommandLogStepStop = (entry) => {
113
+ const { groupStart, end, id } = entry.attributes;
114
+ if (end) {
115
+ // Some entries are already completed (this is similar to the idea behind tms.logStep).
116
+ // Cypress won't call entry.end() in such a case, so we need to stop such a step now.
117
+ // Example: cy.log
118
+ (0, exports.stopCommandLogStep)(id);
119
+ }
120
+ else if (groupStart) {
121
+ // A logging group must be stopped be the user via the Cypress.Log.endGroup() call.
122
+ // If the call is missing, the corresponding step will be stopped either at the test's (the hook's) end.
123
+ overrideEntryEndGroup(entry, id);
124
+ }
125
+ else {
126
+ // Regular log entries are finalized by Cypress via the Cypress.Log.end() call. We're hooking into this function
127
+ // to complete the step at the same time.
128
+ overrideEntryEnd(entry, id);
129
+ }
130
+ };
131
+ const isApiStepErrorLogEntry = (entry) => {
132
+ const { name } = entry.attributes;
133
+ return name === "then" && Object.is((0, utils_js_2.resolveConsoleProps)(entry).props["Applied To"], steps_js_1.TMS_STEP_CMD_SUBJECT);
134
+ };
135
+ const getCommandLogStepName = (entry) => {
136
+ const { name, message, displayName } = entry.attributes;
137
+ const resolvedName = (displayName ?? name).trim();
138
+ const resolvedMessage = (maybeGetAssertionLogMessage(entry) ??
139
+ maybeGetCucumberLogMessage(entry) ??
140
+ (0, utils_js_2.resolveRenderProps)(entry).message ??
141
+ message).trim();
142
+ const stepName = [resolvedName, resolvedMessage].filter(Boolean).join(" ");
143
+ return stepName;
144
+ };
145
+ const getCommandLogStepParameters = (entry) => getLogProps(entry)
146
+ .map(([k, v]) => ({
147
+ name: k.toString(),
148
+ value: (0, serialize_js_1.default)(v),
149
+ }))
150
+ .filter(getPropValueSetFilter(entry));
151
+ const WELL_KNOWN_CUCUMBER_LOG_NAMES = ["Given", "When", "Then", "And"];
152
+ const maybeGetCucumberLogMessage = (entry) => {
153
+ const { attributes: { name, message }, } = entry;
154
+ if (WELL_KNOWN_CUCUMBER_LOG_NAMES.includes(name.trim()) && message.startsWith("**") && message.endsWith("**")) {
155
+ return message.substring(2, message.length - 2);
156
+ }
157
+ };
158
+ const getLogProps = (entry) => {
159
+ const isAssertionWithMessage = !!maybeGetAssertionLogMessage(entry);
160
+ const { props, name } = (0, utils_js_2.resolveConsoleProps)(entry);
161
+ // accessing LocalStorage after the page reload can stick the test runner
162
+ // to avoid the issue, we just need to log the command manually
163
+ // the problem potentially can happen with other storage related commands, like `clearAllLocalStorage`, `clearAllSessionStorage`, `getAllLocalStorage`, `getAllSessionStorage`, `setLocalStorage`, `setSessionStorage`
164
+ // but probably, we don't need to silent them all at this moment
165
+ if (["clearLocalStorage"].includes(name)) {
166
+ return [];
167
+ }
168
+ // For assertion logs, we interpolate the 'Message' property, which contains unformatted assertion description,
169
+ // directly into the step's name.
170
+ // No need to keep the exact same information in the step's parameters.
171
+ const entries = Object.entries(props);
172
+ return entries.filter(([key, value]) => isLogPropIncludedInParameters({ key, value, isAssertionWithMessage }));
173
+ };
174
+ const isLogPropIncludedInParameters = ({ key, value, isAssertionWithMessage, }) => {
175
+ if (!(0, utils_js_1.isDefined)(value)) {
176
+ return false;
177
+ }
178
+ if (isAssertionWithMessage && key === "Message") {
179
+ // The same text is already included into the step's name.
180
+ // No need to duplicate it in parameters.
181
+ return false;
182
+ }
183
+ return true;
184
+ };
185
+ const maybeGetAssertionLogMessage = (entry) => {
186
+ if (isAssertLog(entry)) {
187
+ const message = (0, utils_js_2.resolveConsoleProps)(entry).props.Message;
188
+ if (message && typeof message === "string") {
189
+ return message;
190
+ }
191
+ }
192
+ };
193
+ const isAssertLog = ({ attributes: { name } }) => name === "assert";
194
+ const getCurrentLogEntry = () => (0, state_js_1.getStepStack)().findLast(steps_js_1.isLogStep);
195
+ const shouldStopCurrentLogStep = (currentLogEntry, newLogEntry) => {
196
+ const { groupStart: currentEntryIsGroup, type: currentEntryType } = currentLogEntry.attributes;
197
+ const { type: newEntryType } = newLogEntry.attributes;
198
+ return !currentEntryIsGroup && (currentEntryType === "child" || newEntryType !== "child");
199
+ };
200
+ /**
201
+ * Returns a predicate that decides whether a step parameter should be included.
202
+ * For "wrap" commands we include all parameters; for others we drop "Yielded" when it's "{}".
203
+ */
204
+ const getPropValueSetFilter = (entry) => {
205
+ const isWrapCommand = entry.attributes.name === "wrap";
206
+ if (isWrapCommand) {
207
+ return () => true;
208
+ }
209
+ return ({ name, value }) => shouldIncludeParameter(name, value);
210
+ };
211
+ const shouldIncludeParameter = (name, value) => {
212
+ return name !== "Yielded" || value !== "{}";
213
+ };
@@ -0,0 +1,2 @@
1
+ export declare const registerCypressEventListeners: () => Cypress.Cypress;
2
+ export declare const enableReportingOfCypressScreenshots: () => void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enableReportingOfCypressScreenshots = exports.registerCypressEventListeners = void 0;
4
+ const commandLog_js_1 = require("../commandLog.js");
5
+ const lifecycle_js_1 = require("../lifecycle.js");
6
+ const steps_js_1 = require("../steps.js");
7
+ const utils_js_1 = require("../utils.js");
8
+ const registerCypressEventListeners = () => Cypress.on("fail", onFail).on("log:added", onLogAdded);
9
+ exports.registerCypressEventListeners = registerCypressEventListeners;
10
+ const enableReportingOfCypressScreenshots = () => Cypress.Screenshot.defaults({ onAfterScreenshot });
11
+ exports.enableReportingOfCypressScreenshots = enableReportingOfCypressScreenshots;
12
+ const onAfterScreenshot = (...[, { name: originalName, path }]) => {
13
+ const name = originalName ?? (0, utils_js_1.getFileNameFromPath)(path);
14
+ (0, lifecycle_js_1.reportScreenshot)(path, name);
15
+ (0, commandLog_js_1.setupScreenshotAttachmentStep)(originalName, name);
16
+ };
17
+ const onLogAdded = (_, entry) => {
18
+ if ((0, commandLog_js_1.shouldCreateStepFromCommandLogEntry)(entry)) {
19
+ (0, commandLog_js_1.startCommandLogStep)(entry);
20
+ }
21
+ };
22
+ const onFail = (error) => {
23
+ (0, steps_js_1.reportStepError)(error);
24
+ if (noSubsequentFailListeners()) {
25
+ throw error;
26
+ }
27
+ };
28
+ /**
29
+ * Returns true if this handler is the last registered "fail" listener in Cypress.
30
+ *
31
+ * In that case we rethrow the error so that Cypress can apply its default error handling.
32
+ * If there are other listeners after ours, we assume they will handle the error.
33
+ */
34
+ const noSubsequentFailListeners = () => {
35
+ const failListeners = Cypress.listeners("fail");
36
+ const lastFailListener = failListeners.at(-1);
37
+ return Object.is(lastFailListener, onFail);
38
+ };
@@ -0,0 +1,2 @@
1
+ export declare const enableTms: () => void;
2
+ export { enableReportingOfCypressScreenshots } from "./cypress.js";
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enableReportingOfCypressScreenshots = exports.enableTms = void 0;
4
+ const patching_js_1 = require("../patching.js");
5
+ const cypress_js_1 = require("./cypress.js");
6
+ const mocha_js_1 = require("./mocha.js");
7
+ const enableTms = () => {
8
+ (0, mocha_js_1.registerMochaEventListeners)();
9
+ (0, cypress_js_1.registerCypressEventListeners)();
10
+ (0, mocha_js_1.injectFlushMessageHooks)();
11
+ (0, patching_js_1.enableScopeLevelAfterHookReporting)();
12
+ };
13
+ exports.enableTms = enableTms;
14
+ var cypress_js_2 = require("./cypress.js");
15
+ Object.defineProperty(exports, "enableReportingOfCypressScreenshots", { enumerable: true, get: function () { return cypress_js_2.enableReportingOfCypressScreenshots; } });
@@ -0,0 +1,3 @@
1
+ export declare const TMS_REPORT_SYSTEM_HOOK = "__tms_report_system_hook__";
2
+ export declare const registerMochaEventListeners: () => void;
3
+ export declare const injectFlushMessageHooks: () => void;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.injectFlushMessageHooks = exports.registerMochaEventListeners = exports.TMS_REPORT_SYSTEM_HOOK = void 0;
4
+ const lifecycle_js_1 = require("../lifecycle.js");
5
+ const runtime_js_1 = require("../runtime.js");
6
+ const testplan_js_1 = require("../testplan.js");
7
+ const utils_js_1 = require("../utils.js");
8
+ exports.TMS_REPORT_SYSTEM_HOOK = "__tms_report_system_hook__";
9
+ const registerMochaEventListeners = () => {
10
+ Cypress.mocha.getRunner()
11
+ .on("start", onStart)
12
+ .on("suite", onSuite)
13
+ .on("suite end", lifecycle_js_1.reportSuiteEnd)
14
+ .on("hook", onHook)
15
+ .on("hook end", onHookEnd)
16
+ .on("test", onTest)
17
+ .on("pass", lifecycle_js_1.reportTestPass)
18
+ .on("fail", onFail)
19
+ .on("pending", lifecycle_js_1.reportTestSkip)
20
+ .on("test end", lifecycle_js_1.reportTestEnd);
21
+ };
22
+ exports.registerMochaEventListeners = registerMochaEventListeners;
23
+ const injectFlushMessageHooks = () => {
24
+ afterEach(exports.TMS_REPORT_SYSTEM_HOOK, lifecycle_js_1.flushRuntimeMessages);
25
+ after(exports.TMS_REPORT_SYSTEM_HOOK, onAfterAll);
26
+ };
27
+ exports.injectFlushMessageHooks = injectFlushMessageHooks;
28
+ const onStart = () => {
29
+ (0, runtime_js_1.initTestRuntime)();
30
+ (0, lifecycle_js_1.reportRunStart)();
31
+ };
32
+ const onSuite = (suite) => {
33
+ if (suite.root) {
34
+ (0, testplan_js_1.applyTestPlan)(Cypress.spec, suite);
35
+ }
36
+ (0, lifecycle_js_1.reportSuiteStart)(suite);
37
+ };
38
+ const onHook = (hook) => {
39
+ if ((0, utils_js_1.isTmsHook)(hook)) {
40
+ return;
41
+ }
42
+ (0, lifecycle_js_1.reportHookStart)(hook);
43
+ };
44
+ const onHookEnd = (hook) => {
45
+ if ((0, utils_js_1.isTmsHook)(hook)) {
46
+ return;
47
+ }
48
+ (0, lifecycle_js_1.reportHookEnd)(hook);
49
+ };
50
+ const onTest = (test) => {
51
+ // Cypress emits an extra EVENT_TEST_BEGIN if the test is skipped.
52
+ // reportTestSkip does that already, so we need to filter the extra event out.
53
+ if (!(0, utils_js_1.isTestReported)(test)) {
54
+ (0, lifecycle_js_1.reportTestStart)(test);
55
+ }
56
+ };
57
+ const onFail = (testOrHook, err) => {
58
+ const isHook = "hookName" in testOrHook;
59
+ if (isHook && (0, utils_js_1.isRootAfterAllHook)(testOrHook)) {
60
+ // Errors in spec-level 'after all' hooks are handled by Tms wrappers.
61
+ return;
62
+ }
63
+ const isTmsHookFailure = isHook && (0, utils_js_1.isTmsHook)(testOrHook);
64
+ if (isTmsHookFailure) {
65
+ // Normally, Tms hooks are skipped from the report.
66
+ // In case of errors, it will be helpful to see them.
67
+ (0, lifecycle_js_1.reportHookStart)(testOrHook, Date.now() - (testOrHook.duration ?? 0));
68
+ }
69
+ // This will mark the fixture and the test (if any) as failed/broken.
70
+ (0, lifecycle_js_1.reportTestOrHookFail)(err);
71
+ if (isHook) {
72
+ // This will end the fixture and test (if any) and will report the remaining
73
+ // tests in the hook's suite (the ones that will be skipped by Cypress/Mocha).
74
+ (0, lifecycle_js_1.completeHookErrorReporting)(testOrHook, err);
75
+ }
76
+ };
77
+ const onAfterAll = function () {
78
+ (0, lifecycle_js_1.flushRuntimeMessages)();
79
+ (0, lifecycle_js_1.completeSpecIfNoAfterHookLeft)(this);
80
+ };
@@ -0,0 +1 @@
1
+ export declare const initializeTms: () => void;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initializeTms = void 0;
4
+ const index_js_1 = require("./events/index.js");
5
+ const state_js_1 = require("./state.js");
6
+ const initializeTms = () => {
7
+ if ((0, state_js_1.isTmsInitialized)()) {
8
+ return;
9
+ }
10
+ (0, state_js_1.setTmsInitialized)();
11
+ (0, index_js_1.enableTms)();
12
+ (0, index_js_1.enableReportingOfCypressScreenshots)();
13
+ };
14
+ exports.initializeTms = initializeTms;
@@ -0,0 +1,21 @@
1
+ import type { CypressHook, CypressSuite, CypressTest, StepDescriptor, StatusDetails } from "../models/types.js";
2
+ import { Status } from "../models/status.js";
3
+ export declare const reportRunStart: () => void;
4
+ export declare const reportSuiteStart: (suite: CypressSuite) => void;
5
+ export declare const reportSuiteEnd: (suite: CypressSuite) => void;
6
+ export declare const reportHookStart: (hook: CypressHook, start?: number) => void;
7
+ export declare const reportHookEnd: (hook: CypressHook) => void;
8
+ export declare const reportTestStart: (test: CypressTest) => void;
9
+ export declare const reportStepStart: (id: string, name: string) => void;
10
+ export declare const reportStepStop: (step: StepDescriptor, status?: Status, statusDetails?: StatusDetails) => void;
11
+ export declare const reportTestPass: () => void;
12
+ export declare const reportTestOrHookFail: (err: Error) => void;
13
+ export declare const completeHookErrorReporting: (hook: CypressHook, err: Error) => void;
14
+ export declare const reportTestSkip: (test: CypressTest) => void;
15
+ export declare const reportTestEnd: (test: CypressTest) => void;
16
+ export declare const reportScreenshot: (path: string, name: string) => void;
17
+ export declare const completeSpecIfNoAfterHookLeft: (context: Mocha.Context) => Cypress.Chainable<unknown> | undefined;
18
+ export declare const completeSpecOnAfterHookFailure: (context: Mocha.Context, hookError: Error) => Cypress.Chainable<unknown> | undefined;
19
+ export declare const throwAfterSpecCompletion: (context: Mocha.Context, err: any) => void;
20
+ export declare const flushRuntimeMessages: () => void;
21
+ export declare const completeSpecAsync: () => Cypress.Chainable<unknown> | undefined;