codeceptjs 4.0.0-rc.18 → 4.0.0-rc.19
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 +5 -1
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +250 -82
- package/docs/advanced.md +201 -0
- package/docs/agents.md +159 -0
- package/docs/ai.md +537 -0
- package/docs/aitrace.md +266 -0
- package/docs/api.md +332 -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 +230 -0
- package/docs/continuous-integration.md +497 -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 +136 -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/examples.md +161 -0
- package/docs/heal.md +213 -0
- package/docs/helpers/ApiDataFactory.md +267 -0
- package/docs/helpers/Appium.md +1405 -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/Mochawesome.md +8 -0
- package/docs/helpers/MockRequest.md +377 -0
- package/docs/helpers/MockServer.md +212 -0
- package/docs/helpers/Playwright.md +2969 -0
- package/docs/helpers/Polly.md +44 -0
- package/docs/helpers/Protractor.md +1769 -0
- package/docs/helpers/Puppeteer-firefox.md +86 -0
- package/docs/helpers/Puppeteer.md +2690 -0
- package/docs/helpers/REST.md +289 -0
- package/docs/helpers/SoftExpectHelper.md +352 -0
- package/docs/helpers/WebDriver.md +2682 -0
- package/docs/hooks.md +339 -0
- package/docs/index.md +111 -0
- package/docs/installation.md +83 -0
- package/docs/internal-api.md +265 -0
- package/docs/internal-test-server.md +89 -0
- package/docs/locators.md +355 -0
- package/docs/mcp.md +485 -0
- package/docs/migration-4.md +556 -0
- package/docs/mobile.md +338 -0
- package/docs/pageobjects.md +399 -0
- package/docs/parallel.md +585 -0
- package/docs/playwright.md +714 -0
- package/docs/plugins.md +866 -0
- package/docs/puppeteer.md +314 -0
- package/docs/quickstart.md +120 -0
- package/docs/react.md +70 -0
- package/docs/reports.md +483 -0
- package/docs/retry.md +274 -0
- package/docs/secrets.md +150 -0
- package/docs/sessions.md +80 -0
- package/docs/shadow.md +68 -0
- package/docs/test-structure.md +275 -0
- package/docs/timeouts.md +183 -0
- package/docs/translation.md +247 -0
- package/docs/tutorial.md +271 -0
- package/docs/typescript.md +374 -0
- package/docs/web-element.md +251 -0
- package/docs/webdriver.md +708 -0
- package/docs/within.md +55 -0
- package/lib/command/dryRun.js +9 -3
- package/lib/command/init.js +247 -266
- package/lib/command/query.js +218 -0
- package/lib/config.js +9 -0
- package/lib/element/WebElement.js +37 -0
- package/lib/globals.js +11 -10
- package/lib/helper/Playwright.js +4 -1
- package/lib/html.js +3 -0
- package/lib/index.js +9 -1
- package/lib/locator.js +2 -2
- package/lib/mocha/factory.js +5 -1
- package/lib/mocha/inject.js +1 -1
- package/lib/parser.js +2 -2
- package/lib/plugin/browser.js +2 -1
- package/lib/plugin/expose.js +159 -0
- package/lib/workers.js +1 -15
- package/package.json +7 -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/seeFileDownloaded.mustache +0 -23
- 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/docs/within.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /within
|
|
3
|
+
title: Within
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Within
|
|
7
|
+
|
|
8
|
+
`within` scopes all actions inside it to a specific element on the page — useful when working with repeated UI components or narrowing interaction to a specific section.
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
within('.js-signup-form', () => {
|
|
12
|
+
I.fillField('user[login]', 'User')
|
|
13
|
+
I.fillField('user[email]', 'user@user.com')
|
|
14
|
+
I.fillField('user[password]', 'user@user.com')
|
|
15
|
+
I.click('button')
|
|
16
|
+
})
|
|
17
|
+
I.see('There were problems creating your account.')
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
> ⚠ `within` can cause problems when used incorrectly. If you see unexpected behavior, refactor to use the context parameter on individual actions instead (e.g. `I.click('Login', '.nav')`). Keep `within` for the simplest cases.
|
|
21
|
+
> Since `within` returns a Promise, always `await` it when you need its return value.
|
|
22
|
+
|
|
23
|
+
## IFrames
|
|
24
|
+
|
|
25
|
+
Use a `frame` locator to scope actions inside an iframe:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
within({ frame: '#editor' }, () => {
|
|
29
|
+
I.see('Page')
|
|
30
|
+
I.fillField('Body', 'Hello world')
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Nested iframes _(WebDriver & Puppeteer only)_:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
within({ frame: ['.content', '#editor'] }, () => {
|
|
38
|
+
I.see('Page')
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> ℹ IFrames can also be accessed via `I.switchTo` command.
|
|
43
|
+
|
|
44
|
+
## Returning Values
|
|
45
|
+
|
|
46
|
+
`within` can return a value for use in the scenario:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const val = await within('#sidebar', () => {
|
|
50
|
+
return I.grabTextFrom({ css: 'h1' })
|
|
51
|
+
})
|
|
52
|
+
I.fillField('Description', val)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
When running steps inside a `within` block, they will be shown indented in the output.
|
package/lib/command/dryRun.js
CHANGED
|
@@ -10,6 +10,7 @@ import Container from '../container.js'
|
|
|
10
10
|
export default async function (test, options) {
|
|
11
11
|
if (options.grep) process.env.grep = options.grep
|
|
12
12
|
if (options.ansi === false) chalk.level = 0
|
|
13
|
+
store.dryRun = true
|
|
13
14
|
const configFile = options.config
|
|
14
15
|
let codecept
|
|
15
16
|
|
|
@@ -20,9 +21,15 @@ export default async function (test, options) {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
if (config.plugins) {
|
|
23
|
-
//
|
|
24
|
+
// Disable plugins that block (interactive) or perform external I/O (AI/network).
|
|
25
|
+
// Leave the rest enabled so they can register support objects (e.g. auth registers
|
|
26
|
+
// `login`); helper calls inside those support fns are already no-op'd by HelperStep
|
|
27
|
+
// when store.dryRun is true.
|
|
28
|
+
const disableInDryRun = new Set(['pause', 'pauseOnFail', 'analyze', 'aiTrace', 'pageInfo', 'heal'])
|
|
24
29
|
for (const plugin in config.plugins) {
|
|
25
|
-
|
|
30
|
+
if (disableInDryRun.has(plugin)) {
|
|
31
|
+
config.plugins[plugin].enabled = false
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
|
|
@@ -33,7 +40,6 @@ export default async function (test, options) {
|
|
|
33
40
|
if (options.bootstrap) await codecept.bootstrap()
|
|
34
41
|
|
|
35
42
|
codecept.loadTests()
|
|
36
|
-
store.dryRun = true
|
|
37
43
|
|
|
38
44
|
if (!options.steps && !options.verbose && !options.debug) {
|
|
39
45
|
await printTests(codecept.testFiles)
|
package/lib/command/init.js
CHANGED
|
@@ -15,7 +15,7 @@ import { test as generateTest } from './generate.js'
|
|
|
15
15
|
const isLocal = installedLocally()
|
|
16
16
|
|
|
17
17
|
const defaultConfig = {
|
|
18
|
-
tests: '
|
|
18
|
+
tests: './tests/*_test.js',
|
|
19
19
|
output: '',
|
|
20
20
|
helpers: {},
|
|
21
21
|
include: {},
|
|
@@ -25,14 +25,6 @@ const defaultConfig = {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const helpers = ['Playwright', 'WebDriver', 'Puppeteer', 'REST', 'GraphQL', 'Appium']
|
|
28
|
-
const noTranslation = 'English (no localization)'
|
|
29
|
-
|
|
30
|
-
async function getTranslations() {
|
|
31
|
-
const translationsModule = await import('../../translations/index.js')
|
|
32
|
-
const translations = Object.keys(translationsModule.default || translationsModule)
|
|
33
|
-
translations.unshift(noTranslation)
|
|
34
|
-
return translations
|
|
35
|
-
}
|
|
36
28
|
|
|
37
29
|
const packages = []
|
|
38
30
|
let isTypeScript = false
|
|
@@ -51,6 +43,7 @@ setCommonPlugins();
|
|
|
51
43
|
`
|
|
52
44
|
|
|
53
45
|
const defaultActor = `// in this file you can append custom step methods to 'I' object
|
|
46
|
+
import { actor } from 'codeceptjs';
|
|
54
47
|
|
|
55
48
|
export default function() {
|
|
56
49
|
return actor({
|
|
@@ -63,6 +56,7 @@ export default function() {
|
|
|
63
56
|
`
|
|
64
57
|
|
|
65
58
|
const defaultActorTs = `// in this file you can append custom step methods to 'I' object
|
|
59
|
+
import { actor } from 'codeceptjs';
|
|
66
60
|
|
|
67
61
|
export = function() {
|
|
68
62
|
return actor({
|
|
@@ -74,9 +68,9 @@ export = function() {
|
|
|
74
68
|
}
|
|
75
69
|
`
|
|
76
70
|
|
|
77
|
-
export default async function (initPath) {
|
|
71
|
+
export default async function (initPath, options = {}) {
|
|
78
72
|
const testsPath = getTestRoot(initPath)
|
|
79
|
-
const
|
|
73
|
+
const skipPrompts = !!options.yes
|
|
80
74
|
|
|
81
75
|
print()
|
|
82
76
|
print(` Welcome to ${colors.magenta.bold('CodeceptJS')} initialization tool`)
|
|
@@ -114,251 +108,265 @@ export default async function (initPath) {
|
|
|
114
108
|
return
|
|
115
109
|
}
|
|
116
110
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: 'tests',
|
|
127
|
-
type: 'input',
|
|
128
|
-
default: answers => `./*_test.${answers.typescript ? 'ts' : 'js'}`,
|
|
129
|
-
message: 'Where are your tests located?',
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
name: 'helper',
|
|
133
|
-
type: 'list',
|
|
134
|
-
choices: helpers,
|
|
135
|
-
default: 'Playwright',
|
|
136
|
-
message: 'What helpers do you want to use?',
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: 'jsonResponse',
|
|
140
|
-
type: 'confirm',
|
|
141
|
-
default: true,
|
|
142
|
-
message: 'Do you want to use JSONResponse helper for assertions on JSON responses? http://bit.ly/3ASVPy9',
|
|
143
|
-
when: answers => ['GraphQL', 'REST'].includes(answers.helper) === true,
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
name: 'output',
|
|
147
|
-
default: './output',
|
|
148
|
-
message: 'Where should logs, screenshots, and reports to be stored?',
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
name: 'translation',
|
|
152
|
-
type: 'list',
|
|
153
|
-
message: 'Do you want to enable localization for tests? http://bit.ly/3GNUBbh',
|
|
154
|
-
choices: translations,
|
|
155
|
-
},
|
|
156
|
-
])
|
|
157
|
-
.then(async result => {
|
|
158
|
-
if (result.typescript === true) {
|
|
159
|
-
isTypeScript = true
|
|
160
|
-
extension = isTypeScript === true ? 'ts' : 'js'
|
|
161
|
-
packages.push('typescript')
|
|
162
|
-
packages.push('tsx') // Add tsx for TypeScript support
|
|
163
|
-
packages.push('@types/node')
|
|
111
|
+
const result = skipPrompts
|
|
112
|
+
? {
|
|
113
|
+
typescript: false,
|
|
114
|
+
tests: './tests/*_test.js',
|
|
115
|
+
helper: 'Playwright',
|
|
116
|
+
jsonResponse: false,
|
|
117
|
+
output: './output',
|
|
164
118
|
}
|
|
119
|
+
: await inquirer.prompt([
|
|
120
|
+
{
|
|
121
|
+
name: 'typescript',
|
|
122
|
+
type: 'confirm',
|
|
123
|
+
default: false,
|
|
124
|
+
message: 'Do you plan to write tests in TypeScript?',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'tests',
|
|
128
|
+
type: 'input',
|
|
129
|
+
default: answers => `./tests/*_test.${answers.typescript ? 'ts' : 'js'}`,
|
|
130
|
+
message: 'Where are your tests located?',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'helper',
|
|
134
|
+
type: 'list',
|
|
135
|
+
choices: helpers,
|
|
136
|
+
default: 'Playwright',
|
|
137
|
+
message: 'What helpers do you want to use?',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'jsonResponse',
|
|
141
|
+
type: 'confirm',
|
|
142
|
+
default: true,
|
|
143
|
+
message: 'Do you want to use JSONResponse helper for assertions on JSON responses? http://bit.ly/3ASVPy9',
|
|
144
|
+
when: answers => ['GraphQL', 'REST'].includes(answers.helper) === true,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'output',
|
|
148
|
+
default: './output',
|
|
149
|
+
message: 'Where should logs, screenshots, and reports to be stored?',
|
|
150
|
+
},
|
|
151
|
+
])
|
|
152
|
+
|
|
153
|
+
if (result.typescript === true) {
|
|
154
|
+
isTypeScript = true
|
|
155
|
+
extension = isTypeScript === true ? 'ts' : 'js'
|
|
156
|
+
packages.push('typescript')
|
|
157
|
+
packages.push('tsx')
|
|
158
|
+
packages.push('@types/node')
|
|
159
|
+
}
|
|
165
160
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
161
|
+
const config = defaultConfig
|
|
162
|
+
config.name = testsPath.split(path.sep).pop()
|
|
163
|
+
config.output = result.output
|
|
169
164
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
config.tests = result.tests
|
|
166
|
+
if (isTypeScript) {
|
|
167
|
+
config.tests = `${config.tests.replace(/\.js$/, `.${extension}`)}`
|
|
168
|
+
config.require = ['tsx/cjs']
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const matchResults = config.tests.match(/[^*.]+/)
|
|
172
|
+
if (matchResults) {
|
|
173
|
+
mkdirp.sync(path.join(testsPath, matchResults[0]))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const helperName = result.helper
|
|
177
|
+
config.helpers[helperName] = {}
|
|
175
178
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
if (result.jsonResponse === true) {
|
|
180
|
+
config.helpers.JSONResponse = {}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let helperConfigs = []
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const HelperModule = await import(`../helper/${helperName}.js`)
|
|
187
|
+
const Helper = HelperModule.default || HelperModule
|
|
188
|
+
if (Helper._checkRequirements) {
|
|
189
|
+
packages.concat(Helper._checkRequirements())
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!Helper._config()) return
|
|
193
|
+
helperConfigs = helperConfigs.concat(
|
|
194
|
+
Helper._config().map(config => {
|
|
195
|
+
config.message = `[${helperName}] ${config.message}`
|
|
196
|
+
config.name = `${helperName}_${config.name}`
|
|
197
|
+
config.type = config.type || 'input'
|
|
198
|
+
return config
|
|
199
|
+
}),
|
|
200
|
+
)
|
|
201
|
+
} catch (err) {
|
|
202
|
+
error(err)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const finish = async () => {
|
|
206
|
+
const stepFile = `./steps_file.${extension}`
|
|
207
|
+
fs.writeFileSync(path.join(testsPath, stepFile), extension === 'ts' ? defaultActorTs : defaultActor)
|
|
208
|
+
|
|
209
|
+
config.include = { I: isTypeScript ? './steps_file' : stepFile }
|
|
210
|
+
|
|
211
|
+
print(`Steps file created at ${stepFile}`)
|
|
212
|
+
|
|
213
|
+
let configSource
|
|
214
|
+
const hasConfigure = isLocal && !initPath
|
|
215
|
+
|
|
216
|
+
if (isTypeScript) {
|
|
217
|
+
configSource = beautify(`export const config : CodeceptJS.MainConfig = ${inspect(config, false, 4, false)}`)
|
|
218
|
+
|
|
219
|
+
if (hasConfigure) configSource = importCodeceptConfigure + configHeader + configSource
|
|
220
|
+
|
|
221
|
+
fs.writeFileSync(typeScriptconfigFile, configSource, 'utf-8')
|
|
222
|
+
print(`Config created at ${typeScriptconfigFile}`)
|
|
223
|
+
} else {
|
|
224
|
+
configSource = beautify(`/** @type {CodeceptJS.MainConfig} */\nexport const config = ${inspect(config, false, 4, false)}`)
|
|
225
|
+
|
|
226
|
+
if (hasConfigure) configSource = importCodeceptConfigure + configHeader + configSource
|
|
227
|
+
|
|
228
|
+
fs.writeFileSync(configFile, configSource, 'utf-8')
|
|
229
|
+
print(`Config created at ${configFile}`)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (config.output) {
|
|
233
|
+
if (!fileExists(config.output)) {
|
|
234
|
+
mkdirp.sync(path.join(testsPath, config.output))
|
|
235
|
+
print(`Directory for temporary output files created at '${config.output}'`)
|
|
236
|
+
} else {
|
|
237
|
+
print(`Directory for temporary output files is already created at '${config.output}'`)
|
|
180
238
|
}
|
|
239
|
+
}
|
|
181
240
|
|
|
182
|
-
|
|
241
|
+
const jsconfig = {
|
|
242
|
+
compilerOptions: {
|
|
243
|
+
allowJs: true,
|
|
244
|
+
},
|
|
245
|
+
}
|
|
183
246
|
|
|
184
|
-
|
|
185
|
-
|
|
247
|
+
const tsconfig = {
|
|
248
|
+
'ts-node': {
|
|
249
|
+
files: true,
|
|
250
|
+
},
|
|
251
|
+
compilerOptions: {
|
|
252
|
+
target: 'es2018',
|
|
253
|
+
lib: ['es2018', 'DOM'],
|
|
254
|
+
esModuleInterop: true,
|
|
255
|
+
module: 'commonjs',
|
|
256
|
+
strictNullChecks: false,
|
|
257
|
+
types: ['codeceptjs', 'node'],
|
|
258
|
+
declaration: true,
|
|
259
|
+
skipLibCheck: true,
|
|
260
|
+
},
|
|
261
|
+
exclude: ['node_modules'],
|
|
262
|
+
}
|
|
186
263
|
|
|
187
|
-
|
|
188
|
-
|
|
264
|
+
if (isTypeScript) {
|
|
265
|
+
const tsconfigJson = beautify(JSON.stringify(tsconfig))
|
|
266
|
+
const tsconfigFile = path.join(testsPath, 'tsconfig.json')
|
|
267
|
+
if (fileExists(tsconfigFile)) {
|
|
268
|
+
print(`tsconfig.json already exists at ${tsconfigFile}`)
|
|
269
|
+
} else {
|
|
270
|
+
fs.writeFileSync(tsconfigFile, tsconfigJson)
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
const jsconfigJson = beautify(JSON.stringify(jsconfig))
|
|
274
|
+
const jsconfigFile = path.join(testsPath, 'jsconfig.json')
|
|
275
|
+
if (fileExists(jsconfigFile)) {
|
|
276
|
+
print(`jsconfig.json already exists at ${jsconfigFile}`)
|
|
277
|
+
} else {
|
|
278
|
+
fs.writeFileSync(jsconfigFile, jsconfigJson)
|
|
279
|
+
print(`Intellisense enabled in ${jsconfigFile}`)
|
|
189
280
|
}
|
|
281
|
+
}
|
|
190
282
|
|
|
191
|
-
|
|
283
|
+
const generateDefinitionsManually = colors.bold(`To get auto-completion support, please generate type definitions: ${colors.green('npx codeceptjs def')}`)
|
|
192
284
|
|
|
285
|
+
if (packages) {
|
|
193
286
|
try {
|
|
194
|
-
|
|
195
|
-
const Helper = HelperModule.default || HelperModule
|
|
196
|
-
if (Helper._checkRequirements) {
|
|
197
|
-
packages.concat(Helper._checkRequirements())
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (!Helper._config()) return
|
|
201
|
-
helperConfigs = helperConfigs.concat(
|
|
202
|
-
Helper._config().map(config => {
|
|
203
|
-
config.message = `[${helperName}] ${config.message}`
|
|
204
|
-
config.name = `${helperName}_${config.name}`
|
|
205
|
-
config.type = config.type || 'input'
|
|
206
|
-
return config
|
|
207
|
-
}),
|
|
208
|
-
)
|
|
287
|
+
install(packages)
|
|
209
288
|
} catch (err) {
|
|
210
|
-
|
|
289
|
+
print(colors.bold.red(err.toString()))
|
|
290
|
+
print()
|
|
291
|
+
print(colors.bold.red('Please install next packages manually:'))
|
|
292
|
+
print(`npm i ${packages.join(' ')} --save-dev`)
|
|
293
|
+
print()
|
|
294
|
+
print('Things to do after missing packages installed:')
|
|
295
|
+
print('☑', generateDefinitionsManually)
|
|
296
|
+
print('☑ Create first test:', colors.green('npx codeceptjs gt'))
|
|
297
|
+
print(colors.bold.magenta('Find more information at https://codecept.io'))
|
|
298
|
+
return
|
|
211
299
|
}
|
|
300
|
+
}
|
|
212
301
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (hasConfigure) configSource = importCodeceptConfigure + configHeader + configSource
|
|
234
|
-
|
|
235
|
-
fs.writeFileSync(typeScriptconfigFile, configSource, 'utf-8')
|
|
236
|
-
print(`Config created at ${typeScriptconfigFile}`)
|
|
237
|
-
} else {
|
|
238
|
-
configSource = beautify(`/** @type {CodeceptJS.MainConfig} */\nexport const config = ${inspect(config, false, 4, false)}`)
|
|
239
|
-
|
|
240
|
-
if (hasConfigure) configSource = importCodeceptConfigure + configHeader + configSource
|
|
241
|
-
|
|
242
|
-
fs.writeFileSync(configFile, configSource, 'utf-8')
|
|
243
|
-
print(`Config created at ${configFile}`)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (config.output) {
|
|
247
|
-
if (!fileExists(config.output)) {
|
|
248
|
-
mkdirp.sync(path.join(testsPath, config.output))
|
|
249
|
-
print(`Directory for temporary output files created at '${config.output}'`)
|
|
250
|
-
} else {
|
|
251
|
-
print(`Directory for temporary output files is already created at '${config.output}'`)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const jsconfig = {
|
|
256
|
-
compilerOptions: {
|
|
257
|
-
allowJs: true,
|
|
258
|
-
},
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const tsconfig = {
|
|
262
|
-
'ts-node': {
|
|
263
|
-
files: true,
|
|
264
|
-
},
|
|
265
|
-
compilerOptions: {
|
|
266
|
-
target: 'es2018',
|
|
267
|
-
lib: ['es2018', 'DOM'],
|
|
268
|
-
esModuleInterop: true,
|
|
269
|
-
module: 'commonjs',
|
|
270
|
-
strictNullChecks: false,
|
|
271
|
-
types: ['codeceptjs', 'node'],
|
|
272
|
-
declaration: true,
|
|
273
|
-
skipLibCheck: true,
|
|
274
|
-
},
|
|
275
|
-
exclude: ['node_modules'],
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (isTypeScript) {
|
|
279
|
-
const tsconfigJson = beautify(JSON.stringify(tsconfig))
|
|
280
|
-
const tsconfigFile = path.join(testsPath, 'tsconfig.json')
|
|
281
|
-
if (fileExists(tsconfigFile)) {
|
|
282
|
-
print(`tsconfig.json already exists at ${tsconfigFile}`)
|
|
283
|
-
} else {
|
|
284
|
-
fs.writeFileSync(tsconfigFile, tsconfigJson)
|
|
285
|
-
}
|
|
286
|
-
} else {
|
|
287
|
-
const jsconfigJson = beautify(JSON.stringify(jsconfig))
|
|
288
|
-
const jsconfigFile = path.join(testsPath, 'jsconfig.json')
|
|
289
|
-
if (fileExists(jsconfigFile)) {
|
|
290
|
-
print(`jsconfig.json already exists at ${jsconfigFile}`)
|
|
291
|
-
} else {
|
|
292
|
-
fs.writeFileSync(jsconfigFile, jsconfigJson)
|
|
293
|
-
print(`Intellisense enabled in ${jsconfigFile}`)
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const generateDefinitionsManually = colors.bold(`To get auto-completion support, please generate type definitions: ${colors.green('npx codeceptjs def')}`)
|
|
298
|
-
|
|
299
|
-
if (packages) {
|
|
300
|
-
try {
|
|
301
|
-
install(packages)
|
|
302
|
-
} catch (err) {
|
|
303
|
-
print(colors.bold.red(err.toString()))
|
|
304
|
-
print()
|
|
305
|
-
print(colors.bold.red('Please install next packages manually:'))
|
|
306
|
-
print(`npm i ${packages.join(' ')} --save-dev`)
|
|
307
|
-
print()
|
|
308
|
-
print('Things to do after missing packages installed:')
|
|
309
|
-
print('☑', generateDefinitionsManually)
|
|
310
|
-
print('☑ Create first test:', colors.green('npx codeceptjs gt'))
|
|
311
|
-
print(colors.bold.magenta('Find more information at https://codecept.io'))
|
|
312
|
-
return
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
generateDefinitions(testsPath, {})
|
|
318
|
-
} catch (err) {
|
|
319
|
-
print(colors.bold.red("Couldn't generate type definitions"))
|
|
320
|
-
print(colors.red(err.toString()))
|
|
321
|
-
print('Skipping type definitions...')
|
|
322
|
-
print(generateDefinitionsManually)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
print('')
|
|
326
|
-
success(' Almost ready... Next step:')
|
|
327
|
-
|
|
328
|
-
const generatedTest = generateTest(testsPath)
|
|
329
|
-
if (!generatedTest) return
|
|
330
|
-
generatedTest.then(() => {
|
|
331
|
-
print('\n--')
|
|
332
|
-
print(colors.bold.green('CodeceptJS Installed! Enjoy supercharged testing! 🤩'))
|
|
333
|
-
print(colors.bold.magenta('Find more information at https://codecept.io'))
|
|
334
|
-
print()
|
|
335
|
-
})
|
|
336
|
-
}
|
|
302
|
+
try {
|
|
303
|
+
generateDefinitions(testsPath, {})
|
|
304
|
+
} catch (err) {
|
|
305
|
+
print(colors.bold.red("Couldn't generate type definitions"))
|
|
306
|
+
print(colors.red(err.toString()))
|
|
307
|
+
print('Skipping type definitions...')
|
|
308
|
+
print(generateDefinitionsManually)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
print('')
|
|
312
|
+
success(' Almost ready... Next step:')
|
|
313
|
+
|
|
314
|
+
if (skipPrompts) {
|
|
315
|
+
print('\n--')
|
|
316
|
+
print(colors.bold.green('CodeceptJS Installed! Enjoy supercharged testing! 🤩'))
|
|
317
|
+
print(colors.bold.magenta('Find more information at https://codecept.io'))
|
|
318
|
+
print()
|
|
319
|
+
return
|
|
320
|
+
}
|
|
337
321
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
executablePath: '// require("electron") or require("electron-forge")',
|
|
346
|
-
args: ['path/to/your/main.js'],
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
Object.keys(helperResult).forEach(key => {
|
|
351
|
-
const parts = key.split('_')
|
|
352
|
-
const helperName = parts[0]
|
|
353
|
-
const configName = parts[1]
|
|
354
|
-
if (!configName) return
|
|
355
|
-
config.helpers[helperName][configName] = helperResult[key]
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
print('')
|
|
359
|
-
await finish()
|
|
360
|
-
})
|
|
322
|
+
const generatedTest = generateTest(testsPath)
|
|
323
|
+
if (!generatedTest) return
|
|
324
|
+
generatedTest.then(() => {
|
|
325
|
+
print('\n--')
|
|
326
|
+
print(colors.bold.green('CodeceptJS Installed! Enjoy supercharged testing! 🤩'))
|
|
327
|
+
print(colors.bold.magenta('Find more information at https://codecept.io'))
|
|
328
|
+
print()
|
|
361
329
|
})
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const helperResult = skipPrompts
|
|
333
|
+
? defaultHelperAnswers(helperName)
|
|
334
|
+
: await (async () => {
|
|
335
|
+
print('Configure helpers...')
|
|
336
|
+
return inquirer.prompt(helperConfigs)
|
|
337
|
+
})()
|
|
338
|
+
|
|
339
|
+
if (helperResult.Playwright_browser === 'electron') {
|
|
340
|
+
delete helperResult.Playwright_url
|
|
341
|
+
delete helperResult.Playwright_show
|
|
342
|
+
|
|
343
|
+
helperResult.Playwright_electron = {
|
|
344
|
+
executablePath: '// require("electron") or require("electron-forge")',
|
|
345
|
+
args: ['path/to/your/main.js'],
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
Object.keys(helperResult).forEach(key => {
|
|
350
|
+
const parts = key.split('_')
|
|
351
|
+
const hName = parts[0]
|
|
352
|
+
const configName = parts[1]
|
|
353
|
+
if (!configName) return
|
|
354
|
+
config.helpers[hName][configName] = helperResult[key]
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
print('')
|
|
358
|
+
await finish()
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function defaultHelperAnswers(helperName) {
|
|
362
|
+
if (helperName === 'Playwright') {
|
|
363
|
+
return {
|
|
364
|
+
Playwright_browser: 'chromium',
|
|
365
|
+
Playwright_url: process.env.BASE_URL || 'http://localhost',
|
|
366
|
+
Playwright_show: false,
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return {}
|
|
362
370
|
}
|
|
363
371
|
|
|
364
372
|
function install(dependencies) {
|
|
@@ -399,30 +407,3 @@ function install(dependencies) {
|
|
|
399
407
|
}
|
|
400
408
|
return true
|
|
401
409
|
}
|
|
402
|
-
|
|
403
|
-
async function _actorTranslation(stepFile, translationSelected, translations) {
|
|
404
|
-
let actor
|
|
405
|
-
|
|
406
|
-
for (const translationAvailable of translations) {
|
|
407
|
-
if (actor) {
|
|
408
|
-
break
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (translationSelected === translationAvailable) {
|
|
412
|
-
const translationsModule = await import('../../translations/index.js')
|
|
413
|
-
const nameOfActor = (translationsModule.default || translationsModule)[translationAvailable].I
|
|
414
|
-
|
|
415
|
-
actor = {
|
|
416
|
-
[nameOfActor]: stepFile,
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (!actor) {
|
|
422
|
-
actor = {
|
|
423
|
-
I: stepFile,
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return actor
|
|
428
|
-
}
|