codeceptjs 4.0.1-beta.2 → 4.0.1-beta.20
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/bin/codecept.js +2 -2
- package/lib/actor.js +12 -8
- package/lib/command/definitions.js +8 -3
- package/lib/container.js +65 -17
- package/lib/helper/GraphQL.js +6 -4
- package/lib/helper/JSONResponse.js +3 -4
- package/lib/helper/Playwright.js +97 -113
- package/lib/helper/REST.js +13 -8
- package/lib/helper/extras/PlaywrightLocator.js +13 -34
- package/lib/listener/config.js +11 -3
- package/lib/locator.js +69 -29
- package/lib/mocha/factory.js +2 -27
- package/lib/step/meta.js +18 -1
- package/lib/utils/loaderCheck.js +13 -3
- package/lib/utils/typescript.js +22 -2
- package/lib/workers.js +36 -41
- package/package.json +16 -16
- package/typings/promiseBasedTypes.d.ts +3974 -5520
- package/typings/types.d.ts +4146 -5821
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -52
package/bin/codecept.js
CHANGED
|
@@ -174,7 +174,7 @@ program
|
|
|
174
174
|
.option('-R, --reporter <name>', 'specify the reporter to use')
|
|
175
175
|
.option('-S, --sort', 'sort test files')
|
|
176
176
|
.option('-b, --bail', 'bail after first test failure')
|
|
177
|
-
.option('
|
|
177
|
+
.option('--inspec', "enable node's debugger, synonym for node --debug")
|
|
178
178
|
.option('-g, --grep <pattern>', 'only run tests matching <pattern>')
|
|
179
179
|
.option('-f, --fgrep <string>', 'only run tests containing <string>')
|
|
180
180
|
.option('-i, --invert', 'inverts --grep and --fgrep matches')
|
|
@@ -276,7 +276,7 @@ program
|
|
|
276
276
|
.option('-R, --reporter <name>', 'specify the reporter to use')
|
|
277
277
|
.option('-S, --sort', 'sort test files')
|
|
278
278
|
.option('-b, --bail', 'bail after first test failure')
|
|
279
|
-
.option('
|
|
279
|
+
.option('--inspect', "enable node's debugger, synonym for node --debug")
|
|
280
280
|
.option('-g, --grep <pattern>', 'only run tests matching <pattern>')
|
|
281
281
|
.option('-f, --fgrep <string>', 'only run tests containing <string>')
|
|
282
282
|
.option('-i, --invert', 'inverts --grep and --fgrep matches')
|
package/lib/actor.js
CHANGED
|
@@ -75,7 +75,8 @@ export default function (obj = {}, container) {
|
|
|
75
75
|
if (!container) {
|
|
76
76
|
container = Container
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
|
|
79
|
+
// Get existing actor or create a new one
|
|
79
80
|
const actor = container.actor() || new Actor()
|
|
80
81
|
|
|
81
82
|
// load all helpers once container initialized
|
|
@@ -111,14 +112,17 @@ export default function (obj = {}, container) {
|
|
|
111
112
|
}
|
|
112
113
|
})
|
|
113
114
|
|
|
114
|
-
container.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
// Update container.support.I to ensure it has the latest actor reference
|
|
116
|
+
if (!container.actor() || container.actor() !== actor) {
|
|
117
|
+
container.append({
|
|
118
|
+
support: {
|
|
119
|
+
I: actor,
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
}
|
|
119
123
|
})
|
|
120
|
-
|
|
121
|
-
// add custom steps from actor
|
|
124
|
+
|
|
125
|
+
// add custom steps from actor immediately
|
|
122
126
|
Object.keys(obj).forEach(key => {
|
|
123
127
|
const ms = new MetaStep('I', key)
|
|
124
128
|
ms.setContext(actor)
|
|
@@ -41,7 +41,7 @@ const getDefinitionsFileContent = ({ hasCustomHelper, hasCustomStepsFile, helper
|
|
|
41
41
|
|
|
42
42
|
const importPathsFragment = importPaths.join('\n')
|
|
43
43
|
const supportObjectsTypeFragment = convertMapToType(supportObject)
|
|
44
|
-
const methodsTypeFragment = helperNames.length > 0 ? `interface Methods extends ${helperNames.join(', ')} {}` : ''
|
|
44
|
+
const methodsTypeFragment = helperNames.length > 0 ? `interface Methods extends ${helperNames.join(', ')} {}` : 'interface Methods {}'
|
|
45
45
|
const translatedActionsFragment = JSON.stringify(translations.vocabulary.actions, null, 2)
|
|
46
46
|
|
|
47
47
|
return generateDefinitionsContent({
|
|
@@ -239,8 +239,13 @@ function getImportString(testsPath, targetFolderPath, pathsToType, pathsToValue)
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
for (const name in pathsToValue) {
|
|
242
|
-
const
|
|
243
|
-
|
|
242
|
+
const originalPath = pathsToValue[name]
|
|
243
|
+
const relativePath = getPath(originalPath, targetFolderPath, testsPath)
|
|
244
|
+
if (originalPath.endsWith('.js') || originalPath.endsWith('.ts')) {
|
|
245
|
+
importStrings.push(`type ${name} = InstanceType<typeof import('${relativePath}').default>;`)
|
|
246
|
+
} else {
|
|
247
|
+
importStrings.push(`type ${name} = import('${relativePath}');`)
|
|
248
|
+
}
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
return importStrings
|
package/lib/container.js
CHANGED
|
@@ -22,6 +22,7 @@ let container = {
|
|
|
22
22
|
helpers: {},
|
|
23
23
|
support: {},
|
|
24
24
|
proxySupport: {},
|
|
25
|
+
proxySupportConfig: {}, // Track config used to create proxySupport
|
|
25
26
|
plugins: {},
|
|
26
27
|
actor: null,
|
|
27
28
|
/**
|
|
@@ -67,14 +68,15 @@ class Container {
|
|
|
67
68
|
container.support = {}
|
|
68
69
|
container.helpers = await createHelpers(config.helpers || {})
|
|
69
70
|
container.translation = await loadTranslation(config.translation || null, config.vocabularies || [])
|
|
70
|
-
container.
|
|
71
|
+
container.proxySupportConfig = config.include || {}
|
|
72
|
+
container.proxySupport = createSupportObjects(container.proxySupportConfig)
|
|
71
73
|
container.plugins = await createPlugins(config.plugins || {}, opts)
|
|
72
74
|
container.result = new Result()
|
|
73
75
|
|
|
74
76
|
// Preload includes (so proxies can expose real objects synchronously)
|
|
75
77
|
const includes = config.include || {}
|
|
76
78
|
|
|
77
|
-
//
|
|
79
|
+
// Check if custom I is provided
|
|
78
80
|
if (Object.prototype.hasOwnProperty.call(includes, 'I')) {
|
|
79
81
|
try {
|
|
80
82
|
const mod = includes.I
|
|
@@ -89,7 +91,7 @@ class Container {
|
|
|
89
91
|
throw new Error(`Could not include object I: ${e.message}`)
|
|
90
92
|
}
|
|
91
93
|
} else {
|
|
92
|
-
// Create default actor
|
|
94
|
+
// Create default actor - this sets up the callback in asyncHelperPromise
|
|
93
95
|
createActor()
|
|
94
96
|
}
|
|
95
97
|
|
|
@@ -110,6 +112,9 @@ class Container {
|
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
// Wait for all async helpers to finish loading and populate the actor
|
|
116
|
+
await asyncHelperPromise
|
|
117
|
+
|
|
113
118
|
if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant
|
|
114
119
|
if (config.gherkin) await loadGherkinStepsAsync(config.gherkin.steps || [])
|
|
115
120
|
if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts
|
|
@@ -204,8 +209,10 @@ class Container {
|
|
|
204
209
|
|
|
205
210
|
// If new support objects are added, update the proxy support
|
|
206
211
|
if (newContainer.support) {
|
|
207
|
-
|
|
208
|
-
container.
|
|
212
|
+
// Merge the new support config with existing config
|
|
213
|
+
container.proxySupportConfig = { ...container.proxySupportConfig, ...newContainer.support }
|
|
214
|
+
// Recreate the proxy with merged config
|
|
215
|
+
container.proxySupport = createSupportObjects(container.proxySupportConfig)
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
debug('appended', JSON.stringify(newContainer).slice(0, 300))
|
|
@@ -221,6 +228,7 @@ class Container {
|
|
|
221
228
|
static async clear(newHelpers = {}, newSupport = {}, newPlugins = {}) {
|
|
222
229
|
container.helpers = newHelpers
|
|
223
230
|
container.translation = await loadTranslation()
|
|
231
|
+
container.proxySupportConfig = newSupport
|
|
224
232
|
container.proxySupport = createSupportObjects(newSupport)
|
|
225
233
|
container.plugins = newPlugins
|
|
226
234
|
container.sharedKeys = new Set() // Clear shared keys
|
|
@@ -347,16 +355,17 @@ async function createHelpers(config) {
|
|
|
347
355
|
}
|
|
348
356
|
}
|
|
349
357
|
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
+
// Don't await here - let Container.create() handle the await
|
|
359
|
+
// This allows actor callbacks to be registered before resolution
|
|
360
|
+
asyncHelperPromise = asyncHelperPromise.then(async () => {
|
|
361
|
+
// Call _init on all helpers after they're all loaded
|
|
362
|
+
for (const name in helpers) {
|
|
363
|
+
if (helpers[name]._init) {
|
|
364
|
+
await helpers[name]._init()
|
|
365
|
+
debug(`helper ${name} _init() called`)
|
|
366
|
+
}
|
|
358
367
|
}
|
|
359
|
-
}
|
|
368
|
+
})
|
|
360
369
|
|
|
361
370
|
return helpers
|
|
362
371
|
}
|
|
@@ -389,20 +398,52 @@ async function requireHelperFromModule(helperName, config, HelperClass) {
|
|
|
389
398
|
throw err
|
|
390
399
|
}
|
|
391
400
|
} else {
|
|
401
|
+
// Handle TypeScript files
|
|
402
|
+
let importPath = moduleName
|
|
403
|
+
let tempJsFile = null
|
|
404
|
+
const ext = path.extname(moduleName)
|
|
405
|
+
|
|
406
|
+
if (ext === '.ts') {
|
|
407
|
+
try {
|
|
408
|
+
// Use the TypeScript transpilation utility
|
|
409
|
+
const typescript = await import('typescript')
|
|
410
|
+
const { tempFile, allTempFiles } = await transpileTypeScript(importPath, typescript)
|
|
411
|
+
|
|
412
|
+
debug(`Transpiled TypeScript helper: ${importPath} -> ${tempFile}`)
|
|
413
|
+
|
|
414
|
+
importPath = tempFile
|
|
415
|
+
tempJsFile = allTempFiles
|
|
416
|
+
} catch (tsError) {
|
|
417
|
+
throw new Error(`Failed to load TypeScript helper ${importPath}: ${tsError.message}. Make sure 'typescript' package is installed.`)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
392
421
|
// check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName.
|
|
393
422
|
try {
|
|
394
423
|
// Try dynamic import for both CommonJS and ESM modules
|
|
395
|
-
const mod = await import(
|
|
424
|
+
const mod = await import(importPath)
|
|
396
425
|
if (!mod && !mod.default) {
|
|
397
426
|
throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`)
|
|
398
427
|
}
|
|
399
428
|
HelperClass = mod.default || mod
|
|
429
|
+
|
|
430
|
+
// Clean up temp files if created
|
|
431
|
+
if (tempJsFile) {
|
|
432
|
+
const filesToClean = Array.isArray(tempJsFile) ? tempJsFile : [tempJsFile]
|
|
433
|
+
cleanupTempFiles(filesToClean)
|
|
434
|
+
}
|
|
400
435
|
} catch (err) {
|
|
436
|
+
// Clean up temp files before rethrowing
|
|
437
|
+
if (tempJsFile) {
|
|
438
|
+
const filesToClean = Array.isArray(tempJsFile) ? tempJsFile : [tempJsFile]
|
|
439
|
+
cleanupTempFiles(filesToClean)
|
|
440
|
+
}
|
|
441
|
+
|
|
401
442
|
if (err.code === 'ERR_REQUIRE_ESM' || (err.message && err.message.includes('ES module'))) {
|
|
402
443
|
// This is an ESM module, use dynamic import
|
|
403
444
|
try {
|
|
404
445
|
const pathModule = await import('path')
|
|
405
|
-
const absolutePath = pathModule.default.resolve(
|
|
446
|
+
const absolutePath = pathModule.default.resolve(importPath)
|
|
406
447
|
const mod = await import(absolutePath)
|
|
407
448
|
HelperClass = mod.default || mod
|
|
408
449
|
debug(`helper ${helperName} loaded via ESM import`)
|
|
@@ -531,10 +572,17 @@ function createSupportObjects(config) {
|
|
|
531
572
|
return [...new Set([...keys, ...container.sharedKeys])]
|
|
532
573
|
},
|
|
533
574
|
getOwnPropertyDescriptor(target, prop) {
|
|
575
|
+
// For destructuring to work, we need to return the actual value from the getter
|
|
576
|
+
let value
|
|
577
|
+
if (container.sharedKeys.has(prop) && prop in container.support) {
|
|
578
|
+
value = container.support[prop]
|
|
579
|
+
} else {
|
|
580
|
+
value = lazyLoad(prop)
|
|
581
|
+
}
|
|
534
582
|
return {
|
|
535
583
|
enumerable: true,
|
|
536
584
|
configurable: true,
|
|
537
|
-
value:
|
|
585
|
+
value: value,
|
|
538
586
|
}
|
|
539
587
|
},
|
|
540
588
|
get(target, key) {
|
package/lib/helper/GraphQL.js
CHANGED
|
@@ -45,6 +45,8 @@ class GraphQL extends Helper {
|
|
|
45
45
|
timeout: 10000,
|
|
46
46
|
defaultHeaders: {},
|
|
47
47
|
endpoint: '',
|
|
48
|
+
onRequest: null,
|
|
49
|
+
onResponse: null,
|
|
48
50
|
}
|
|
49
51
|
this.options = Object.assign(this.options, config)
|
|
50
52
|
this.headers = { ...this.options.defaultHeaders }
|
|
@@ -87,8 +89,8 @@ class GraphQL extends Helper {
|
|
|
87
89
|
|
|
88
90
|
request.headers = { ...this.headers, ...request.headers }
|
|
89
91
|
|
|
90
|
-
if (this.
|
|
91
|
-
await this.
|
|
92
|
+
if (this.options.onRequest) {
|
|
93
|
+
await this.options.onRequest(request)
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
this.debugSection('Request', JSON.stringify(request))
|
|
@@ -102,8 +104,8 @@ class GraphQL extends Helper {
|
|
|
102
104
|
response = err.response
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
if (this.
|
|
106
|
-
await this.
|
|
107
|
+
if (this.options.onResponse) {
|
|
108
|
+
await this.options.onResponse(response)
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
this.debugSection('Response', JSON.stringify(response.data))
|
|
@@ -72,8 +72,8 @@ class JSONResponse extends Helper {
|
|
|
72
72
|
if (!this.helpers[this.options.requestHelper]) {
|
|
73
73
|
throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`)
|
|
74
74
|
}
|
|
75
|
-
const origOnResponse = this.helpers[this.options.requestHelper].
|
|
76
|
-
this.helpers[this.options.requestHelper].
|
|
75
|
+
const origOnResponse = this.helpers[this.options.requestHelper].options.onResponse
|
|
76
|
+
this.helpers[this.options.requestHelper].options.onResponse = response => {
|
|
77
77
|
this.response = response
|
|
78
78
|
if (typeof origOnResponse === 'function') origOnResponse(response)
|
|
79
79
|
}
|
|
@@ -83,7 +83,6 @@ class JSONResponse extends Helper {
|
|
|
83
83
|
this.response = null
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
86
|
/**
|
|
88
87
|
* Checks that response code is equal to the provided one
|
|
89
88
|
*
|
|
@@ -372,4 +371,4 @@ class JSONResponse extends Helper {
|
|
|
372
371
|
}
|
|
373
372
|
}
|
|
374
373
|
|
|
375
|
-
export { JSONResponse as default }
|
|
374
|
+
export { JSONResponse, JSONResponse as default }
|