@trackunit/iris-app-e2e 1.8.85-alpha-20757f7c966.0 → 1.8.85

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/node.cjs.js DELETED
@@ -1,350 +0,0 @@
1
- 'use strict';
2
-
3
- var fs = require('fs');
4
- var path = require('path');
5
- var crypto = require('crypto');
6
- var nodeXlsx = require('node-xlsx');
7
- var fileNameBuilder = require('./fileNameBuilder.cjs.js');
8
-
9
- function _interopNamespaceDefault(e) {
10
- var n = Object.create(null);
11
- if (e) {
12
- Object.keys(e).forEach(function (k) {
13
- if (k !== 'default') {
14
- var d = Object.getOwnPropertyDescriptor(e, k);
15
- Object.defineProperty(n, k, d.get ? d : {
16
- enumerable: true,
17
- get: function () { return e[k]; }
18
- });
19
- }
20
- });
21
- }
22
- n.default = e;
23
- return Object.freeze(n);
24
- }
25
-
26
- var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
27
-
28
- /* eslint-disable no-console */
29
- /**
30
- * Writes a file with Prettier formatting applied.
31
- * Automatically detects parser based on file extension.
32
- */
33
- const writeFileWithPrettier = async (nxRoot, filePath, content, writeOptions = { encoding: "utf-8" }, writer) => {
34
- const prettierConfigPath = path__namespace.join(nxRoot, ".prettierrc");
35
- const options = await writer
36
- .resolveConfig(prettierConfigPath)
37
- .catch(error => console.log("Prettier config error: ", error));
38
- if (!options) {
39
- throw new Error("Could not find prettier config");
40
- }
41
- if (filePath.endsWith("json")) {
42
- options.parser = "json";
43
- }
44
- else {
45
- options.parser = "typescript";
46
- }
47
- try {
48
- const prettySrc = await writer.format(content, options);
49
- fs.writeFileSync(filePath, prettySrc, writeOptions);
50
- }
51
- catch (error) {
52
- console.error("Error in prettier.format:", error);
53
- }
54
- };
55
-
56
- const isNetworkCall = (log) => {
57
- return log.type === "cy:fetch" || log.type === "cy:request" || log.type === "cy:response" || log.type === "cy:xrh";
58
- };
59
- /**
60
- * Creates log files for Cypress test runs.
61
- * Generates separate files for all logs, errors, and network errors.
62
- */
63
- function createLogFile(nxRoot, logsPath, fileNameWithoutExtension, logs, logWriter) {
64
- if (!fs.existsSync(logsPath)) {
65
- fs.mkdirSync(logsPath, { recursive: true });
66
- }
67
- const logFilePath = path.join(logsPath, fileNameWithoutExtension);
68
- writeFileWithPrettier(nxRoot, logFilePath + "-all.json", JSON.stringify(logs), { flag: "a" }, logWriter);
69
- const errorCmds = logs.filter(log => log.severity === "error" &&
70
- // This seems to be when apollo has cancelled requests it marks it as failed to fetch only on cypress ?!??
71
- // might be fixed by https://github.com/Trackunit/manager/pull/12917
72
- !log.message.includes("TypeError: Failed to fetch"));
73
- if (errorCmds.length > 0) {
74
- writeFileWithPrettier(nxRoot, logFilePath + "-errors.json", JSON.stringify(errorCmds), {
75
- flag: "a",
76
- }, logWriter);
77
- }
78
- const networkErrorsCmds = logs.filter(log => isNetworkCall(log) &&
79
- !log.message.includes("Status: 200") &&
80
- log.severity !== "success" &&
81
- !log.message.includes("sentry.io/api/") &&
82
- // This seems to be when apollo has cancelled requests it marks it as failed to fetch only on cypress ?!??
83
- !log.message.includes("TypeError: Failed to fetch"));
84
- if (networkErrorsCmds.length > 0) {
85
- writeFileWithPrettier(nxRoot, logFilePath + "-network-errors.json", JSON.stringify(networkErrorsCmds), {
86
- flag: "a",
87
- }, logWriter);
88
- }
89
- }
90
-
91
- /**
92
- * Parses lines from a CODEOWNERS‐style file into a mapping of patterns → owners.
93
- * Skips blank lines and comments (lines beginning with `#`).
94
- *
95
- * @param {string[]} lines - Each element is a line from your CODEOWNERS file.
96
- * @returns {Record<string, string>} An object whose keys are normalized path patterns (no leading/trailing slashes)
97
- * and whose values are the owner (e.g. a GitHub team handle).
98
- * @example
99
- * ```ts
100
- * const lines = [
101
- * "# Our CODEOWNERS",
102
- * "/src @team/backend",
103
- * "README.md @team/docs",
104
- * "", // blank lines ignored
105
- * "# end of file"
106
- * ];
107
- * const owners = parseCodeowners(lines);
108
- * // → { "src": "@team/backend", "README.md": "@team/docs" }
109
- * ```
110
- */
111
- const parseCodeowners = (lines) => {
112
- const patterns = {};
113
- for (const line of lines) {
114
- const trimmed = line.trim();
115
- if (!trimmed || trimmed.startsWith("#")) {
116
- continue;
117
- }
118
- const [pattern, owner] = trimmed.split(/\s+/, 2);
119
- if (pattern && owner) {
120
- const normalizedPattern = pattern.replace(/^\/+|\/+$/g, "");
121
- patterns[normalizedPattern] = owner;
122
- }
123
- }
124
- return patterns;
125
- };
126
- /**
127
- * Converts a full team handle (potentially namespaced and with platform suffix)
128
- * into its “short” team name.
129
- *
130
- * - Strips any leading `@org/` prefix
131
- * - Removes `-be` or `-fe` suffix if present
132
- *
133
- * @param {string} teamName - e.g. `"@trackunit/backend-be"` or `"@trackunit/frontend-fe"`
134
- * @returns {string} e.g. `"backend"` or `"frontend"`
135
- * @example
136
- * ```ts
137
- * toShortTeamName("@trackunit/backend-be"); // → "backend"
138
- * toShortTeamName("@trackunit/frontend-fe"); // → "frontend"
139
- * toShortTeamName("infra"); // → "infra"
140
- * ```
141
- */
142
- const toShortTeamName = (teamName) => {
143
- if (!teamName) {
144
- return undefined;
145
- }
146
- let shortName = teamName;
147
- if (teamName.startsWith("@")) {
148
- shortName = shortName.slice(shortName.indexOf("/") + 1);
149
- }
150
- if (shortName.endsWith("-be") || shortName.endsWith("-fe")) {
151
- shortName = shortName.slice(0, shortName.lastIndexOf("-"));
152
- }
153
- return shortName;
154
- };
155
- /**
156
- * Recursively looks up the CODEOWNER for a given file or directory path
157
- * by reading your workspace’s CODEOWNERS file.
158
- *
159
- * Walks up the directory tree until it finds a matching pattern. If no
160
- * deeper match is found but there is a `"."` entry, returns that.
161
- *
162
- * @param {string} currentPath - Absolute path to the file/directory you’re querying.
163
- * @param {string} workspaceRoot - Absolute path to your repo/workspace root.
164
- * @param {string} [codeownersFileName="TEAM_CODEOWNERS"] - Filename to read at the root.
165
- * @returns {string|undefined} The owner handle (e.g. `"@team/backend"`) or `undefined` if none found.
166
- * @example
167
- * ```ts
168
- * // Suppose your repo root has a TEAM_CODEOWNERS file containing:
169
- * // src @team/backend
170
- * // src/utils @team/utils
171
- * // . @team/root
172
- *
173
- * const owner1 = getCodeowner(
174
- * "/Users/alice/project/src/utils/helpers.ts",
175
- * "/Users/alice/project"
176
- * );
177
- * // → "@team/utils"
178
- *
179
- * const owner2 = getCodeowner(
180
- * "/Users/alice/project/other/file.txt",
181
- * "/Users/alice/project"
182
- * );
183
- * // → "@team/root" (falls back to the "." entry)
184
- * ```
185
- */
186
- const getCodeowner = (currentPath, workspaceRoot, codeownersFileName = "TEAM_CODEOWNERS") => {
187
- if (!workspaceRoot) {
188
- return undefined;
189
- }
190
- const codeownersPath = path.join(workspaceRoot, codeownersFileName);
191
- if (!fs.existsSync(codeownersPath)) {
192
- return undefined;
193
- }
194
- const codeownersLines = fs.readFileSync(codeownersPath, "utf8").split("\n");
195
- const codeowners = parseCodeowners(codeownersLines);
196
- let relPath = path
197
- .relative(workspaceRoot, currentPath)
198
- .replace(/\\/g, "/")
199
- .replace(/^\/+|\/+$/g, "");
200
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
201
- while (true) {
202
- const codeowner = codeowners[relPath];
203
- if (codeowner) {
204
- return codeowner;
205
- }
206
- const parent = path.posix.dirname(relPath);
207
- if ((parent === relPath || parent === ".") && codeowners["."]) {
208
- return codeowners["."];
209
- }
210
- if (parent === relPath || parent === ".") {
211
- break;
212
- }
213
- relPath = parent;
214
- }
215
- return undefined;
216
- };
217
-
218
- /**
219
- * Utility function to find NX workspace root by looking for nx.json or workspace.json.
220
- * This is more reliable than hardcoded relative paths and works from any directory.
221
- *
222
- * @param startDir Starting directory for the search (defaults to current working directory)
223
- * @returns {string} Absolute path to the workspace root
224
- * @throws Error if workspace root cannot be found
225
- */
226
- function findWorkspaceRoot(startDir = process.cwd()) {
227
- let currentDir = startDir;
228
- while (currentDir !== path.dirname(currentDir)) {
229
- if (fs.existsSync(path.join(currentDir, "nx.json")) || fs.existsSync(path.join(currentDir, "workspace.json"))) {
230
- return currentDir;
231
- }
232
- currentDir = path.dirname(currentDir);
233
- }
234
- throw new Error("Could not find NX workspace root (nx.json or workspace.json not found)");
235
- }
236
- /**
237
- * Creates default Cypress configuration for E2E testing.
238
- * Supports both legacy string parameter (dirname) and new options object for backward compatibility.
239
- */
240
- const defaultCypressConfig = optionsOrDirname => {
241
- // Support both old API (string/undefined) and new API (object) for backward compatibility
242
- const options = typeof optionsOrDirname === "object" ? optionsOrDirname : {};
243
- const { nxRoot: providedNxRoot, outputDirOverride, projectConfig = {}, behaviorConfig = {}, pluginConfig = {}, } = options;
244
- // Use NX workspace detection for reliable root finding
245
- const nxRoot = providedNxRoot ?? findWorkspaceRoot();
246
- // For output path calculation, determine the relative path from caller to workspace root
247
- const callerDirname = typeof optionsOrDirname === "string" ? optionsOrDirname : process.cwd();
248
- const relativePath = path.relative(nxRoot, callerDirname);
249
- const dotsToNxRoot = relativePath
250
- .split(path.sep)
251
- .map(_ => "..")
252
- .join("/");
253
- const envOutputDirOverride = process.env.NX_E2E_OUTPUT_DIR || outputDirOverride;
254
- // Function to build output paths that respects the override
255
- const buildOutputPath = (subPath) => {
256
- if (envOutputDirOverride) {
257
- return path.join(dotsToNxRoot, envOutputDirOverride, subPath);
258
- }
259
- return `${dotsToNxRoot}/dist/cypress/${relativePath}/${subPath}`;
260
- };
261
- return {
262
- projectId: projectConfig.projectId ?? process.env.CYPRESS_PROJECT_ID,
263
- defaultCommandTimeout: behaviorConfig.defaultCommandTimeout ?? 20000,
264
- execTimeout: behaviorConfig.execTimeout ?? 300000,
265
- taskTimeout: behaviorConfig.taskTimeout ?? 35000,
266
- pageLoadTimeout: behaviorConfig.pageLoadTimeout ?? 35000,
267
- // setting to undefined makes no effect on the baseUrl so child projects can override it
268
- baseUrl: process.env.NX_FEATURE_BRANCH_BASE_URL ?? undefined,
269
- // This avoid issues with SRI hashes changing
270
- modifyObstructiveCode: false,
271
- requestTimeout: behaviorConfig.requestTimeout ?? 25000,
272
- responseTimeout: behaviorConfig.responseTimeout ?? 150000,
273
- retries: behaviorConfig.retries ?? {
274
- runMode: 3,
275
- openMode: 0,
276
- },
277
- fixturesFolder: projectConfig.fixturesFolder ?? "./src/fixtures",
278
- downloadsFolder: pluginConfig.outputPath ?? buildOutputPath("downloads"),
279
- logsFolder: pluginConfig.logsFolder ?? buildOutputPath("logs"),
280
- chromeWebSecurity: false,
281
- reporter: "junit",
282
- reporterOptions: {
283
- mochaFile: buildOutputPath("results-[hash].xml"),
284
- },
285
- specPattern: projectConfig.specPattern ?? "src/e2e/**/*.e2e.{js,jsx,ts,tsx}",
286
- supportFile: projectConfig.supportFile ?? "src/support/e2e.ts",
287
- nxRoot,
288
- fileServerFolder: ".",
289
- video: true,
290
- trashAssetsBeforeRuns: false, // Don't delete videos from previous test runs (important for sequential runs)
291
- videosFolder: pluginConfig.videosFolder ?? buildOutputPath("videos"),
292
- screenshotsFolder: pluginConfig.screenshotsFolder ?? buildOutputPath("screenshots"),
293
- env: {
294
- hars_folders: pluginConfig.harFolder ?? buildOutputPath("hars"),
295
- CYPRESS_RUN_UNIQUE_ID: crypto.randomUUID(),
296
- },
297
- };
298
- };
299
- /**
300
- * Sets up Cypress plugins for logging, tasks, and HAR generation.
301
- * Configures terminal reporting, XLSX parsing, and HTTP archive recording.
302
- */
303
- const setupPlugins = (on, config, logWriter, installHarGenerator) => {
304
- /* ---- BEGIN: Logging setup ---- */
305
- // Read options https://github.com/archfz/cypress-terminal-report
306
- const options = {
307
- printLogsToFile: "always", // Ensures logs are always printed to a file
308
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
309
- collectTestLogs: (context, logs) => {
310
- const testName = fileNameBuilder.fileNameBuilder(context.test, context.state);
311
- createLogFile(config.nxRoot, config.logsFolder, testName, logs, logWriter);
312
- },
313
- };
314
- // eslint-disable-next-line @typescript-eslint/no-require-imports
315
- require("cypress-terminal-report/src/installLogsPrinter")(on, options);
316
- /* ---- END: Logging setup ---- */
317
- /* ---- BEGIN: Task setup ---- */
318
- on("task", {
319
- parseXlsx(filePath) {
320
- return new Promise((resolve, reject) => {
321
- try {
322
- const jsonData = nodeXlsx.parse(fs.readFileSync(filePath));
323
- resolve(jsonData);
324
- }
325
- catch (e) {
326
- reject(e);
327
- }
328
- });
329
- },
330
- fileExists(filename) {
331
- return fs.existsSync(filename);
332
- },
333
- });
334
- /* ---- END: Task setup ---- */
335
- /* ---- BEGIN: codeowner setup ---- */
336
- const codeowner = toShortTeamName(getCodeowner(config.projectRoot, config.nxRoot));
337
- config.env.codeowner = codeowner;
338
- /* ---- END: codeowner setup ---- */
339
- /* ---- BEGIN: HAR setup ---- */
340
- // Installing the HAR geneartor should happen last according to the documentation
341
- // https://github.com/NeuraLegion/cypress-har-generator?tab=readme-ov-file#setting-up-the-plugin
342
- installHarGenerator(on);
343
- /* ---- END: HAR setup ---- */
344
- return config;
345
- };
346
-
347
- exports.createLogFile = createLogFile;
348
- exports.defaultCypressConfig = defaultCypressConfig;
349
- exports.setupPlugins = setupPlugins;
350
- exports.writeFileWithPrettier = writeFileWithPrettier;
package/node.cjs.mjs DELETED
@@ -1,2 +0,0 @@
1
- export * from './node.cjs.js';
2
- export { _default as default } from './node.cjs.default.js';
package/node.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/node";
package/node.esm.js DELETED
@@ -1,327 +0,0 @@
1
- import fs, { writeFileSync, existsSync, readFileSync } from 'fs';
2
- import * as path from 'path';
3
- import path__default from 'path';
4
- import crypto from 'crypto';
5
- import { parse } from 'node-xlsx';
6
- import { f as fileNameBuilder } from './fileNameBuilder.esm.js';
7
-
8
- /* eslint-disable no-console */
9
- /**
10
- * Writes a file with Prettier formatting applied.
11
- * Automatically detects parser based on file extension.
12
- */
13
- const writeFileWithPrettier = async (nxRoot, filePath, content, writeOptions = { encoding: "utf-8" }, writer) => {
14
- const prettierConfigPath = path.join(nxRoot, ".prettierrc");
15
- const options = await writer
16
- .resolveConfig(prettierConfigPath)
17
- .catch(error => console.log("Prettier config error: ", error));
18
- if (!options) {
19
- throw new Error("Could not find prettier config");
20
- }
21
- if (filePath.endsWith("json")) {
22
- options.parser = "json";
23
- }
24
- else {
25
- options.parser = "typescript";
26
- }
27
- try {
28
- const prettySrc = await writer.format(content, options);
29
- writeFileSync(filePath, prettySrc, writeOptions);
30
- }
31
- catch (error) {
32
- console.error("Error in prettier.format:", error);
33
- }
34
- };
35
-
36
- const isNetworkCall = (log) => {
37
- return log.type === "cy:fetch" || log.type === "cy:request" || log.type === "cy:response" || log.type === "cy:xrh";
38
- };
39
- /**
40
- * Creates log files for Cypress test runs.
41
- * Generates separate files for all logs, errors, and network errors.
42
- */
43
- function createLogFile(nxRoot, logsPath, fileNameWithoutExtension, logs, logWriter) {
44
- if (!existsSync(logsPath)) {
45
- fs.mkdirSync(logsPath, { recursive: true });
46
- }
47
- const logFilePath = path__default.join(logsPath, fileNameWithoutExtension);
48
- writeFileWithPrettier(nxRoot, logFilePath + "-all.json", JSON.stringify(logs), { flag: "a" }, logWriter);
49
- const errorCmds = logs.filter(log => log.severity === "error" &&
50
- // This seems to be when apollo has cancelled requests it marks it as failed to fetch only on cypress ?!??
51
- // might be fixed by https://github.com/Trackunit/manager/pull/12917
52
- !log.message.includes("TypeError: Failed to fetch"));
53
- if (errorCmds.length > 0) {
54
- writeFileWithPrettier(nxRoot, logFilePath + "-errors.json", JSON.stringify(errorCmds), {
55
- flag: "a",
56
- }, logWriter);
57
- }
58
- const networkErrorsCmds = logs.filter(log => isNetworkCall(log) &&
59
- !log.message.includes("Status: 200") &&
60
- log.severity !== "success" &&
61
- !log.message.includes("sentry.io/api/") &&
62
- // This seems to be when apollo has cancelled requests it marks it as failed to fetch only on cypress ?!??
63
- !log.message.includes("TypeError: Failed to fetch"));
64
- if (networkErrorsCmds.length > 0) {
65
- writeFileWithPrettier(nxRoot, logFilePath + "-network-errors.json", JSON.stringify(networkErrorsCmds), {
66
- flag: "a",
67
- }, logWriter);
68
- }
69
- }
70
-
71
- /**
72
- * Parses lines from a CODEOWNERS‐style file into a mapping of patterns → owners.
73
- * Skips blank lines and comments (lines beginning with `#`).
74
- *
75
- * @param {string[]} lines - Each element is a line from your CODEOWNERS file.
76
- * @returns {Record<string, string>} An object whose keys are normalized path patterns (no leading/trailing slashes)
77
- * and whose values are the owner (e.g. a GitHub team handle).
78
- * @example
79
- * ```ts
80
- * const lines = [
81
- * "# Our CODEOWNERS",
82
- * "/src @team/backend",
83
- * "README.md @team/docs",
84
- * "", // blank lines ignored
85
- * "# end of file"
86
- * ];
87
- * const owners = parseCodeowners(lines);
88
- * // → { "src": "@team/backend", "README.md": "@team/docs" }
89
- * ```
90
- */
91
- const parseCodeowners = (lines) => {
92
- const patterns = {};
93
- for (const line of lines) {
94
- const trimmed = line.trim();
95
- if (!trimmed || trimmed.startsWith("#")) {
96
- continue;
97
- }
98
- const [pattern, owner] = trimmed.split(/\s+/, 2);
99
- if (pattern && owner) {
100
- const normalizedPattern = pattern.replace(/^\/+|\/+$/g, "");
101
- patterns[normalizedPattern] = owner;
102
- }
103
- }
104
- return patterns;
105
- };
106
- /**
107
- * Converts a full team handle (potentially namespaced and with platform suffix)
108
- * into its “short” team name.
109
- *
110
- * - Strips any leading `@org/` prefix
111
- * - Removes `-be` or `-fe` suffix if present
112
- *
113
- * @param {string} teamName - e.g. `"@trackunit/backend-be"` or `"@trackunit/frontend-fe"`
114
- * @returns {string} e.g. `"backend"` or `"frontend"`
115
- * @example
116
- * ```ts
117
- * toShortTeamName("@trackunit/backend-be"); // → "backend"
118
- * toShortTeamName("@trackunit/frontend-fe"); // → "frontend"
119
- * toShortTeamName("infra"); // → "infra"
120
- * ```
121
- */
122
- const toShortTeamName = (teamName) => {
123
- if (!teamName) {
124
- return undefined;
125
- }
126
- let shortName = teamName;
127
- if (teamName.startsWith("@")) {
128
- shortName = shortName.slice(shortName.indexOf("/") + 1);
129
- }
130
- if (shortName.endsWith("-be") || shortName.endsWith("-fe")) {
131
- shortName = shortName.slice(0, shortName.lastIndexOf("-"));
132
- }
133
- return shortName;
134
- };
135
- /**
136
- * Recursively looks up the CODEOWNER for a given file or directory path
137
- * by reading your workspace’s CODEOWNERS file.
138
- *
139
- * Walks up the directory tree until it finds a matching pattern. If no
140
- * deeper match is found but there is a `"."` entry, returns that.
141
- *
142
- * @param {string} currentPath - Absolute path to the file/directory you’re querying.
143
- * @param {string} workspaceRoot - Absolute path to your repo/workspace root.
144
- * @param {string} [codeownersFileName="TEAM_CODEOWNERS"] - Filename to read at the root.
145
- * @returns {string|undefined} The owner handle (e.g. `"@team/backend"`) or `undefined` if none found.
146
- * @example
147
- * ```ts
148
- * // Suppose your repo root has a TEAM_CODEOWNERS file containing:
149
- * // src @team/backend
150
- * // src/utils @team/utils
151
- * // . @team/root
152
- *
153
- * const owner1 = getCodeowner(
154
- * "/Users/alice/project/src/utils/helpers.ts",
155
- * "/Users/alice/project"
156
- * );
157
- * // → "@team/utils"
158
- *
159
- * const owner2 = getCodeowner(
160
- * "/Users/alice/project/other/file.txt",
161
- * "/Users/alice/project"
162
- * );
163
- * // → "@team/root" (falls back to the "." entry)
164
- * ```
165
- */
166
- const getCodeowner = (currentPath, workspaceRoot, codeownersFileName = "TEAM_CODEOWNERS") => {
167
- if (!workspaceRoot) {
168
- return undefined;
169
- }
170
- const codeownersPath = path__default.join(workspaceRoot, codeownersFileName);
171
- if (!fs.existsSync(codeownersPath)) {
172
- return undefined;
173
- }
174
- const codeownersLines = fs.readFileSync(codeownersPath, "utf8").split("\n");
175
- const codeowners = parseCodeowners(codeownersLines);
176
- let relPath = path__default
177
- .relative(workspaceRoot, currentPath)
178
- .replace(/\\/g, "/")
179
- .replace(/^\/+|\/+$/g, "");
180
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
181
- while (true) {
182
- const codeowner = codeowners[relPath];
183
- if (codeowner) {
184
- return codeowner;
185
- }
186
- const parent = path__default.posix.dirname(relPath);
187
- if ((parent === relPath || parent === ".") && codeowners["."]) {
188
- return codeowners["."];
189
- }
190
- if (parent === relPath || parent === ".") {
191
- break;
192
- }
193
- relPath = parent;
194
- }
195
- return undefined;
196
- };
197
-
198
- /**
199
- * Utility function to find NX workspace root by looking for nx.json or workspace.json.
200
- * This is more reliable than hardcoded relative paths and works from any directory.
201
- *
202
- * @param startDir Starting directory for the search (defaults to current working directory)
203
- * @returns {string} Absolute path to the workspace root
204
- * @throws Error if workspace root cannot be found
205
- */
206
- function findWorkspaceRoot(startDir = process.cwd()) {
207
- let currentDir = startDir;
208
- while (currentDir !== path__default.dirname(currentDir)) {
209
- if (existsSync(path__default.join(currentDir, "nx.json")) || existsSync(path__default.join(currentDir, "workspace.json"))) {
210
- return currentDir;
211
- }
212
- currentDir = path__default.dirname(currentDir);
213
- }
214
- throw new Error("Could not find NX workspace root (nx.json or workspace.json not found)");
215
- }
216
- /**
217
- * Creates default Cypress configuration for E2E testing.
218
- * Supports both legacy string parameter (dirname) and new options object for backward compatibility.
219
- */
220
- const defaultCypressConfig = optionsOrDirname => {
221
- // Support both old API (string/undefined) and new API (object) for backward compatibility
222
- const options = typeof optionsOrDirname === "object" ? optionsOrDirname : {};
223
- const { nxRoot: providedNxRoot, outputDirOverride, projectConfig = {}, behaviorConfig = {}, pluginConfig = {}, } = options;
224
- // Use NX workspace detection for reliable root finding
225
- const nxRoot = providedNxRoot ?? findWorkspaceRoot();
226
- // For output path calculation, determine the relative path from caller to workspace root
227
- const callerDirname = typeof optionsOrDirname === "string" ? optionsOrDirname : process.cwd();
228
- const relativePath = path__default.relative(nxRoot, callerDirname);
229
- const dotsToNxRoot = relativePath
230
- .split(path__default.sep)
231
- .map(_ => "..")
232
- .join("/");
233
- const envOutputDirOverride = process.env.NX_E2E_OUTPUT_DIR || outputDirOverride;
234
- // Function to build output paths that respects the override
235
- const buildOutputPath = (subPath) => {
236
- if (envOutputDirOverride) {
237
- return path__default.join(dotsToNxRoot, envOutputDirOverride, subPath);
238
- }
239
- return `${dotsToNxRoot}/dist/cypress/${relativePath}/${subPath}`;
240
- };
241
- return {
242
- projectId: projectConfig.projectId ?? process.env.CYPRESS_PROJECT_ID,
243
- defaultCommandTimeout: behaviorConfig.defaultCommandTimeout ?? 20000,
244
- execTimeout: behaviorConfig.execTimeout ?? 300000,
245
- taskTimeout: behaviorConfig.taskTimeout ?? 35000,
246
- pageLoadTimeout: behaviorConfig.pageLoadTimeout ?? 35000,
247
- // setting to undefined makes no effect on the baseUrl so child projects can override it
248
- baseUrl: process.env.NX_FEATURE_BRANCH_BASE_URL ?? undefined,
249
- // This avoid issues with SRI hashes changing
250
- modifyObstructiveCode: false,
251
- requestTimeout: behaviorConfig.requestTimeout ?? 25000,
252
- responseTimeout: behaviorConfig.responseTimeout ?? 150000,
253
- retries: behaviorConfig.retries ?? {
254
- runMode: 3,
255
- openMode: 0,
256
- },
257
- fixturesFolder: projectConfig.fixturesFolder ?? "./src/fixtures",
258
- downloadsFolder: pluginConfig.outputPath ?? buildOutputPath("downloads"),
259
- logsFolder: pluginConfig.logsFolder ?? buildOutputPath("logs"),
260
- chromeWebSecurity: false,
261
- reporter: "junit",
262
- reporterOptions: {
263
- mochaFile: buildOutputPath("results-[hash].xml"),
264
- },
265
- specPattern: projectConfig.specPattern ?? "src/e2e/**/*.e2e.{js,jsx,ts,tsx}",
266
- supportFile: projectConfig.supportFile ?? "src/support/e2e.ts",
267
- nxRoot,
268
- fileServerFolder: ".",
269
- video: true,
270
- trashAssetsBeforeRuns: false, // Don't delete videos from previous test runs (important for sequential runs)
271
- videosFolder: pluginConfig.videosFolder ?? buildOutputPath("videos"),
272
- screenshotsFolder: pluginConfig.screenshotsFolder ?? buildOutputPath("screenshots"),
273
- env: {
274
- hars_folders: pluginConfig.harFolder ?? buildOutputPath("hars"),
275
- CYPRESS_RUN_UNIQUE_ID: crypto.randomUUID(),
276
- },
277
- };
278
- };
279
- /**
280
- * Sets up Cypress plugins for logging, tasks, and HAR generation.
281
- * Configures terminal reporting, XLSX parsing, and HTTP archive recording.
282
- */
283
- const setupPlugins = (on, config, logWriter, installHarGenerator) => {
284
- /* ---- BEGIN: Logging setup ---- */
285
- // Read options https://github.com/archfz/cypress-terminal-report
286
- const options = {
287
- printLogsToFile: "always", // Ensures logs are always printed to a file
288
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
289
- collectTestLogs: (context, logs) => {
290
- const testName = fileNameBuilder(context.test, context.state);
291
- createLogFile(config.nxRoot, config.logsFolder, testName, logs, logWriter);
292
- },
293
- };
294
- // eslint-disable-next-line @typescript-eslint/no-require-imports
295
- require("cypress-terminal-report/src/installLogsPrinter")(on, options);
296
- /* ---- END: Logging setup ---- */
297
- /* ---- BEGIN: Task setup ---- */
298
- on("task", {
299
- parseXlsx(filePath) {
300
- return new Promise((resolve, reject) => {
301
- try {
302
- const jsonData = parse(readFileSync(filePath));
303
- resolve(jsonData);
304
- }
305
- catch (e) {
306
- reject(e);
307
- }
308
- });
309
- },
310
- fileExists(filename) {
311
- return existsSync(filename);
312
- },
313
- });
314
- /* ---- END: Task setup ---- */
315
- /* ---- BEGIN: codeowner setup ---- */
316
- const codeowner = toShortTeamName(getCodeowner(config.projectRoot, config.nxRoot));
317
- config.env.codeowner = codeowner;
318
- /* ---- END: codeowner setup ---- */
319
- /* ---- BEGIN: HAR setup ---- */
320
- // Installing the HAR geneartor should happen last according to the documentation
321
- // https://github.com/NeuraLegion/cypress-har-generator?tab=readme-ov-file#setting-up-the-plugin
322
- installHarGenerator(on);
323
- /* ---- END: HAR setup ---- */
324
- return config;
325
- };
326
-
327
- export { createLogFile, defaultCypressConfig, setupPlugins, writeFileWithPrettier };
package/src/node.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from "./plugins/createLogFile";
2
- export * from "./plugins/defaultPlugins";
3
- export * from "./plugins/writeFileWithPrettier";