codeceptjs 4.0.1-beta.9 → 4.0.1
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/README.md +39 -28
- package/bin/codecept.js +17 -4
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +1189 -0
- package/docs/advanced.md +201 -0
- package/docs/agents.md +181 -0
- package/docs/ai.md +489 -0
- package/docs/aitrace.md +266 -0
- package/docs/api.md +332 -0
- package/docs/architecture.md +235 -0
- package/docs/assertions.md +415 -0
- package/docs/auth.md +318 -0
- package/docs/basics.md +424 -0
- package/docs/bdd.md +539 -0
- package/docs/best.md +240 -0
- package/docs/bootstrap.md +132 -0
- package/docs/commands.md +352 -0
- package/docs/community-helpers.md +63 -0
- package/docs/configuration.md +185 -0
- package/docs/continuous-integration.md +431 -0
- package/docs/custom-helpers.md +297 -0
- package/docs/data.md +448 -0
- package/docs/debugging.md +332 -0
- package/docs/detox.md +235 -0
- package/docs/docker.md +107 -0
- package/docs/effects.md +179 -0
- package/docs/element-based-testing.md +295 -0
- package/docs/element-selection.md +125 -0
- package/docs/els.md +328 -0
- package/docs/environment-variables.md +131 -0
- package/docs/examples.md +160 -0
- package/docs/heal.md +213 -0
- package/docs/helpers/ApiDataFactory.md +267 -0
- package/docs/helpers/Appium.md +1419 -0
- package/docs/helpers/Detox.md +665 -0
- package/docs/helpers/ExpectHelper.md +275 -0
- package/docs/helpers/FileSystem.md +152 -0
- package/docs/helpers/GraphQL.md +152 -0
- package/docs/helpers/GraphQLDataFactory.md +226 -0
- package/docs/helpers/JSONResponse.md +255 -0
- package/docs/helpers/MockRequest.md +377 -0
- package/docs/helpers/Playwright.md +2970 -0
- package/docs/helpers/Puppeteer-firefox.md +86 -0
- package/docs/helpers/Puppeteer.md +2583 -0
- package/docs/helpers/REST.md +289 -0
- package/docs/helpers/WebDriver.md +2639 -0
- package/docs/hooks.md +148 -0
- package/docs/index.md +111 -0
- package/docs/installation.md +121 -0
- package/docs/internal-test-server.md +89 -0
- package/docs/locators.md +355 -0
- package/docs/mcp.md +485 -0
- package/docs/migrate-from-cypress.md +98 -0
- package/docs/migrate-from-java.md +108 -0
- package/docs/migrate-from-protractor.md +101 -0
- package/docs/migrate-from-testcafe.md +99 -0
- package/docs/migration-4.md +745 -0
- package/docs/mobile.md +338 -0
- package/docs/pageobjects.md +399 -0
- package/docs/parallel.md +187 -0
- package/docs/playwright.md +714 -0
- package/docs/plugins/aiTrace.md +49 -0
- package/docs/plugins/analyze.md +66 -0
- package/docs/plugins/auth.md +241 -0
- package/docs/plugins/autoDelay.md +48 -0
- package/docs/plugins/browser.md +41 -0
- package/docs/plugins/coverage.md +39 -0
- package/docs/plugins/customLocator.md +119 -0
- package/docs/plugins/customReporter.md +16 -0
- package/docs/plugins/expose.md +75 -0
- package/docs/plugins/heal.md +44 -0
- package/docs/plugins/junitReporter.md +51 -0
- package/docs/plugins/pageInfo.md +34 -0
- package/docs/plugins/pause.md +43 -0
- package/docs/plugins/pauseOnFail.md +18 -0
- package/docs/plugins/retryFailedStep.md +75 -0
- package/docs/plugins/screencast.md +55 -0
- package/docs/plugins/screenshot.md +58 -0
- package/docs/plugins/screenshotOnFail.md +18 -0
- package/docs/plugins/stepTimeout.md +65 -0
- package/docs/plugins.md +87 -0
- package/docs/puppeteer.md +314 -0
- package/docs/quickstart.md +120 -0
- package/docs/reports.md +195 -0
- package/docs/retry.md +311 -0
- package/docs/secrets.md +150 -0
- package/docs/sessions.md +80 -0
- package/docs/shadow.md +68 -0
- package/docs/store.md +94 -0
- package/docs/test-structure.md +275 -0
- package/docs/timeouts.md +183 -0
- package/docs/translation.md +247 -0
- package/docs/tutorial.md +323 -0
- package/docs/typescript.md +159 -0
- package/docs/web-element.md +251 -0
- package/docs/webdriver.md +641 -0
- package/docs/within.md +55 -0
- package/lib/actor.js +1 -36
- package/lib/ai.js +3 -2
- package/lib/aria.js +260 -0
- package/lib/assertions.js +18 -0
- package/lib/codecept.js +34 -25
- package/lib/command/check.js +2 -1
- package/lib/command/definitions.js +14 -10
- package/lib/command/dryRun.js +24 -5
- package/lib/command/generate.js +3 -1
- package/lib/command/gherkin/snippets.js +5 -4
- package/lib/command/init.js +249 -270
- package/lib/command/list.js +150 -10
- package/lib/command/query.js +218 -0
- package/lib/command/run-multiple.js +3 -2
- package/lib/command/run-workers.js +14 -16
- package/lib/command/run.js +3 -17
- package/lib/command/utils.js +14 -0
- package/lib/command/workers/runTests.js +117 -9
- package/lib/config.js +98 -19
- package/lib/container.js +188 -19
- package/lib/effects.js +17 -0
- package/lib/element/WebElement.js +246 -2
- package/lib/els.js +12 -6
- package/lib/globals.js +32 -19
- package/lib/heal.js +7 -4
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +8 -8
- package/lib/helper/FileSystem.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +2 -1
- package/lib/helper/Playwright.js +367 -516
- package/lib/helper/Puppeteer.js +343 -197
- package/lib/helper/WebDriver.js +324 -111
- package/lib/helper/errors/ElementNotFound.js +5 -2
- package/lib/helper/errors/MultipleElementsFound.js +52 -0
- package/lib/helper/errors/NonFocusedType.js +8 -0
- package/lib/helper/extras/Download.js +45 -0
- package/lib/helper/extras/PlaywrightLocator.js +7 -107
- package/lib/helper/extras/elementSelection.js +58 -0
- package/lib/helper/extras/focusCheck.js +43 -0
- package/lib/helper/extras/richTextEditor.js +178 -0
- package/lib/helper/scripts/dropFile.js +11 -0
- package/lib/history.js +3 -2
- package/lib/html.js +103 -16
- package/lib/index.js +9 -1
- package/lib/listener/config.js +6 -4
- package/lib/listener/emptyRun.js +2 -1
- package/lib/listener/globalRetry.js +32 -6
- package/lib/listener/helpers.js +6 -15
- package/lib/listener/mocha.js +2 -1
- package/lib/listener/pageobjects.js +43 -0
- package/lib/listener/result.js +3 -2
- package/lib/locator.js +158 -16
- package/lib/mocha/cli.js +19 -1
- package/lib/mocha/factory.js +13 -28
- package/lib/mocha/inject.js +1 -1
- package/lib/mocha/scenarioConfig.js +2 -1
- package/lib/mocha/test.js +4 -2
- package/lib/mocha/ui.js +5 -6
- package/lib/output.js +2 -2
- package/lib/parser.js +2 -2
- package/lib/pause.js +38 -4
- package/lib/plugin/aiTrace.js +457 -0
- package/lib/plugin/analyze.js +9 -9
- package/lib/plugin/auth.js +5 -4
- package/lib/plugin/browser.js +77 -0
- package/lib/plugin/expose.js +159 -0
- package/lib/plugin/heal.js +47 -3
- package/lib/plugin/junitReporter.js +303 -0
- package/lib/plugin/pageInfo.js +54 -52
- package/lib/plugin/pause.js +131 -0
- package/lib/plugin/pauseOnFail.js +11 -33
- package/lib/plugin/retryFailedStep.js +43 -32
- package/lib/plugin/screencast.js +289 -0
- package/lib/plugin/screenshot.js +558 -0
- package/lib/plugin/screenshotOnFail.js +9 -170
- package/lib/plugin/stepTimeout.js +3 -2
- package/lib/recorder.js +1 -1
- package/lib/rerun.js +2 -1
- package/lib/result.js +2 -1
- package/lib/step/base.js +23 -9
- package/lib/step/comment.js +2 -2
- package/lib/step/config.js +15 -2
- package/lib/step/helper.js +4 -4
- package/lib/step/meta.js +3 -3
- package/lib/step/record.js +12 -4
- package/lib/store.js +72 -3
- package/lib/translation.js +2 -1
- package/lib/utils/loaderCheck.js +41 -3
- package/lib/utils/mask_data.js +2 -1
- package/lib/utils/pluginParser.js +151 -0
- package/lib/utils/trace.js +297 -0
- package/lib/utils/typescript.js +261 -49
- package/lib/utils.js +77 -3
- package/lib/workers.js +123 -17
- package/package.json +48 -43
- package/typings/index.d.ts +120 -9
- package/typings/promiseBasedTypes.d.ts +3243 -6057
- package/typings/types.d.ts +3541 -6506
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/blur.mustache +0 -18
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -9
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -29
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/dontSeeTraffic.mustache +0 -13
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/flushNetworkTraffics.mustache +0 -5
- package/docs/webapi/focus.mustache +0 -13
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/grabWebElement.mustache +0 -9
- package/docs/webapi/grabWebElements.mustache +0 -9
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/seeTraffic.mustache +0 -36
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/startRecordingTraffic.mustache +0 -8
- package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
- package/docs/webapi/stopRecordingTraffic.mustache +0 -5
- package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForCookie.mustache +0 -9
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForDisabled.mustache +0 -6
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/lib/helper/AI.js +0 -214
- package/lib/helper/Mochawesome.js +0 -96
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -52
- package/lib/helper/extras/React.js +0 -65
- package/lib/listener/enhancedGlobalRetry.js +0 -110
- package/lib/plugin/enhancedRetryFailedStep.js +0 -99
- package/lib/plugin/htmlReporter.js +0 -3648
- package/lib/plugin/stepByStepReport.js +0 -427
- package/lib/plugin/subtitles.js +0 -89
- package/lib/retryCoordinator.js +0 -207
package/lib/mocha/cli.js
CHANGED
|
@@ -8,7 +8,9 @@ import { dirname, join } from 'path'
|
|
|
8
8
|
import event from '../event.js'
|
|
9
9
|
import AssertionFailedError from '../assert/error.js'
|
|
10
10
|
import output from '../output.js'
|
|
11
|
+
import store from '../store.js'
|
|
11
12
|
import test, { cloneTest } from './test.js'
|
|
13
|
+
import { fixErrorStack } from '../utils/typescript.js'
|
|
12
14
|
|
|
13
15
|
// Get version from package.json to avoid circular dependency
|
|
14
16
|
const __filename = fileURLToPath(import.meta.url)
|
|
@@ -40,7 +42,7 @@ class Cli extends Base {
|
|
|
40
42
|
if (opts.verbose) level = 3
|
|
41
43
|
output.level(level)
|
|
42
44
|
output.print(`CodeceptJS v${codeceptVersion} ${output.standWithUkraine()}`)
|
|
43
|
-
output.print(`Using test root "${
|
|
45
|
+
output.print(`Using test root "${store.codeceptDir}"`)
|
|
44
46
|
|
|
45
47
|
const showSteps = level >= 1
|
|
46
48
|
|
|
@@ -201,7 +203,18 @@ class Cli extends Base {
|
|
|
201
203
|
|
|
202
204
|
// failures
|
|
203
205
|
if (stats.failures) {
|
|
206
|
+
for (const test of this.failures) {
|
|
207
|
+
if (test.err && typeof test.err.fetchDetails === 'function') {
|
|
208
|
+
try {
|
|
209
|
+
await test.err.fetchDetails()
|
|
210
|
+
} catch (e) {
|
|
211
|
+
// ignore fetch errors
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
204
216
|
// append step traces
|
|
217
|
+
const Container = await getContainer()
|
|
205
218
|
this.failures = this.failures.map(test => {
|
|
206
219
|
// we will change the stack trace, so we need to clone the test
|
|
207
220
|
const err = test.err
|
|
@@ -264,6 +277,11 @@ class Cli extends Base {
|
|
|
264
277
|
}
|
|
265
278
|
|
|
266
279
|
try {
|
|
280
|
+
const fileMapping = Container?.tsFileMapping?.()
|
|
281
|
+
if (fileMapping) {
|
|
282
|
+
fixErrorStack(err, fileMapping)
|
|
283
|
+
}
|
|
284
|
+
|
|
267
285
|
let stack = err.stack
|
|
268
286
|
stack = (stack || '').replace(originalMessage, '')
|
|
269
287
|
stack = stack ? stack.split('\n') : []
|
package/lib/mocha/factory.js
CHANGED
|
@@ -7,6 +7,8 @@ import gherkinParser, { loadTranslations } from './gherkin.js'
|
|
|
7
7
|
import output from '../output.js'
|
|
8
8
|
import scenarioUiFunction from './ui.js'
|
|
9
9
|
import { initMochaGlobals } from '../globals.js'
|
|
10
|
+
import { fixErrorStack } from '../utils/typescript.js'
|
|
11
|
+
import container from '../container.js'
|
|
10
12
|
|
|
11
13
|
const __filename = fileURLToPath(import.meta.url)
|
|
12
14
|
const __dirname = fsPath.dirname(__filename)
|
|
@@ -15,7 +17,11 @@ let mocha
|
|
|
15
17
|
|
|
16
18
|
class MochaFactory {
|
|
17
19
|
static create(config, opts) {
|
|
18
|
-
|
|
20
|
+
const merged = Object.assign({}, config, opts)
|
|
21
|
+
mocha = new Mocha(merged)
|
|
22
|
+
if (merged.cleanReferencesAfterRun !== true) {
|
|
23
|
+
mocha.cleanReferencesAfterRun(false)
|
|
24
|
+
}
|
|
19
25
|
output.process(opts.child)
|
|
20
26
|
mocha.ui(scenarioUiFunction)
|
|
21
27
|
|
|
@@ -34,6 +40,10 @@ class MochaFactory {
|
|
|
34
40
|
// Handle ECONNREFUSED without dynamic import for now
|
|
35
41
|
err = new Error('Connection refused: ' + err.toString())
|
|
36
42
|
}
|
|
43
|
+
const fileMapping = container?.tsFileMapping?.()
|
|
44
|
+
if (fileMapping) {
|
|
45
|
+
fixErrorStack(err, fileMapping)
|
|
46
|
+
}
|
|
37
47
|
output.error(err)
|
|
38
48
|
output.print(err.stack)
|
|
39
49
|
process.exit(1)
|
|
@@ -62,34 +72,9 @@ class MochaFactory {
|
|
|
62
72
|
const jsFiles = this.files.filter(file => !file.match(/\.feature$/))
|
|
63
73
|
this.files = this.files.filter(file => !file.match(/\.feature$/))
|
|
64
74
|
|
|
65
|
-
// Load JavaScript test files using
|
|
75
|
+
// Load JavaScript test files using original loadFiles
|
|
66
76
|
if (jsFiles.length > 0) {
|
|
67
|
-
|
|
68
|
-
// Try original loadFiles first for compatibility
|
|
69
|
-
originalLoadFiles.call(this, fn)
|
|
70
|
-
} catch (e) {
|
|
71
|
-
// If original loadFiles fails, load ESM files manually
|
|
72
|
-
if (e.message.includes('not in cache') || e.message.includes('ESM') || e.message.includes('getStatus')) {
|
|
73
|
-
// Load ESM files by importing them synchronously using top-level await workaround
|
|
74
|
-
for (const file of jsFiles) {
|
|
75
|
-
try {
|
|
76
|
-
// Convert file path to file:// URL for dynamic import
|
|
77
|
-
const fileUrl = `file://${file}`
|
|
78
|
-
// Use import() but don't await it - let it load in the background
|
|
79
|
-
import(fileUrl).catch(importErr => {
|
|
80
|
-
// If dynamic import fails, the file may have syntax errors or other issues
|
|
81
|
-
console.error(`Failed to load test file ${file}:`, importErr.message)
|
|
82
|
-
})
|
|
83
|
-
if (fn) fn()
|
|
84
|
-
} catch (fileErr) {
|
|
85
|
-
console.error(`Error processing test file ${file}:`, fileErr.message)
|
|
86
|
-
if (fn) fn(fileErr)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
throw e
|
|
91
|
-
}
|
|
92
|
-
}
|
|
77
|
+
originalLoadFiles.call(this, fn)
|
|
93
78
|
}
|
|
94
79
|
|
|
95
80
|
// add ids for each test and check uniqueness
|
package/lib/mocha/inject.js
CHANGED
|
@@ -5,7 +5,7 @@ const getInjectedArguments = async (fn, test, suite) => {
|
|
|
5
5
|
const container = containerModule.default || containerModule
|
|
6
6
|
|
|
7
7
|
const testArgs = {}
|
|
8
|
-
const params = getParams(fn) || []
|
|
8
|
+
const params = getParams(fn, { warnOnLegacyFormat: true }) || []
|
|
9
9
|
const objects = container.support()
|
|
10
10
|
|
|
11
11
|
for (const key of params) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isAsyncFunction } from '../utils.js'
|
|
2
|
+
import store from '../store.js'
|
|
2
3
|
|
|
3
4
|
/** @class */
|
|
4
5
|
class ScenarioConfig {
|
|
@@ -40,7 +41,7 @@ class ScenarioConfig {
|
|
|
40
41
|
* @returns {this}
|
|
41
42
|
*/
|
|
42
43
|
retry(retries) {
|
|
43
|
-
if (
|
|
44
|
+
if (store.scenarioOnly) retries = -retries
|
|
44
45
|
this.test.retries(retries)
|
|
45
46
|
return this
|
|
46
47
|
}
|
package/lib/mocha/test.js
CHANGED
|
@@ -154,14 +154,16 @@ function cloneTest(test) {
|
|
|
154
154
|
function testToFileName(test, { suffix = '', unique = false } = {}) {
|
|
155
155
|
let fileName = test.title
|
|
156
156
|
|
|
157
|
-
if (unique) fileName = `${fileName}_${test?.uid || Math.floor(new Date().getTime() / 1000)}`
|
|
158
|
-
if (suffix) fileName = `${fileName}_${suffix}`
|
|
159
157
|
// remove tags with empty string (disable for now)
|
|
160
158
|
// fileName = fileName.replace(/\@\w+/g, '')
|
|
161
159
|
fileName = fileName.slice(0, 100)
|
|
162
160
|
if (fileName.indexOf('{') !== -1) {
|
|
163
161
|
fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
|
|
164
162
|
}
|
|
163
|
+
|
|
164
|
+
// Apply unique suffix AFTER removing data part to ensure uniqueness
|
|
165
|
+
if (unique) fileName = `${fileName}_${test?.uid || Math.floor(new Date().getTime())}`
|
|
166
|
+
if (suffix) fileName = `${fileName}_${suffix}`
|
|
165
167
|
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`)
|
|
166
168
|
// TODO: add suite title to file name
|
|
167
169
|
// if (test.parent && test.parent.title) {
|
package/lib/mocha/ui.js
CHANGED
|
@@ -9,13 +9,12 @@ import { HookConfig, AfterSuiteHook, AfterHook, BeforeSuiteHook, BeforeHook } fr
|
|
|
9
9
|
import { initMochaGlobals } from '../globals.js'
|
|
10
10
|
import common from 'mocha/lib/interfaces/common.js'
|
|
11
11
|
import container from '../container.js'
|
|
12
|
+
import store from '../store.js'
|
|
12
13
|
|
|
13
14
|
const setContextTranslation = context => {
|
|
14
|
-
|
|
15
|
-
const containerToUse = global.container || container
|
|
16
|
-
if (!containerToUse) return
|
|
15
|
+
if (!container) return
|
|
17
16
|
|
|
18
|
-
const translation =
|
|
17
|
+
const translation = container.translation?.() || container.translation
|
|
19
18
|
const contexts = translation?.value?.('contexts')
|
|
20
19
|
|
|
21
20
|
if (contexts) {
|
|
@@ -119,7 +118,7 @@ export default function (suite) {
|
|
|
119
118
|
context.Feature.only = function (title, opts) {
|
|
120
119
|
const reString = `^${escapeRe(`${title}:`)}`
|
|
121
120
|
mocha.grep(new RegExp(reString))
|
|
122
|
-
|
|
121
|
+
store.featureOnly = true
|
|
123
122
|
return context.Feature(title, opts)
|
|
124
123
|
}
|
|
125
124
|
|
|
@@ -171,7 +170,7 @@ export default function (suite) {
|
|
|
171
170
|
context.Scenario.only = function (title, opts, fn) {
|
|
172
171
|
const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`
|
|
173
172
|
mocha.grep(new RegExp(reString))
|
|
174
|
-
|
|
173
|
+
store.scenarioOnly = true
|
|
175
174
|
return addScenario(title, opts, fn)
|
|
176
175
|
}
|
|
177
176
|
|
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
|
package/lib/parser.js
CHANGED
|
@@ -14,11 +14,11 @@ export const getParamsToString = function (fn) {
|
|
|
14
14
|
return getParams(newFn).join(', ')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function getParams(fn) {
|
|
17
|
+
function getParams(fn, { warnOnLegacyFormat = false } = {}) {
|
|
18
18
|
if (fn.isSinonProxy) return []
|
|
19
19
|
try {
|
|
20
20
|
const reflected = parser.parse(fn)
|
|
21
|
-
if (reflected.args.length > 1 || reflected.args[0] === 'I') {
|
|
21
|
+
if (warnOnLegacyFormat && (reflected.args.length > 1 || reflected.args[0] === 'I')) {
|
|
22
22
|
output.error('Error: old CodeceptJS v2 format detected. Upgrade your project to the new format -> https://bit.ly/codecept3Up')
|
|
23
23
|
}
|
|
24
24
|
if (reflected.destructuredArgs.length > 0) reflected.args = [...reflected.destructuredArgs]
|
package/lib/pause.js
CHANGED
|
@@ -18,6 +18,8 @@ let nextStep
|
|
|
18
18
|
let finish
|
|
19
19
|
let next
|
|
20
20
|
let registeredVariables = {}
|
|
21
|
+
let externalHandler = null
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* Pauses test execution and starts interactive shell
|
|
23
25
|
* @param {Object<string, *>} [passedObject]
|
|
@@ -37,10 +39,10 @@ const pause = function (passedObject = {}) {
|
|
|
37
39
|
})
|
|
38
40
|
|
|
39
41
|
event.dispatcher.on(event.test.finished, () => {
|
|
40
|
-
finish()
|
|
42
|
+
if (typeof finish === 'function') finish()
|
|
41
43
|
recorder.session.restore('pause')
|
|
42
|
-
rl.close()
|
|
43
|
-
history.save()
|
|
44
|
+
if (rl) rl.close()
|
|
45
|
+
if (!externalHandler) history.save()
|
|
44
46
|
})
|
|
45
47
|
|
|
46
48
|
recorder.add('Start new session', () => pauseSession(passedObject))
|
|
@@ -49,6 +51,15 @@ const pause = function (passedObject = {}) {
|
|
|
49
51
|
function pauseSession(passedObject = {}) {
|
|
50
52
|
registeredVariables = passedObject
|
|
51
53
|
recorder.session.start('pause')
|
|
54
|
+
|
|
55
|
+
if (externalHandler) {
|
|
56
|
+
store.onPause = true
|
|
57
|
+
return externalHandler({ registeredVariables }).then(() => {
|
|
58
|
+
store.onPause = false
|
|
59
|
+
recorder.session.restore('pause')
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
52
63
|
if (!next) {
|
|
53
64
|
let vars = Object.keys(registeredVariables).join(', ')
|
|
54
65
|
if (vars) vars = `(vars: ${vars})`
|
|
@@ -234,5 +245,28 @@ function registerVariable(name, value) {
|
|
|
234
245
|
registeredVariables[name] = value
|
|
235
246
|
}
|
|
236
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Hook for external pause drivers (e.g. the MCP server). When set, pauseSession
|
|
250
|
+
* delegates to the handler instead of opening a readline REPL. The handler
|
|
251
|
+
* receives `{ registeredVariables }` and returns a Promise that resolves when
|
|
252
|
+
* the driver decides to continue (resume) or step.
|
|
253
|
+
*
|
|
254
|
+
* The driver controls step-vs-resume by mutating `next` via setNextStep before
|
|
255
|
+
* resolving its Promise.
|
|
256
|
+
*/
|
|
257
|
+
function setPauseHandler(handler) {
|
|
258
|
+
externalHandler = handler
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Trigger a one-shot pause from outside the test (e.g. the MCP server,
|
|
263
|
+
* pausing the test at a specific step index without modifying the test).
|
|
264
|
+
* Schedules pauseSession through the recorder so it slots between steps.
|
|
265
|
+
*/
|
|
266
|
+
function pauseNow(passedObject = {}) {
|
|
267
|
+
if (store.dryRun) return
|
|
268
|
+
recorder.add('Triggered pause', () => pauseSession(passedObject))
|
|
269
|
+
}
|
|
270
|
+
|
|
237
271
|
export default pause
|
|
238
|
-
export { registerVariable }
|
|
272
|
+
export { registerVariable, setPauseHandler, pauseNow }
|