codeceptjs 4.0.0-rc.8 → 4.0.0
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 +9 -10
- package/bin/codecept.js +15 -2
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +751 -172
- 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 +743 -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 +198 -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 +7 -7
- package/lib/command/check.js +2 -1
- package/lib/command/dryRun.js +24 -5
- package/lib/command/generate.js +2 -0
- package/lib/command/gherkin/snippets.js +5 -4
- package/lib/command/init.js +248 -266
- 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 +1 -14
- package/lib/command/run.js +3 -17
- package/lib/command/utils.js +14 -0
- package/lib/command/workers/runTests.js +11 -15
- package/lib/config.js +77 -4
- package/lib/container.js +97 -15
- package/lib/effects.js +17 -0
- package/lib/element/WebElement.js +195 -3
- 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/FileSystem.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +2 -1
- package/lib/helper/Playwright.js +96 -115
- package/lib/helper/Puppeteer.js +43 -131
- package/lib/helper/WebDriver.js +42 -52
- package/lib/helper/errors/NonFocusedType.js +8 -0
- package/lib/helper/extras/Download.js +45 -0
- package/lib/helper/extras/PlaywrightLocator.js +10 -0
- 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/history.js +3 -2
- package/lib/html.js +90 -16
- package/lib/index.js +9 -1
- package/lib/listener/config.js +6 -4
- package/lib/listener/emptyRun.js +2 -1
- package/lib/listener/helpers.js +4 -1
- 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 +126 -16
- package/lib/mocha/cli.js +4 -2
- package/lib/mocha/factory.js +7 -2
- package/lib/mocha/inject.js +1 -1
- package/lib/mocha/scenarioConfig.js +2 -1
- package/lib/mocha/ui.js +5 -6
- package/lib/parser.js +2 -2
- package/lib/pause.js +38 -4
- package/lib/plugin/aiTrace.js +96 -103
- package/lib/plugin/analyze.js +9 -9
- package/lib/plugin/auth.js +3 -3
- 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 +15 -13
- 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 +10 -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 +5 -5
- package/lib/store.js +72 -3
- package/lib/translation.js +2 -1
- 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.js +29 -3
- package/lib/workers.js +14 -22
- package/package.json +17 -14
- package/typings/index.d.ts +19 -5
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -16
- package/docs/webapi/attachFile.mustache +0 -24
- 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 -14
- 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/dontSeeCurrentPathEquals.mustache +0 -10
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -12
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -16
- 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 -21
- 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 -16
- 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/seeCurrentPathEquals.mustache +0 -10
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -12
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -17
- 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 -26
- 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/plugin/stepByStepReport.js +0 -431
- package/lib/plugin/subtitles.js +0 -89
package/lib/plugin/pageInfo.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import Container from '../container.js'
|
|
4
|
-
const supportedHelpers = Container.STANDARD_ACTING_HELPERS
|
|
5
4
|
import recorder from '../recorder.js'
|
|
6
5
|
import event from '../event.js'
|
|
7
6
|
import { scanForErrorMessages } from '../html.js'
|
|
7
|
+
import { captureSnapshot, pickActingHelper } from '../utils/trace.js'
|
|
8
8
|
import { output } from '../index.js'
|
|
9
|
+
import store from '../store.js'
|
|
9
10
|
import { humanizeString, ucfirst } from '../utils.js'
|
|
10
11
|
import { testToFileName } from '../mocha/test.js'
|
|
12
|
+
|
|
11
13
|
const defaultConfig = {
|
|
12
14
|
errorClasses: ['error', 'warning', 'alert', 'danger'],
|
|
13
15
|
browserLogs: ['error'],
|
|
@@ -36,67 +38,66 @@ const defaultConfig = {
|
|
|
36
38
|
*
|
|
37
39
|
*/
|
|
38
40
|
export default function (config = {}) {
|
|
39
|
-
const helpers = Container.helpers()
|
|
40
|
-
let helper
|
|
41
|
-
|
|
42
41
|
config = Object.assign(defaultConfig, config)
|
|
43
42
|
|
|
44
|
-
for (const helperName of supportedHelpers) {
|
|
45
|
-
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
46
|
-
helper = helpers[helperName]
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (!helper) return // no helpers for screenshot
|
|
51
|
-
|
|
52
43
|
event.dispatcher.on(event.test.failed, test => {
|
|
44
|
+
const helper = pickActingHelper(Container.helpers())
|
|
45
|
+
if (!helper) return
|
|
46
|
+
|
|
53
47
|
const pageState = {}
|
|
54
48
|
|
|
55
|
-
recorder.add('
|
|
49
|
+
recorder.add('pageInfo capture', async () => {
|
|
56
50
|
try {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
51
|
+
const prefix = `${testToFileName(test)}.pageInfo`
|
|
52
|
+
const captured = await captureSnapshot(helper, {
|
|
53
|
+
dir: store.outputDir,
|
|
54
|
+
prefix,
|
|
55
|
+
captureScreenshot: false,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (captured.url) pageState.url = captured.url
|
|
59
|
+
|
|
60
|
+
if (captured.html) {
|
|
61
|
+
const htmlPath = path.join(store.outputDir, captured.html)
|
|
62
|
+
pageState.htmlSnapshot = htmlPath
|
|
63
|
+
const htmlForScan = captured.htmlRaw || (() => {
|
|
64
|
+
try { return fs.readFileSync(htmlPath, 'utf8') } catch { return '' }
|
|
65
|
+
})()
|
|
66
|
+
if (htmlForScan) {
|
|
67
|
+
try {
|
|
68
|
+
const errors = scanForErrorMessages(htmlForScan, config.errorClasses)
|
|
69
|
+
if (errors.length) {
|
|
70
|
+
output.debug('Detected errors in HTML code')
|
|
71
|
+
errors.forEach(error => output.debug(error))
|
|
72
|
+
pageState.htmlErrors = errors
|
|
73
|
+
}
|
|
74
|
+
} catch {}
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
|
-
} catch (err) {
|
|
76
|
-
// not really needed
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!logs) return
|
|
78
|
+
if (captured.aria) {
|
|
79
|
+
pageState.ariaSnapshot = path.join(store.outputDir, captured.aria)
|
|
80
|
+
}
|
|
85
81
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
if (captured.console) {
|
|
83
|
+
const consolePath = path.join(store.outputDir, captured.console)
|
|
84
|
+
pageState.consoleSnapshot = consolePath
|
|
85
|
+
try {
|
|
86
|
+
const logs = JSON.parse(fs.readFileSync(consolePath, 'utf8'))
|
|
87
|
+
pageState.browserErrors = getBrowserErrors(logs, config.browserLogs)
|
|
88
|
+
} catch {}
|
|
89
|
+
}
|
|
90
|
+
} catch {}
|
|
91
|
+
}, true)
|
|
91
92
|
|
|
92
93
|
recorder.add('Save page info', () => {
|
|
93
94
|
test.addNote('pageInfo', pageStateToMarkdown(pageState))
|
|
94
95
|
|
|
95
|
-
const pageStateFileName = path.join(
|
|
96
|
+
const pageStateFileName = path.join(store.outputDir, `${testToFileName(test)}.pageInfo.md`)
|
|
96
97
|
fs.writeFileSync(pageStateFileName, pageStateToMarkdown(pageState))
|
|
97
98
|
test.artifacts.pageInfo = pageStateFileName
|
|
98
99
|
return pageState
|
|
99
|
-
})
|
|
100
|
+
}, true)
|
|
100
101
|
})
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -126,15 +127,16 @@ function pageStateToMarkdown(pageState) {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
function getBrowserErrors(logs, type = ['error']) {
|
|
129
|
-
// Playwright
|
|
130
|
-
|
|
130
|
+
// Accepts Playwright ConsoleMessage objects, normalized {type, text}, or strings
|
|
131
|
+
return logs
|
|
131
132
|
.map(log => {
|
|
132
133
|
if (typeof log === 'string') return log
|
|
133
|
-
if (!log
|
|
134
|
-
|
|
134
|
+
if (!log) return null
|
|
135
|
+
const t = typeof log.type === 'function' ? log.type() : log.type
|
|
136
|
+
const text = typeof log.text === 'function' ? log.text() : log.text
|
|
137
|
+
if (!t) return null
|
|
138
|
+
return { type: t, text }
|
|
135
139
|
})
|
|
136
140
|
.filter(l => l && (typeof l === 'string' || type.includes(l.type)))
|
|
137
141
|
.map(l => (typeof l === 'string' ? l : l.text))
|
|
138
|
-
|
|
139
|
-
return errors
|
|
140
142
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import event from '../event.js'
|
|
2
|
+
import pause from '../pause.js'
|
|
3
|
+
import recorder from '../recorder.js'
|
|
4
|
+
import output from '../output.js'
|
|
5
|
+
import {
|
|
6
|
+
parsePluginArgs,
|
|
7
|
+
resolveTrigger,
|
|
8
|
+
matchStepFile,
|
|
9
|
+
matchUrl,
|
|
10
|
+
getBrowserHelper,
|
|
11
|
+
} from '../utils/pluginParser.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Pauses test execution interactively. Replaces the legacy `pauseOnFail`
|
|
15
|
+
* plugin. The default `on=fail` matches the old `pauseOnFail` behavior.
|
|
16
|
+
*
|
|
17
|
+
* #### Configuration
|
|
18
|
+
*
|
|
19
|
+
* ```js
|
|
20
|
+
* plugins: {
|
|
21
|
+
* pause: {
|
|
22
|
+
* enabled: false,
|
|
23
|
+
* on: 'fail',
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* #### `on=` modes
|
|
29
|
+
*
|
|
30
|
+
* * **fail** — pause when a step fails (default)
|
|
31
|
+
* * **test** — pause after each test
|
|
32
|
+
* * **step** — pause before the first step (interactive walk-through)
|
|
33
|
+
* * **file** — pause when execution reaches `path=...[;line=...]`
|
|
34
|
+
* * **url** — pause when the browser URL matches `pattern=...`
|
|
35
|
+
*
|
|
36
|
+
* CLI examples:
|
|
37
|
+
*
|
|
38
|
+
* ```
|
|
39
|
+
* npx codeceptjs run -p pause
|
|
40
|
+
* npx codeceptjs run -p pause:on=step
|
|
41
|
+
* npx codeceptjs run -p pause:on=file:path=tests/login_test.js;line=43
|
|
42
|
+
* npx codeceptjs run -p pause:on=url:pattern=/users/*
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export default function (config = {}) {
|
|
46
|
+
const cliArgs = parsePluginArgs(config._args)
|
|
47
|
+
const trigger = resolveTrigger(cliArgs, config, { on: 'fail' }, { name: 'pause' })
|
|
48
|
+
if (!trigger) return
|
|
49
|
+
|
|
50
|
+
switch (trigger.on) {
|
|
51
|
+
case 'fail':
|
|
52
|
+
return initFailMode()
|
|
53
|
+
case 'test':
|
|
54
|
+
return initTestMode()
|
|
55
|
+
case 'step':
|
|
56
|
+
return initStepMode()
|
|
57
|
+
case 'file':
|
|
58
|
+
return initFileMode(trigger.path, trigger.line)
|
|
59
|
+
case 'url':
|
|
60
|
+
return initUrlMode(trigger.pattern)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function initFailMode() {
|
|
65
|
+
let failed = false
|
|
66
|
+
|
|
67
|
+
event.dispatcher.on(event.test.started, () => {
|
|
68
|
+
failed = false
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
event.dispatcher.on(event.step.failed, () => {
|
|
72
|
+
failed = true
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
event.dispatcher.on(event.test.after, () => {
|
|
76
|
+
if (failed) pause()
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function initTestMode() {
|
|
81
|
+
event.dispatcher.on(event.test.after, () => pause())
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function initStepMode() {
|
|
85
|
+
let activated = false
|
|
86
|
+
|
|
87
|
+
event.dispatcher.on(event.test.before, () => {
|
|
88
|
+
if (activated) return
|
|
89
|
+
activated = true
|
|
90
|
+
recorder.add('pause:step', () => pause())
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function initFileMode(targetPath, targetLine) {
|
|
95
|
+
let paused = false
|
|
96
|
+
|
|
97
|
+
event.dispatcher.on(event.step.before, step => {
|
|
98
|
+
if (paused) return
|
|
99
|
+
if (!matchStepFile(step, targetPath, targetLine)) return
|
|
100
|
+
paused = true
|
|
101
|
+
recorder.add('pause:file', () => pause())
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function initUrlMode(pattern) {
|
|
106
|
+
const helper = getBrowserHelper()
|
|
107
|
+
|
|
108
|
+
if (!helper) {
|
|
109
|
+
output.error('pause:on=url requires a browser helper (Playwright, WebDriver, Puppeteer, Appium)')
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let paused = false
|
|
114
|
+
|
|
115
|
+
event.dispatcher.on(event.step.after, () => {
|
|
116
|
+
if (paused) return
|
|
117
|
+
|
|
118
|
+
recorder.add('pause:url check', async () => {
|
|
119
|
+
if (paused) return
|
|
120
|
+
try {
|
|
121
|
+
const currentUrl = await helper.grabCurrentUrl()
|
|
122
|
+
if (matchUrl(currentUrl, pattern)) {
|
|
123
|
+
paused = true
|
|
124
|
+
return pause()
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
// page may not be loaded yet
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
}
|
|
@@ -1,39 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import output from '../output.js'
|
|
2
|
+
import pause from './pause.js'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
let warned = false
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Useful for debugging flaky tests on local environment.
|
|
9
|
-
* Add this plugin to config file:
|
|
10
|
-
*
|
|
11
|
-
* ```js
|
|
12
|
-
* plugins: {
|
|
13
|
-
* pauseOnFail: {},
|
|
14
|
-
* }
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* Unlike other plugins, `pauseOnFail` is not recommended to be enabled by default.
|
|
18
|
-
* Enable it manually on each run via `-p` option:
|
|
19
|
-
*
|
|
20
|
-
* ```
|
|
21
|
-
* npx codeceptjs run -p pauseOnFail
|
|
22
|
-
* ```
|
|
7
|
+
* Starts an interactive pause when a test fails.
|
|
23
8
|
*
|
|
9
|
+
* **Deprecated:** use the `pause` plugin with `on: 'fail'`, which is the default behavior.
|
|
24
10
|
*/
|
|
25
|
-
export default function() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
event.dispatcher.on(event.step.failed, () => {
|
|
33
|
-
failed = true
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
event.dispatcher.on(event.test.after, () => {
|
|
37
|
-
if (failed) pause()
|
|
38
|
-
})
|
|
11
|
+
export default function (config = {}) {
|
|
12
|
+
if (!warned) {
|
|
13
|
+
output.error('pauseOnFail is deprecated; use the `pause` plugin (default on=fail).')
|
|
14
|
+
warned = true
|
|
15
|
+
}
|
|
16
|
+
return pause({ ...config, on: 'fail' })
|
|
39
17
|
}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import debugModule from 'debug'
|
|
1
2
|
import event from '../event.js'
|
|
2
3
|
import recorder from '../recorder.js'
|
|
3
4
|
import store from '../store.js'
|
|
4
5
|
|
|
6
|
+
const debug = debugModule('codeceptjs:retryFailedStep')
|
|
7
|
+
|
|
5
8
|
const defaultConfig = {
|
|
6
9
|
retries: 3,
|
|
7
10
|
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
|
|
11
|
+
minTimeout: 150,
|
|
12
|
+
maxTimeout: 10000,
|
|
8
13
|
factor: 1.5,
|
|
14
|
+
randomize: false,
|
|
9
15
|
ignoredSteps: [],
|
|
10
16
|
deferToScenarioRetries: true,
|
|
11
17
|
}
|
|
@@ -41,10 +47,9 @@ const RETRY_PRIORITIES = {
|
|
|
41
47
|
* #### Configuration:
|
|
42
48
|
*
|
|
43
49
|
* * `retries` - number of retries (by default 3),
|
|
44
|
-
* * `when` - function, when to perform a retry (accepts error as parameter)
|
|
45
50
|
* * `factor` - The exponential factor to use. Default is 1.5.
|
|
46
|
-
* * `minTimeout` - The number of milliseconds before starting the first retry. Default is
|
|
47
|
-
* * `maxTimeout` - The maximum number of milliseconds between two retries. Default is
|
|
51
|
+
* * `minTimeout` - The number of milliseconds before starting the first retry. Default is 150.
|
|
52
|
+
* * `maxTimeout` - The maximum number of milliseconds between two retries. Default is 10000.
|
|
48
53
|
* * `randomize` - Randomizes the timeouts by multiplying with a factor from 1 to 2. Default is false.
|
|
49
54
|
* * `defaultIgnoredSteps` - an array of steps to be ignored for retry. Includes:
|
|
50
55
|
* * `amOnPage`
|
|
@@ -74,7 +79,7 @@ const RETRY_PRIORITIES = {
|
|
|
74
79
|
*
|
|
75
80
|
* #### Disable Per Test
|
|
76
81
|
*
|
|
77
|
-
* This plugin can be disabled per test. In this case you will need to
|
|
82
|
+
* This plugin can be disabled per test. In this case you will need to add `step.retry()` to all flaky steps:
|
|
78
83
|
*
|
|
79
84
|
* Use scenario configuration to disable plugin for a test
|
|
80
85
|
*
|
|
@@ -86,9 +91,8 @@ const RETRY_PRIORITIES = {
|
|
|
86
91
|
*
|
|
87
92
|
*/
|
|
88
93
|
export default function (config) {
|
|
89
|
-
config = Object.assign(defaultConfig, config)
|
|
94
|
+
config = Object.assign({}, defaultConfig, config)
|
|
90
95
|
config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
|
|
91
|
-
const customWhen = config.when
|
|
92
96
|
|
|
93
97
|
let enableRetry = false
|
|
94
98
|
|
|
@@ -98,7 +102,6 @@ export default function (config) {
|
|
|
98
102
|
if (!store.autoRetries) return false
|
|
99
103
|
if (err && err.isTerminal) return false
|
|
100
104
|
if (err && err.message && (err.message.includes('ERR_ABORTED') || err.message.includes('frame was detached') || err.message.includes('Target page, context or browser has been closed'))) return false
|
|
101
|
-
if (customWhen) return customWhen(err)
|
|
102
105
|
return true
|
|
103
106
|
}
|
|
104
107
|
config.when = when
|
|
@@ -108,11 +111,12 @@ export default function (config) {
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
event.dispatcher.on(event.step.started, step => {
|
|
114
|
+
if (!step.title) return
|
|
111
115
|
for (const ignored of config.ignoredSteps) {
|
|
112
|
-
if (step.
|
|
116
|
+
if (step.title === ignored) return
|
|
113
117
|
if (ignored instanceof RegExp) {
|
|
114
|
-
if (step.
|
|
115
|
-
} else if (ignored.indexOf('*') && step.
|
|
118
|
+
if (step.title.match(ignored)) return
|
|
119
|
+
} else if (ignored.indexOf('*') && step.title.startsWith(ignored.slice(0, -1))) return
|
|
116
120
|
}
|
|
117
121
|
enableRetry = true
|
|
118
122
|
})
|
|
@@ -147,9 +151,7 @@ export default function (config) {
|
|
|
147
151
|
test.opts.conditionalRetries = config.retries
|
|
148
152
|
test.opts.stepRetryPriority = stepRetryPriority
|
|
149
153
|
|
|
150
|
-
|
|
151
|
-
console.log('[retryFailedStep] applying retries =', config.retries, 'for test', test.title)
|
|
152
|
-
}
|
|
154
|
+
debug('applying retries = %d for test %s', config.retries, test.title)
|
|
153
155
|
recorder.retry(config)
|
|
154
156
|
})
|
|
155
157
|
|