codeceptjs 4.0.1-beta.23 → 4.0.1-beta.26

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/lib/output.js CHANGED
@@ -222,12 +222,10 @@ const output = {
222
222
  /**
223
223
  * @param {Mocha.Test} test
224
224
  */
225
-
226
225
  started(test) {
227
226
  if (outputLevel < 1) return
228
227
  print(` ${colors.dim.bold('Scenario()')}`)
229
228
  },
230
-
231
229
  /**
232
230
  * @param {Mocha.Test} test
233
231
  */
@@ -273,10 +271,12 @@ const output = {
273
271
  },
274
272
 
275
273
  /**
274
+ * Prints the stats of a test run to the console.
276
275
  * @param {number} passed
277
276
  * @param {number} failed
278
277
  * @param {number} skipped
279
278
  * @param {number|string} duration
279
+ * @param {number} [failedHooks]
280
280
  */
281
281
  result(passed, failed, skipped, duration, failedHooks = 0) {
282
282
  let style = colors.bgGreen
@@ -4,10 +4,10 @@ import path from 'path'
4
4
  /**
5
5
  * Transpile TypeScript files to ES modules with CommonJS shim support
6
6
  * Handles recursive transpilation of imported TypeScript files
7
- *
7
+ *
8
8
  * @param {string} mainFilePath - Path to the main TypeScript file to transpile
9
9
  * @param {object} typescript - TypeScript compiler instance
10
- * @returns {Promise<{tempFile: string, allTempFiles: string[]}>} - Main temp file and all temp files created
10
+ * @returns {Promise<{tempFile: string, allTempFiles: string[], fileMapping: any}>} - Main temp file and all temp files created
11
11
  */
12
12
  export async function transpileTypeScript(mainFilePath, typescript) {
13
13
  const { transpile } = typescript
@@ -18,7 +18,7 @@ export async function transpileTypeScript(mainFilePath, typescript) {
18
18
  */
19
19
  const transpileTS = (filePath) => {
20
20
  const tsContent = fs.readFileSync(filePath, 'utf8')
21
-
21
+
22
22
  // Transpile TypeScript to JavaScript with ES module output
23
23
  let jsContent = transpile(tsContent, {
24
24
  module: 99, // ModuleKind.ESNext
@@ -29,16 +29,16 @@ export async function transpileTypeScript(mainFilePath, typescript) {
29
29
  suppressOutputPathCheck: true,
30
30
  skipLibCheck: true,
31
31
  })
32
-
32
+
33
33
  // Check if the code uses CommonJS globals
34
34
  const usesCommonJSGlobals = /__dirname|__filename/.test(jsContent)
35
35
  const usesRequire = /\brequire\s*\(/.test(jsContent)
36
36
  const usesModuleExports = /\b(module\.exports|exports\.)/.test(jsContent)
37
-
37
+
38
38
  if (usesCommonJSGlobals || usesRequire || usesModuleExports) {
39
39
  // Inject ESM equivalents at the top of the file
40
40
  let esmGlobals = ''
41
-
41
+
42
42
  if (usesRequire || usesModuleExports) {
43
43
  // IMPORTANT: Use the original .ts file path as the base for require()
44
44
  // This ensures dynamic require() calls work with relative paths from the original file location
@@ -81,7 +81,7 @@ const exports = module.exports;
81
81
 
82
82
  `
83
83
  }
84
-
84
+
85
85
  if (usesCommonJSGlobals) {
86
86
  // For __dirname and __filename, also use the original file path
87
87
  const originalFileUrl = `file://${filePath.replace(/\\/g, '/')}`
@@ -92,48 +92,48 @@ const __dirname = __dirname_fn(__filename);
92
92
 
93
93
  `
94
94
  }
95
-
95
+
96
96
  jsContent = esmGlobals + jsContent
97
-
97
+
98
98
  // If module.exports is used, we need to export it as default
99
99
  if (usesModuleExports) {
100
100
  jsContent += `\nexport default module.exports;\n`
101
101
  }
102
102
  }
103
-
103
+
104
104
  return jsContent
105
105
  }
106
-
106
+
107
107
  // Create a map to track transpiled files
108
108
  const transpiledFiles = new Map()
109
109
  const baseDir = path.dirname(mainFilePath)
110
-
110
+
111
111
  // Recursive function to transpile a file and all its TypeScript dependencies
112
112
  const transpileFileAndDeps = (filePath) => {
113
113
  // Already transpiled, skip
114
114
  if (transpiledFiles.has(filePath)) {
115
115
  return
116
116
  }
117
-
117
+
118
118
  // Transpile this file
119
119
  let jsContent = transpileTS(filePath)
120
-
120
+
121
121
  // Find all relative TypeScript imports in this file
122
122
  const importRegex = /from\s+['"](\..+?)(?:\.ts)?['"]/g
123
123
  let match
124
124
  const imports = []
125
-
125
+
126
126
  while ((match = importRegex.exec(jsContent)) !== null) {
127
127
  imports.push(match[1])
128
128
  }
129
-
129
+
130
130
  // Get the base directory for this file
131
131
  const fileBaseDir = path.dirname(filePath)
132
-
132
+
133
133
  // Recursively transpile each imported TypeScript file
134
134
  for (const relativeImport of imports) {
135
135
  let importedPath = path.resolve(fileBaseDir, relativeImport)
136
-
136
+
137
137
  // Handle .js extensions that might actually be .ts files
138
138
  if (importedPath.endsWith('.js')) {
139
139
  const tsVersion = importedPath.replace(/\.js$/, '.ts')
@@ -141,12 +141,12 @@ const __dirname = __dirname_fn(__filename);
141
141
  importedPath = tsVersion
142
142
  }
143
143
  }
144
-
144
+
145
145
  // Check for standard module extensions to determine if we should try adding .ts
146
146
  const ext = path.extname(importedPath)
147
147
  const standardExtensions = ['.js', '.mjs', '.cjs', '.json', '.node']
148
148
  const hasStandardExtension = standardExtensions.includes(ext.toLowerCase())
149
-
149
+
150
150
  // If it doesn't end with .ts and doesn't have a standard extension, try adding .ts
151
151
  if (!importedPath.endsWith('.ts') && !hasStandardExtension) {
152
152
  const tsPath = importedPath + '.ts'
@@ -161,20 +161,20 @@ const __dirname = __dirname_fn(__filename);
161
161
  }
162
162
  }
163
163
  }
164
-
164
+
165
165
  // If it's a TypeScript file, recursively transpile it and its dependencies
166
166
  if (importedPath.endsWith('.ts') && fs.existsSync(importedPath)) {
167
167
  transpileFileAndDeps(importedPath)
168
168
  }
169
169
  }
170
-
170
+
171
171
  // After all dependencies are transpiled, rewrite imports in this file
172
172
  jsContent = jsContent.replace(
173
173
  /from\s+['"](\..+?)(?:\.ts)?['"]/g,
174
174
  (match, importPath) => {
175
175
  let resolvedPath = path.resolve(fileBaseDir, importPath)
176
176
  const originalExt = path.extname(importPath)
177
-
177
+
178
178
  // Handle .js extension that might be .ts
179
179
  if (resolvedPath.endsWith('.js')) {
180
180
  const tsVersion = resolvedPath.replace(/\.js$/, '.ts')
@@ -190,10 +190,10 @@ const __dirname = __dirname_fn(__filename);
190
190
  // Keep .js extension as-is (might be a real .js file)
191
191
  return match
192
192
  }
193
-
193
+
194
194
  // Try with .ts extension
195
195
  const tsPath = resolvedPath.endsWith('.ts') ? resolvedPath : resolvedPath + '.ts'
196
-
196
+
197
197
  // If we transpiled this file, use the temp file
198
198
  if (transpiledFiles.has(tsPath)) {
199
199
  const tempFile = transpiledFiles.get(tsPath)
@@ -204,7 +204,7 @@ const __dirname = __dirname_fn(__filename);
204
204
  }
205
205
  return `from '${relPath}'`
206
206
  }
207
-
207
+
208
208
  // If the import doesn't have a standard module extension (.js, .mjs, .cjs, .json)
209
209
  // add .js for ESM compatibility
210
210
  // This handles cases where:
@@ -212,32 +212,59 @@ const __dirname = __dirname_fn(__filename);
212
212
  // 2. Import has a non-standard extension that's part of the name (e.g., "./abstract.helper")
213
213
  const standardExtensions = ['.js', '.mjs', '.cjs', '.json', '.node']
214
214
  const hasStandardExtension = standardExtensions.includes(originalExt.toLowerCase())
215
-
215
+
216
216
  if (!hasStandardExtension) {
217
217
  return match.replace(importPath, importPath + '.js')
218
218
  }
219
-
219
+
220
220
  // Otherwise, keep the import as-is
221
221
  return match
222
222
  }
223
223
  )
224
-
224
+
225
225
  // Write the transpiled file with updated imports
226
226
  const tempFile = filePath.replace(/\.ts$/, '.temp.mjs')
227
227
  fs.writeFileSync(tempFile, jsContent)
228
228
  transpiledFiles.set(filePath, tempFile)
229
229
  }
230
-
230
+
231
231
  // Start recursive transpilation from the main file
232
232
  transpileFileAndDeps(mainFilePath)
233
-
233
+
234
234
  // Get the main transpiled file
235
235
  const tempJsFile = transpiledFiles.get(mainFilePath)
236
-
236
+
237
237
  // Store all temp files for cleanup
238
238
  const allTempFiles = Array.from(transpiledFiles.values())
239
-
240
- return { tempFile: tempJsFile, allTempFiles }
239
+
240
+ return { tempFile: tempJsFile, allTempFiles, fileMapping: transpiledFiles }
241
+ }
242
+
243
+ /**
244
+ * Map error stack traces from temp .mjs files back to original .ts files
245
+ * @param {Error} error - The error object to fix
246
+ * @param {Map<string, string>} fileMapping - Map of original .ts files to temp .mjs files
247
+ * @returns {Error} - Error with fixed stack trace
248
+ */
249
+ export function fixErrorStack(error, fileMapping) {
250
+ if (!error.stack || !fileMapping) return error
251
+
252
+ let stack = error.stack
253
+
254
+ // Create reverse mapping (temp.mjs -> original.ts)
255
+ const reverseMap = new Map()
256
+ for (const [tsFile, mjsFile] of fileMapping.entries()) {
257
+ reverseMap.set(mjsFile, tsFile)
258
+ }
259
+
260
+ // Replace all temp.mjs references with original .ts files
261
+ for (const [mjsFile, tsFile] of reverseMap.entries()) {
262
+ const mjsPattern = mjsFile.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
263
+ stack = stack.replace(new RegExp(mjsPattern, 'g'), tsFile)
264
+ }
265
+
266
+ error.stack = stack
267
+ return error
241
268
  }
242
269
 
243
270
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "4.0.1-beta.23",
3
+ "version": "4.0.1-beta.26",
4
4
  "type": "module",
5
5
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
6
6
  "keywords": [
@@ -88,8 +88,8 @@
88
88
  "@codeceptjs/configure": "1.0.6",
89
89
  "@codeceptjs/helper": "2.0.4",
90
90
  "@cucumber/cucumber-expressions": "18",
91
- "@cucumber/gherkin": "37.0.0",
92
- "@cucumber/messages": "31.0.0",
91
+ "@cucumber/gherkin": "37.0.1",
92
+ "@cucumber/messages": "31.1.0",
93
93
  "@xmldom/xmldom": "0.9.8",
94
94
  "acorn": "8.15.0",
95
95
  "ai": "^5.0.60",
@@ -138,15 +138,15 @@
138
138
  "@codeceptjs/expect-helper": "^1.0.2",
139
139
  "@codeceptjs/mock-request": "0.3.1",
140
140
  "@eslint/eslintrc": "3.3.1",
141
- "@eslint/js": "9.36.0",
141
+ "@eslint/js": "9.39.2",
142
142
  "@faker-js/faker": "9.8.0",
143
- "@inquirer/testing": "^2.1.49",
143
+ "@inquirer/testing": "^3.0.3",
144
144
  "@pollyjs/adapter-puppeteer": "6.0.6",
145
145
  "@pollyjs/core": "6.0.6",
146
146
  "@testomatio/reporter": "^2.3.1",
147
147
  "@types/chai": "5.2.3",
148
148
  "@types/inquirer": "9.0.9",
149
- "@types/node": "^24.9.2",
149
+ "@types/node": "^25.0.3",
150
150
  "@wdio/sauce-service": "9.12.5",
151
151
  "@wdio/selenium-standalone-service": "8.15.0",
152
152
  "@wdio/utils": "9.21.0",
@@ -186,9 +186,9 @@
186
186
  "tsx": "^4.19.2",
187
187
  "typedoc": "0.28.15",
188
188
  "typedoc-plugin-markdown": "4.9.0",
189
- "typescript": "5.8.3",
189
+ "typescript": "5.9.3",
190
190
  "wdio-docker-service": "3.2.1",
191
- "webdriverio": "9.12.5",
191
+ "webdriverio": "9.23.0",
192
192
  "xml2js": "0.6.2",
193
193
  "xpath": "0.0.34"
194
194
  },
@@ -519,7 +519,7 @@ declare namespace CodeceptJS {
519
519
  retry(retries?: number): HookConfig
520
520
  }
521
521
 
522
- function addStep(step: string, fn: Function): Promise<void>
522
+ function addStep(step: string | RegExp, fn: Function): Promise<void>
523
523
  }
524
524
 
525
525
  type TryTo = <T>(fn: () => Promise<T> | T) => Promise<T | false>