codeceptjs 4.0.0-beta.1 → 4.0.0-beta.3
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 +84 -81
- package/lib/actor.js +13 -13
- package/lib/ai.js +10 -13
- package/lib/assert/empty.js +20 -21
- package/lib/assert/equal.js +37 -39
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +46 -47
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +19 -22
- package/lib/assert.js +4 -2
- package/lib/cli.js +57 -49
- package/lib/codecept.js +142 -155
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +58 -52
- package/lib/command/definitions.js +88 -89
- package/lib/command/dryRun.js +71 -68
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +40 -38
- package/lib/command/init.js +290 -288
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +6 -2
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +20 -25
- package/lib/command/run-workers.js +64 -66
- package/lib/command/run.js +26 -29
- package/lib/command/utils.js +80 -65
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +10 -9
- package/lib/container.js +40 -48
- package/lib/data/context.js +60 -59
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/event.js +163 -167
- package/lib/heal.js +13 -17
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +73 -69
- package/lib/helper/Appium.js +413 -382
- package/lib/helper/ExpectHelper.js +40 -48
- package/lib/helper/FileSystem.js +80 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -14
- package/lib/helper/Nightmare.js +662 -566
- package/lib/helper/Playwright.js +1361 -1216
- package/lib/helper/Protractor.js +663 -627
- package/lib/helper/Puppeteer.js +1231 -1128
- package/lib/helper/REST.js +159 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -484
- package/lib/helper/WebDriver.js +1297 -1156
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +21 -18
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +14 -7
- package/lib/helper/network/utils.js +3 -2
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +6 -7
- package/lib/helper.js +1 -3
- package/lib/history.js +6 -5
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +25 -41
- package/lib/interfaces/bdd.js +47 -64
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +124 -118
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +32 -30
- package/lib/listener/steps.js +50 -53
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +6 -10
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +6 -10
- package/lib/parser.js +15 -12
- package/lib/pause.js +40 -33
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +29 -37
- package/lib/plugin/autoLogin.js +70 -65
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +115 -67
- package/lib/plugin/customLocator.js +21 -20
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +67 -108
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +32 -39
- package/lib/plugin/retryTo.js +46 -40
- package/lib/plugin/screenshotOnFail.js +109 -87
- package/lib/plugin/selenoid.js +131 -118
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +110 -91
- package/lib/plugin/stepTimeout.js +24 -23
- package/lib/plugin/subtitles.js +34 -35
- package/lib/plugin/tryTo.js +40 -30
- package/lib/plugin/wdio.js +78 -75
- package/lib/recorder.js +14 -17
- package/lib/rerun.js +11 -10
- package/lib/scenario.js +25 -23
- package/lib/secret.js +4 -2
- package/lib/session.js +10 -10
- package/lib/step.js +12 -9
- package/lib/store.js +2 -3
- package/lib/transform.js +1 -1
- package/lib/translation.js +7 -8
- package/lib/ui.js +12 -14
- package/lib/utils.js +70 -72
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +27 -25
- package/lib/workers.js +29 -32
- package/package.json +56 -57
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -13
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +415 -65
- package/typings/promiseBasedTypes.d.ts +32 -0
- package/typings/types.d.ts +32 -0
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
package/lib/helper/AI.js
CHANGED
|
@@ -1,39 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const Helper = require('@codeceptjs/helper')
|
|
2
|
+
const ora = require('ora-classic')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const ai = require('../ai')
|
|
6
|
+
const standardActingHelpers = require('../plugin/standardActingHelpers')
|
|
7
|
+
const Container = require('../container')
|
|
8
|
+
const { splitByChunks, minifyHtml } = require('../html')
|
|
9
|
+
const { beautify } = require('../utils')
|
|
10
|
+
const output = require('../output')
|
|
11
|
+
const { registerVariable } = require('../pause')
|
|
12
|
+
|
|
13
|
+
const gtpRole = {
|
|
14
|
+
user: 'user',
|
|
15
|
+
}
|
|
6
16
|
|
|
7
17
|
/**
|
|
8
18
|
* AI Helper for CodeceptJS.
|
|
9
19
|
*
|
|
10
20
|
* This helper class provides integration with the AI GPT-3.5 or 4 language model for generating responses to questions or prompts within the context of web pages. It allows you to interact with the GPT-3.5 model to obtain intelligent responses based on HTML fragments or general prompts.
|
|
11
|
-
* This helper should be enabled with any web helpers like Playwright or Puppeteer or
|
|
21
|
+
* This helper should be enabled with any web helpers like Playwright or Puppeteer or WebDriver to ensure the HTML context is available.
|
|
22
|
+
*
|
|
23
|
+
* Use it only in development mode. It is recommended to run it only inside pause() mode.
|
|
12
24
|
*
|
|
13
25
|
* ## Configuration
|
|
14
26
|
*
|
|
15
|
-
* This helper should be configured in codecept.
|
|
27
|
+
* This helper should be configured in codecept.conf.{js|ts}
|
|
16
28
|
*
|
|
17
29
|
* * `chunkSize`: (optional, default: 80000) - The maximum number of characters to send to the AI API at once. We split HTML fragments by 8000 chars to not exceed token limit. Increase this value if you use GPT-4.
|
|
18
30
|
*/
|
|
19
31
|
class AI extends Helper {
|
|
20
32
|
constructor(config) {
|
|
21
|
-
super(config)
|
|
22
|
-
this.aiAssistant =
|
|
33
|
+
super(config)
|
|
34
|
+
this.aiAssistant = ai
|
|
23
35
|
|
|
24
36
|
this.options = {
|
|
25
37
|
chunkSize: 80000,
|
|
26
|
-
}
|
|
27
|
-
this.options = { ...this.options, ...config }
|
|
38
|
+
}
|
|
39
|
+
this.options = { ...this.options, ...config }
|
|
40
|
+
this.aiAssistant.enable(this.config)
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
_beforeSuite() {
|
|
31
|
-
const helpers = Container.helpers()
|
|
44
|
+
const helpers = Container.helpers()
|
|
32
45
|
|
|
33
46
|
for (const helperName of standardActingHelpers) {
|
|
34
47
|
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
35
|
-
this.helper = helpers[helperName]
|
|
36
|
-
break
|
|
48
|
+
this.helper = helpers[helperName]
|
|
49
|
+
break
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
52
|
}
|
|
@@ -50,30 +63,34 @@ class AI extends Helper {
|
|
|
50
63
|
* @returns {Promise<string>} - A Promise that resolves to the generated responses from the GPT model, joined by newlines.
|
|
51
64
|
*/
|
|
52
65
|
async askGptOnPage(prompt) {
|
|
53
|
-
const html = await this.helper.grabSource()
|
|
66
|
+
const html = await this.helper.grabSource()
|
|
54
67
|
|
|
55
|
-
const htmlChunks = splitByChunks(html, this.options.chunkSize)
|
|
68
|
+
const htmlChunks = splitByChunks(html, this.options.chunkSize)
|
|
56
69
|
|
|
57
|
-
if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`)
|
|
70
|
+
if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`)
|
|
58
71
|
|
|
59
|
-
const responses = []
|
|
72
|
+
const responses = []
|
|
60
73
|
|
|
61
74
|
for (const chunk of htmlChunks) {
|
|
62
75
|
const messages = [
|
|
63
|
-
{ role:
|
|
64
|
-
{ role:
|
|
65
|
-
]
|
|
76
|
+
{ role: gtpRole.user, content: prompt },
|
|
77
|
+
{ role: gtpRole.user, content: `Within this HTML: ${await minifyHtml(chunk)}` },
|
|
78
|
+
]
|
|
66
79
|
|
|
67
|
-
if (htmlChunks.length > 1)
|
|
80
|
+
if (htmlChunks.length > 1)
|
|
81
|
+
messages.push({
|
|
82
|
+
role: 'user',
|
|
83
|
+
content: 'If action is not possible on this page, do not propose anything, I will send another HTML fragment',
|
|
84
|
+
})
|
|
68
85
|
|
|
69
|
-
const response = await this.
|
|
86
|
+
const response = await this._processAIRequest(messages)
|
|
70
87
|
|
|
71
|
-
|
|
88
|
+
output.print(response)
|
|
72
89
|
|
|
73
|
-
responses.push(response)
|
|
90
|
+
responses.push(response)
|
|
74
91
|
}
|
|
75
92
|
|
|
76
|
-
return responses.join('\n\n')
|
|
93
|
+
return responses.join('\n\n')
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
/**
|
|
@@ -89,36 +106,108 @@ class AI extends Helper {
|
|
|
89
106
|
* @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
|
|
90
107
|
*/
|
|
91
108
|
async askGptOnPageFragment(prompt, locator) {
|
|
92
|
-
const html = await this.helper.grabHTMLFrom(locator)
|
|
109
|
+
const html = await this.helper.grabHTMLFrom(locator)
|
|
93
110
|
|
|
94
111
|
const messages = [
|
|
95
|
-
{ role:
|
|
96
|
-
{ role:
|
|
97
|
-
]
|
|
112
|
+
{ role: gtpRole.user, content: prompt },
|
|
113
|
+
{ role: gtpRole.user, content: `Within this HTML: ${await minifyHtml(html)}` },
|
|
114
|
+
]
|
|
98
115
|
|
|
99
|
-
const response = await this.
|
|
116
|
+
const response = await this._processAIRequest(messages)
|
|
100
117
|
|
|
101
|
-
|
|
118
|
+
output.print(response)
|
|
102
119
|
|
|
103
|
-
return response
|
|
120
|
+
return response
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
/**
|
|
107
|
-
* Send a general request to
|
|
124
|
+
* Send a general request to AI and return response.
|
|
108
125
|
* @param {string} prompt
|
|
109
126
|
* @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
|
|
110
127
|
*/
|
|
111
128
|
async askGptGeneralPrompt(prompt) {
|
|
112
|
-
const messages = [
|
|
113
|
-
|
|
114
|
-
|
|
129
|
+
const messages = [{ role: gtpRole.user, content: prompt }]
|
|
130
|
+
|
|
131
|
+
const response = await this._processAIRequest(messages)
|
|
132
|
+
|
|
133
|
+
output.print(response)
|
|
134
|
+
|
|
135
|
+
return response
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generates PageObject for current page using AI.
|
|
140
|
+
*
|
|
141
|
+
* It saves the PageObject to the output directory. You can review the page object and adjust it as needed and move to pages directory.
|
|
142
|
+
* Prompt can be customized in a global config file.
|
|
143
|
+
*
|
|
144
|
+
* ```js
|
|
145
|
+
* // create page object for whole page
|
|
146
|
+
* I.askForPageObject('home');
|
|
147
|
+
*
|
|
148
|
+
* // create page object with extra prompt
|
|
149
|
+
* I.askForPageObject('home', 'implement signIn(username, password) method');
|
|
150
|
+
*
|
|
151
|
+
* // create page object for a specific element
|
|
152
|
+
* I.askForPageObject('home', null, '.detail');
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* Asks for a page object based on the provided page name, locator, and extra prompt.
|
|
156
|
+
*
|
|
157
|
+
* @async
|
|
158
|
+
* @param {string} pageName - The name of the page to retrieve the object for.
|
|
159
|
+
* @param {string|null} [extraPrompt=null] - An optional extra prompt for additional context or information.
|
|
160
|
+
* @param {string|null} [locator=null] - An optional locator to find a specific element on the page.
|
|
161
|
+
* @returns {Promise<Object>} A promise that resolves to the requested page object.
|
|
162
|
+
*/
|
|
163
|
+
async askForPageObject(pageName, extraPrompt = null, locator = null) {
|
|
164
|
+
const spinner = ora(' Processing AI request...').start()
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const html = locator ? await this.helper.grabHTMLFrom(locator) : await this.helper.grabSource()
|
|
168
|
+
await this.aiAssistant.setHtmlContext(html)
|
|
169
|
+
const response = await this.aiAssistant.generatePageObject(extraPrompt, locator)
|
|
170
|
+
spinner.stop()
|
|
171
|
+
|
|
172
|
+
if (!response[0]) {
|
|
173
|
+
output.error('No response from AI')
|
|
174
|
+
return ''
|
|
175
|
+
}
|
|
115
176
|
|
|
116
|
-
|
|
177
|
+
const code = beautify(response[0])
|
|
117
178
|
|
|
118
|
-
|
|
179
|
+
output.print('----- Generated PageObject ----')
|
|
180
|
+
output.print(code)
|
|
181
|
+
output.print('-------------------------------')
|
|
182
|
+
|
|
183
|
+
const fileName = path.join(output_dir, `${pageName}Page-${Date.now()}.js`)
|
|
184
|
+
|
|
185
|
+
output.print(output.styles.bold(`Page object for ${pageName} is saved to ${output.styles.bold(fileName)}`))
|
|
186
|
+
fs.writeFileSync(fileName, code)
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
registerVariable('page', require(fileName))
|
|
190
|
+
output.success('Page object registered for this session as `page` variable')
|
|
191
|
+
output.print('Use `=>page.methodName()` in shell to run methods of page object')
|
|
192
|
+
output.print('Use `click(page.locatorName)` to check locators of page object')
|
|
193
|
+
} catch (err) {
|
|
194
|
+
output.error('Error while registering page object')
|
|
195
|
+
output.error(err.message)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return code
|
|
199
|
+
} catch (e) {
|
|
200
|
+
spinner.stop()
|
|
201
|
+
throw Error(`Something went wrong! ${e.message}`)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
119
204
|
|
|
120
|
-
|
|
205
|
+
async _processAIRequest(messages) {
|
|
206
|
+
const spinner = ora(' Processing AI request...').start()
|
|
207
|
+
const response = await this.aiAssistant.createCompletion(messages)
|
|
208
|
+
spinner.stop()
|
|
209
|
+
return response
|
|
121
210
|
}
|
|
122
211
|
}
|
|
123
212
|
|
|
124
|
-
|
|
213
|
+
module.exports = AI
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
const Helper = require('@codeceptjs/helper')
|
|
4
|
+
const REST = require('./REST')
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Helper for managing remote data using REST API.
|
|
@@ -183,67 +184,67 @@ import REST from './REST';
|
|
|
183
184
|
*/
|
|
184
185
|
class ApiDataFactory extends Helper {
|
|
185
186
|
constructor(config) {
|
|
186
|
-
super(config)
|
|
187
|
+
super(config)
|
|
187
188
|
|
|
188
189
|
const defaultConfig = {
|
|
189
190
|
cleanup: true,
|
|
190
191
|
REST: {},
|
|
191
192
|
factories: {},
|
|
192
193
|
returnId: false,
|
|
193
|
-
}
|
|
194
|
-
this.config = Object.assign(defaultConfig, this.config)
|
|
194
|
+
}
|
|
195
|
+
this.config = Object.assign(defaultConfig, this.config)
|
|
195
196
|
|
|
196
|
-
if (this.config.headers) this.config.REST.defaultHeaders = this.config.headers
|
|
197
|
-
if (this.config.onRequest) this.config.REST.onRequest = this.config.onRequest
|
|
198
|
-
this.restHelper = new REST(Object.assign(this.config.REST, { endpoint: this.config.endpoint }))
|
|
199
|
-
this.factories = this.config.factories
|
|
197
|
+
if (this.config.headers) this.config.REST.defaultHeaders = this.config.headers
|
|
198
|
+
if (this.config.onRequest) this.config.REST.onRequest = this.config.onRequest
|
|
199
|
+
this.restHelper = new REST(Object.assign(this.config.REST, { endpoint: this.config.endpoint }))
|
|
200
|
+
this.factories = this.config.factories
|
|
200
201
|
|
|
201
202
|
for (const factory in this.factories) {
|
|
202
|
-
const factoryConfig = this.factories[factory]
|
|
203
|
+
const factoryConfig = this.factories[factory]
|
|
203
204
|
if (!factoryConfig.uri && !factoryConfig.create) {
|
|
204
205
|
throw new Error(`Uri for factory "${factory}" is not defined. Please set "uri" parameter:
|
|
205
206
|
|
|
206
207
|
"factories": {
|
|
207
208
|
"${factory}": {
|
|
208
209
|
"uri": ...
|
|
209
|
-
`)
|
|
210
|
+
`)
|
|
210
211
|
}
|
|
211
212
|
|
|
212
|
-
if (!factoryConfig.create) factoryConfig.create = { post: factoryConfig.uri }
|
|
213
|
-
if (!factoryConfig.delete) factoryConfig.delete = { delete: `${factoryConfig.uri}/{id}` }
|
|
213
|
+
if (!factoryConfig.create) factoryConfig.create = { post: factoryConfig.uri }
|
|
214
|
+
if (!factoryConfig.delete) factoryConfig.delete = { delete: `${factoryConfig.uri}/{id}` }
|
|
214
215
|
|
|
215
|
-
this.factories[factory] = factoryConfig
|
|
216
|
+
this.factories[factory] = factoryConfig
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
this.created = {}
|
|
219
|
-
Object.keys(this.factories).forEach(f => this.created[f] = [])
|
|
219
|
+
this.created = {}
|
|
220
|
+
Object.keys(this.factories).forEach((f) => (this.created[f] = []))
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
static _checkRequirements() {
|
|
223
224
|
try {
|
|
224
|
-
require('axios')
|
|
225
|
-
require('rosie')
|
|
225
|
+
require('axios')
|
|
226
|
+
require('rosie')
|
|
226
227
|
} catch (e) {
|
|
227
|
-
return ['axios', 'rosie']
|
|
228
|
+
return ['axios', 'rosie']
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
_after() {
|
|
232
233
|
if (!this.config.cleanup || this.config.cleanup === false) {
|
|
233
|
-
return Promise.resolve()
|
|
234
|
+
return Promise.resolve()
|
|
234
235
|
}
|
|
235
|
-
const promises = []
|
|
236
|
+
const promises = []
|
|
236
237
|
|
|
237
238
|
// clean up all created items
|
|
238
239
|
for (const factoryName in this.created) {
|
|
239
|
-
const createdItems = this.created[factoryName]
|
|
240
|
-
if (!createdItems.length) continue
|
|
241
|
-
this.debug(`Deleting ${createdItems.length} ${factoryName}(s)`)
|
|
240
|
+
const createdItems = this.created[factoryName]
|
|
241
|
+
if (!createdItems.length) continue
|
|
242
|
+
this.debug(`Deleting ${createdItems.length} ${factoryName}(s)`)
|
|
242
243
|
for (const id in createdItems) {
|
|
243
|
-
promises.push(this._requestDelete(factoryName, createdItems[id]))
|
|
244
|
+
promises.push(this._requestDelete(factoryName, createdItems[id]))
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
|
-
return Promise.all(promises)
|
|
247
|
+
return Promise.all(promises)
|
|
247
248
|
}
|
|
248
249
|
|
|
249
250
|
/**
|
|
@@ -265,9 +266,9 @@ class ApiDataFactory extends Helper {
|
|
|
265
266
|
* @returns {Promise<*>}
|
|
266
267
|
*/
|
|
267
268
|
have(factory, params, options) {
|
|
268
|
-
const item = this._createItem(factory, params, options)
|
|
269
|
-
this.debug(`Creating ${factory} ${JSON.stringify(item)}`)
|
|
270
|
-
return this._requestCreate(factory, item)
|
|
269
|
+
const item = this._createItem(factory, params, options)
|
|
270
|
+
this.debug(`Creating ${factory} ${JSON.stringify(item)}`)
|
|
271
|
+
return this._requestCreate(factory, item)
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
/**
|
|
@@ -290,27 +291,27 @@ class ApiDataFactory extends Helper {
|
|
|
290
291
|
* @param {*} [options]
|
|
291
292
|
*/
|
|
292
293
|
haveMultiple(factory, times, params, options) {
|
|
293
|
-
const promises = []
|
|
294
|
+
const promises = []
|
|
294
295
|
for (let i = 0; i < times; i++) {
|
|
295
|
-
promises.push(this.have(factory, params, options))
|
|
296
|
+
promises.push(this.have(factory, params, options))
|
|
296
297
|
}
|
|
297
|
-
return Promise.all(promises)
|
|
298
|
+
return Promise.all(promises)
|
|
298
299
|
}
|
|
299
300
|
|
|
300
301
|
_createItem(model, data, options) {
|
|
301
302
|
if (!this.factories[model]) {
|
|
302
|
-
throw new Error(`Factory ${model} is not defined in config`)
|
|
303
|
+
throw new Error(`Factory ${model} is not defined in config`)
|
|
303
304
|
}
|
|
304
|
-
let modulePath = this.factories[model].factory
|
|
305
|
+
let modulePath = this.factories[model].factory
|
|
305
306
|
try {
|
|
306
307
|
try {
|
|
307
|
-
require.resolve(modulePath)
|
|
308
|
+
require.resolve(modulePath)
|
|
308
309
|
} catch (e) {
|
|
309
|
-
modulePath = path.join(global.codecept_dir, modulePath)
|
|
310
|
+
modulePath = path.join(global.codecept_dir, modulePath)
|
|
310
311
|
}
|
|
311
312
|
// check if the new syntax `export default new Factory()` is used and loads the builder, otherwise loads the module that used old syntax `module.exports = new Factory()`.
|
|
312
|
-
const builder = require(modulePath).default || require(modulePath)
|
|
313
|
-
return builder.build(data, options)
|
|
313
|
+
const builder = require(modulePath).default || require(modulePath)
|
|
314
|
+
return builder.build(data, options)
|
|
314
315
|
} catch (err) {
|
|
315
316
|
throw new Error(`Couldn't load factory file from ${modulePath}, check that
|
|
316
317
|
|
|
@@ -321,17 +322,17 @@ class ApiDataFactory extends Helper {
|
|
|
321
322
|
points to valid factory file.
|
|
322
323
|
Factory file should export an object with build method.
|
|
323
324
|
|
|
324
|
-
Current file error: ${err.message}`)
|
|
325
|
+
Current file error: ${err.message}`)
|
|
325
326
|
}
|
|
326
327
|
}
|
|
327
328
|
|
|
328
329
|
_fetchId(body, factory) {
|
|
329
330
|
if (this.config.factories[factory].fetchId) {
|
|
330
|
-
return this.config.factories[factory].fetchId(body)
|
|
331
|
+
return this.config.factories[factory].fetchId(body)
|
|
331
332
|
}
|
|
332
|
-
if (body.id) return body.id
|
|
333
|
-
if (body[factory] && body[factory].id) return body[factory].id
|
|
334
|
-
return null
|
|
333
|
+
if (body.id) return body.id
|
|
334
|
+
if (body[factory] && body[factory].id) return body[factory].id
|
|
335
|
+
return null
|
|
335
336
|
}
|
|
336
337
|
|
|
337
338
|
/**
|
|
@@ -342,27 +343,27 @@ Current file error: ${err.message}`);
|
|
|
342
343
|
* @param {*} data
|
|
343
344
|
*/
|
|
344
345
|
_requestCreate(factory, data) {
|
|
345
|
-
let request = createRequestFromFunction(this.factories[factory].create, data)
|
|
346
|
+
let request = createRequestFromFunction(this.factories[factory].create, data)
|
|
346
347
|
|
|
347
348
|
if (!request) {
|
|
348
|
-
const method = Object.keys(this.factories[factory].create)[0]
|
|
349
|
-
const url = this.factories[factory].create[method]
|
|
349
|
+
const method = Object.keys(this.factories[factory].create)[0]
|
|
350
|
+
const url = this.factories[factory].create[method]
|
|
350
351
|
request = {
|
|
351
352
|
method,
|
|
352
353
|
url,
|
|
353
354
|
data,
|
|
354
|
-
}
|
|
355
|
+
}
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
request.baseURL = this.config.endpoint
|
|
358
|
+
request.baseURL = this.config.endpoint
|
|
358
359
|
|
|
359
360
|
return this.restHelper._executeRequest(request).then((resp) => {
|
|
360
|
-
const id = this._fetchId(resp.data, factory)
|
|
361
|
-
this.created[factory].push(id)
|
|
362
|
-
this.debugSection('Created', `Id: ${id}`)
|
|
363
|
-
if (this.config.returnId) return id
|
|
364
|
-
return resp.data
|
|
365
|
-
})
|
|
361
|
+
const id = this._fetchId(resp.data, factory)
|
|
362
|
+
this.created[factory].push(id)
|
|
363
|
+
this.debugSection('Created', `Id: ${id}`)
|
|
364
|
+
if (this.config.returnId) return id
|
|
365
|
+
return resp.data
|
|
366
|
+
})
|
|
366
367
|
}
|
|
367
368
|
|
|
368
369
|
/**
|
|
@@ -373,37 +374,40 @@ Current file error: ${err.message}`);
|
|
|
373
374
|
* @param {*} id
|
|
374
375
|
*/
|
|
375
376
|
_requestDelete(factory, id) {
|
|
376
|
-
if (!this.factories[factory].delete) return
|
|
377
|
-
let request = createRequestFromFunction(this.factories[factory].delete, id)
|
|
377
|
+
if (!this.factories[factory].delete) return
|
|
378
|
+
let request = createRequestFromFunction(this.factories[factory].delete, id)
|
|
378
379
|
|
|
379
380
|
if (!request) {
|
|
380
|
-
const method = Object.keys(this.factories[factory].delete)[0]
|
|
381
|
+
const method = Object.keys(this.factories[factory].delete)[0]
|
|
381
382
|
|
|
382
|
-
const url = this.factories[factory].delete[method].replace('{id}', id)
|
|
383
|
+
const url = this.factories[factory].delete[method].replace('{id}', id)
|
|
383
384
|
|
|
384
385
|
request = {
|
|
385
386
|
method,
|
|
386
387
|
url,
|
|
387
|
-
}
|
|
388
|
+
}
|
|
388
389
|
}
|
|
389
390
|
|
|
390
|
-
request.baseURL = this.config.endpoint
|
|
391
|
+
request.baseURL = this.config.endpoint
|
|
391
392
|
|
|
392
393
|
if (request.url.match(/^undefined/)) {
|
|
393
|
-
return this.debugSection(
|
|
394
|
+
return this.debugSection(
|
|
395
|
+
'Please configure the delete request in your ApiDataFactory helper',
|
|
396
|
+
"delete: () => ({ method: 'DELETE', url: '/api/users' })",
|
|
397
|
+
)
|
|
394
398
|
}
|
|
395
399
|
|
|
396
400
|
return this.restHelper._executeRequest(request).then(() => {
|
|
397
|
-
const idx = this.created[factory].indexOf(id)
|
|
398
|
-
this.debugSection('Deleted Id', `Id: ${id}`)
|
|
399
|
-
this.created[factory].splice(idx, 1)
|
|
400
|
-
})
|
|
401
|
+
const idx = this.created[factory].indexOf(id)
|
|
402
|
+
this.debugSection('Deleted Id', `Id: ${id}`)
|
|
403
|
+
this.created[factory].splice(idx, 1)
|
|
404
|
+
})
|
|
401
405
|
}
|
|
402
406
|
}
|
|
403
407
|
|
|
404
|
-
|
|
408
|
+
module.exports = ApiDataFactory
|
|
405
409
|
|
|
406
410
|
function createRequestFromFunction(param, data) {
|
|
407
|
-
if (typeof param !== 'function') return
|
|
408
|
-
return param(data)
|
|
411
|
+
if (typeof param !== 'function') return
|
|
412
|
+
return param(data)
|
|
409
413
|
}
|