codeceptjs 3.6.7 → 4.0.0-beta.2
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 +81 -84
- package/lib/actor.js +13 -13
- package/lib/ai.js +13 -10
- package/lib/assert/empty.js +21 -20
- package/lib/assert/equal.js +39 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +47 -46
- package/lib/assert/throws.js +11 -13
- package/lib/assert/truth.js +22 -19
- package/lib/assert.js +2 -4
- package/lib/cli.js +49 -57
- package/lib/codecept.js +155 -142
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +52 -58
- package/lib/command/definitions.js +89 -88
- package/lib/command/dryRun.js +68 -71
- package/lib/command/generate.js +188 -197
- package/lib/command/gherkin/init.js +16 -27
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +38 -40
- package/lib/command/init.js +288 -290
- 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 +2 -6
- package/lib/command/run-multiple.js +93 -113
- package/lib/command/run-rerun.js +25 -20
- package/lib/command/run-workers.js +66 -64
- package/lib/command/run.js +29 -26
- package/lib/command/utils.js +65 -80
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +9 -10
- package/lib/container.js +48 -40
- package/lib/data/context.js +59 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +20 -26
- package/lib/dirname.js +5 -0
- package/lib/event.js +167 -163
- package/lib/heal.js +17 -13
- package/lib/helper/AI.js +41 -130
- package/lib/helper/ApiDataFactory.js +69 -73
- package/lib/helper/Appium.js +381 -412
- package/lib/helper/Expect.js +425 -0
- package/lib/helper/ExpectHelper.js +48 -40
- package/lib/helper/FileSystem.js +79 -80
- package/lib/helper/GraphQL.js +43 -44
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +62 -65
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +14 -12
- package/lib/helper/Nightmare.js +566 -662
- package/lib/helper/Playwright.js +1216 -1361
- package/lib/helper/Protractor.js +627 -663
- package/lib/helper/Puppeteer.js +1128 -1231
- package/lib/helper/REST.js +68 -159
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +484 -490
- package/lib/helper/WebDriver.js +1156 -1297
- 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 +18 -21
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +7 -14
- package/lib/helper/network/utils.js +2 -3
- 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 +7 -6
- package/lib/helper.js +3 -1
- package/lib/history.js +5 -6
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +41 -25
- package/lib/interfaces/bdd.js +64 -47
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +118 -124
- 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 +30 -32
- package/lib/listener/steps.js +53 -50
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +10 -6
- package/lib/mochaFactory.js +15 -18
- package/lib/output.js +10 -6
- package/lib/parser.js +12 -15
- package/lib/pause.js +33 -40
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +37 -29
- package/lib/plugin/autoLogin.js +65 -70
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +67 -115
- package/lib/plugin/customLocator.js +20 -21
- 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 +108 -67
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +39 -32
- package/lib/plugin/retryTo.js +40 -46
- package/lib/plugin/screenshotOnFail.js +87 -109
- package/lib/plugin/selenoid.js +118 -131
- package/lib/plugin/standardActingHelpers.js +8 -2
- package/lib/plugin/stepByStepReport.js +91 -110
- package/lib/plugin/stepTimeout.js +23 -24
- package/lib/plugin/subtitles.js +35 -34
- package/lib/plugin/tryTo.js +30 -40
- package/lib/plugin/wdio.js +75 -78
- package/lib/recorder.js +17 -14
- package/lib/rerun.js +10 -11
- package/lib/scenario.js +23 -25
- package/lib/secret.js +2 -4
- package/lib/session.js +10 -10
- package/lib/step.js +9 -12
- package/lib/store.js +3 -2
- package/lib/transform.js +1 -1
- package/lib/translation.js +8 -7
- package/lib/ui.js +14 -12
- package/lib/utils.js +72 -70
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +25 -27
- package/lib/workers.js +32 -29
- package/package.json +53 -51
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +13 -9
- 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 +65 -415
package/lib/helper/AI.js
CHANGED
|
@@ -1,52 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
}
|
|
1
|
+
import Helper from '@codeceptjs/helper';
|
|
2
|
+
import AiAssistant from '../ai.js';
|
|
3
|
+
import standardActingHelpers from '../plugin/standardActingHelpers.js';
|
|
4
|
+
import Container from '../container.js';
|
|
5
|
+
import { splitByChunks, minifyHtml } from '../html.js';
|
|
16
6
|
|
|
17
7
|
/**
|
|
18
8
|
* AI Helper for CodeceptJS.
|
|
19
9
|
*
|
|
20
10
|
* 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.
|
|
21
|
-
* This helper should be enabled with any web helpers like Playwright or Puppeteer or
|
|
22
|
-
*
|
|
23
|
-
* Use it only in development mode. It is recommended to run it only inside pause() mode.
|
|
11
|
+
* This helper should be enabled with any web helpers like Playwright or Puppeteer or WebDrvier to ensure the HTML context is available.
|
|
24
12
|
*
|
|
25
13
|
* ## Configuration
|
|
26
14
|
*
|
|
27
|
-
* This helper should be configured in codecept.conf.
|
|
15
|
+
* This helper should be configured in codecept.json or codecept.conf.js
|
|
28
16
|
*
|
|
29
17
|
* * `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.
|
|
30
18
|
*/
|
|
31
19
|
class AI extends Helper {
|
|
32
20
|
constructor(config) {
|
|
33
|
-
super(config)
|
|
34
|
-
this.aiAssistant =
|
|
21
|
+
super(config);
|
|
22
|
+
this.aiAssistant = AiAssistant;
|
|
35
23
|
|
|
36
24
|
this.options = {
|
|
37
25
|
chunkSize: 80000,
|
|
38
|
-
}
|
|
39
|
-
this.options = { ...this.options, ...config }
|
|
40
|
-
this.aiAssistant.enable(this.config)
|
|
26
|
+
};
|
|
27
|
+
this.options = { ...this.options, ...config };
|
|
41
28
|
}
|
|
42
29
|
|
|
43
30
|
_beforeSuite() {
|
|
44
|
-
const helpers = Container.helpers()
|
|
31
|
+
const helpers = Container.helpers();
|
|
45
32
|
|
|
46
33
|
for (const helperName of standardActingHelpers) {
|
|
47
34
|
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
48
|
-
this.helper = helpers[helperName]
|
|
49
|
-
break
|
|
35
|
+
this.helper = helpers[helperName];
|
|
36
|
+
break;
|
|
50
37
|
}
|
|
51
38
|
}
|
|
52
39
|
}
|
|
@@ -63,34 +50,30 @@ class AI extends Helper {
|
|
|
63
50
|
* @returns {Promise<string>} - A Promise that resolves to the generated responses from the GPT model, joined by newlines.
|
|
64
51
|
*/
|
|
65
52
|
async askGptOnPage(prompt) {
|
|
66
|
-
const html = await this.helper.grabSource()
|
|
53
|
+
const html = await this.helper.grabSource();
|
|
67
54
|
|
|
68
|
-
const htmlChunks = splitByChunks(html, this.options.chunkSize)
|
|
55
|
+
const htmlChunks = splitByChunks(html, this.options.chunkSize);
|
|
69
56
|
|
|
70
|
-
if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`)
|
|
57
|
+
if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`);
|
|
71
58
|
|
|
72
|
-
const responses = []
|
|
59
|
+
const responses = [];
|
|
73
60
|
|
|
74
61
|
for (const chunk of htmlChunks) {
|
|
75
62
|
const messages = [
|
|
76
|
-
{ role:
|
|
77
|
-
{ role:
|
|
78
|
-
]
|
|
63
|
+
{ role: 'user', content: prompt },
|
|
64
|
+
{ role: 'user', content: `Within this HTML: ${minifyHtml(chunk)}` },
|
|
65
|
+
];
|
|
79
66
|
|
|
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
|
-
})
|
|
67
|
+
if (htmlChunks.length > 1) messages.push({ role: 'user', content: 'If action is not possible on this page, do not propose anything, I will send another HTML fragment' });
|
|
85
68
|
|
|
86
|
-
const response = await this.
|
|
69
|
+
const response = await this.aiAssistant.createCompletion(messages);
|
|
87
70
|
|
|
88
|
-
|
|
71
|
+
console.log(response);
|
|
89
72
|
|
|
90
|
-
responses.push(response)
|
|
73
|
+
responses.push(response);
|
|
91
74
|
}
|
|
92
75
|
|
|
93
|
-
return responses.join('\n\n')
|
|
76
|
+
return responses.join('\n\n');
|
|
94
77
|
}
|
|
95
78
|
|
|
96
79
|
/**
|
|
@@ -106,108 +89,36 @@ class AI extends Helper {
|
|
|
106
89
|
* @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
|
|
107
90
|
*/
|
|
108
91
|
async askGptOnPageFragment(prompt, locator) {
|
|
109
|
-
const html = await this.helper.grabHTMLFrom(locator)
|
|
92
|
+
const html = await this.helper.grabHTMLFrom(locator);
|
|
110
93
|
|
|
111
94
|
const messages = [
|
|
112
|
-
{ role:
|
|
113
|
-
{ role:
|
|
114
|
-
]
|
|
95
|
+
{ role: 'user', content: prompt },
|
|
96
|
+
{ role: 'user', content: `Within this HTML: ${minifyHtml(html)}` },
|
|
97
|
+
];
|
|
115
98
|
|
|
116
|
-
const response = await this.
|
|
99
|
+
const response = await this.aiAssistant.createCompletion(messages);
|
|
117
100
|
|
|
118
|
-
|
|
101
|
+
console.log(response);
|
|
119
102
|
|
|
120
|
-
return response
|
|
103
|
+
return response;
|
|
121
104
|
}
|
|
122
105
|
|
|
123
106
|
/**
|
|
124
|
-
* Send a general request to
|
|
107
|
+
* Send a general request to ChatGPT and return response.
|
|
125
108
|
* @param {string} prompt
|
|
126
109
|
* @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
|
|
127
110
|
*/
|
|
128
111
|
async askGptGeneralPrompt(prompt) {
|
|
129
|
-
const messages = [
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
}
|
|
176
|
-
|
|
177
|
-
const code = beautify(response[0])
|
|
178
|
-
|
|
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`)
|
|
112
|
+
const messages = [
|
|
113
|
+
{ role: 'user', content: prompt },
|
|
114
|
+
];
|
|
184
115
|
|
|
185
|
-
|
|
186
|
-
fs.writeFileSync(fileName, code)
|
|
116
|
+
const response = await this.aiAssistant.createCompletion(messages);
|
|
187
117
|
|
|
188
|
-
|
|
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
|
-
}
|
|
118
|
+
console.log(response);
|
|
204
119
|
|
|
205
|
-
|
|
206
|
-
const spinner = ora(' Processing AI request...').start()
|
|
207
|
-
const response = await this.aiAssistant.createCompletion(messages)
|
|
208
|
-
spinner.stop()
|
|
209
|
-
return response
|
|
120
|
+
return response;
|
|
210
121
|
}
|
|
211
122
|
}
|
|
212
123
|
|
|
213
|
-
|
|
124
|
+
export default AI;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const REST = require('./REST')
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import Helper from '@codeceptjs/helper';
|
|
3
|
+
import REST from './REST';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Helper for managing remote data using REST API.
|
|
@@ -184,67 +183,67 @@ const REST = require('./REST')
|
|
|
184
183
|
*/
|
|
185
184
|
class ApiDataFactory extends Helper {
|
|
186
185
|
constructor(config) {
|
|
187
|
-
super(config)
|
|
186
|
+
super(config);
|
|
188
187
|
|
|
189
188
|
const defaultConfig = {
|
|
190
189
|
cleanup: true,
|
|
191
190
|
REST: {},
|
|
192
191
|
factories: {},
|
|
193
192
|
returnId: false,
|
|
194
|
-
}
|
|
195
|
-
this.config = Object.assign(defaultConfig, this.config)
|
|
193
|
+
};
|
|
194
|
+
this.config = Object.assign(defaultConfig, this.config);
|
|
196
195
|
|
|
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
|
|
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;
|
|
201
200
|
|
|
202
201
|
for (const factory in this.factories) {
|
|
203
|
-
const factoryConfig = this.factories[factory]
|
|
202
|
+
const factoryConfig = this.factories[factory];
|
|
204
203
|
if (!factoryConfig.uri && !factoryConfig.create) {
|
|
205
204
|
throw new Error(`Uri for factory "${factory}" is not defined. Please set "uri" parameter:
|
|
206
205
|
|
|
207
206
|
"factories": {
|
|
208
207
|
"${factory}": {
|
|
209
208
|
"uri": ...
|
|
210
|
-
`)
|
|
209
|
+
`);
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
if (!factoryConfig.create) factoryConfig.create = { post: factoryConfig.uri }
|
|
214
|
-
if (!factoryConfig.delete) factoryConfig.delete = { delete: `${factoryConfig.uri}/{id}` }
|
|
212
|
+
if (!factoryConfig.create) factoryConfig.create = { post: factoryConfig.uri };
|
|
213
|
+
if (!factoryConfig.delete) factoryConfig.delete = { delete: `${factoryConfig.uri}/{id}` };
|
|
215
214
|
|
|
216
|
-
this.factories[factory] = factoryConfig
|
|
215
|
+
this.factories[factory] = factoryConfig;
|
|
217
216
|
}
|
|
218
217
|
|
|
219
|
-
this.created = {}
|
|
220
|
-
Object.keys(this.factories).forEach(
|
|
218
|
+
this.created = {};
|
|
219
|
+
Object.keys(this.factories).forEach(f => this.created[f] = []);
|
|
221
220
|
}
|
|
222
221
|
|
|
223
222
|
static _checkRequirements() {
|
|
224
223
|
try {
|
|
225
|
-
require('axios')
|
|
226
|
-
require('rosie')
|
|
224
|
+
require('axios');
|
|
225
|
+
require('rosie');
|
|
227
226
|
} catch (e) {
|
|
228
|
-
return ['axios', 'rosie']
|
|
227
|
+
return ['axios', 'rosie'];
|
|
229
228
|
}
|
|
230
229
|
}
|
|
231
230
|
|
|
232
231
|
_after() {
|
|
233
232
|
if (!this.config.cleanup || this.config.cleanup === false) {
|
|
234
|
-
return Promise.resolve()
|
|
233
|
+
return Promise.resolve();
|
|
235
234
|
}
|
|
236
|
-
const promises = []
|
|
235
|
+
const promises = [];
|
|
237
236
|
|
|
238
237
|
// clean up all created items
|
|
239
238
|
for (const factoryName in this.created) {
|
|
240
|
-
const createdItems = this.created[factoryName]
|
|
241
|
-
if (!createdItems.length) continue
|
|
242
|
-
this.debug(`Deleting ${createdItems.length} ${factoryName}(s)`)
|
|
239
|
+
const createdItems = this.created[factoryName];
|
|
240
|
+
if (!createdItems.length) continue;
|
|
241
|
+
this.debug(`Deleting ${createdItems.length} ${factoryName}(s)`);
|
|
243
242
|
for (const id in createdItems) {
|
|
244
|
-
promises.push(this._requestDelete(factoryName, createdItems[id]))
|
|
243
|
+
promises.push(this._requestDelete(factoryName, createdItems[id]));
|
|
245
244
|
}
|
|
246
245
|
}
|
|
247
|
-
return Promise.all(promises)
|
|
246
|
+
return Promise.all(promises);
|
|
248
247
|
}
|
|
249
248
|
|
|
250
249
|
/**
|
|
@@ -266,9 +265,9 @@ class ApiDataFactory extends Helper {
|
|
|
266
265
|
* @returns {Promise<*>}
|
|
267
266
|
*/
|
|
268
267
|
have(factory, params, options) {
|
|
269
|
-
const item = this._createItem(factory, params, options)
|
|
270
|
-
this.debug(`Creating ${factory} ${JSON.stringify(item)}`)
|
|
271
|
-
return this._requestCreate(factory, item)
|
|
268
|
+
const item = this._createItem(factory, params, options);
|
|
269
|
+
this.debug(`Creating ${factory} ${JSON.stringify(item)}`);
|
|
270
|
+
return this._requestCreate(factory, item);
|
|
272
271
|
}
|
|
273
272
|
|
|
274
273
|
/**
|
|
@@ -291,27 +290,27 @@ class ApiDataFactory extends Helper {
|
|
|
291
290
|
* @param {*} [options]
|
|
292
291
|
*/
|
|
293
292
|
haveMultiple(factory, times, params, options) {
|
|
294
|
-
const promises = []
|
|
293
|
+
const promises = [];
|
|
295
294
|
for (let i = 0; i < times; i++) {
|
|
296
|
-
promises.push(this.have(factory, params, options))
|
|
295
|
+
promises.push(this.have(factory, params, options));
|
|
297
296
|
}
|
|
298
|
-
return Promise.all(promises)
|
|
297
|
+
return Promise.all(promises);
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
_createItem(model, data, options) {
|
|
302
301
|
if (!this.factories[model]) {
|
|
303
|
-
throw new Error(`Factory ${model} is not defined in config`)
|
|
302
|
+
throw new Error(`Factory ${model} is not defined in config`);
|
|
304
303
|
}
|
|
305
|
-
let modulePath = this.factories[model].factory
|
|
304
|
+
let modulePath = this.factories[model].factory;
|
|
306
305
|
try {
|
|
307
306
|
try {
|
|
308
|
-
require.resolve(modulePath)
|
|
307
|
+
require.resolve(modulePath);
|
|
309
308
|
} catch (e) {
|
|
310
|
-
modulePath = path.join(global.codecept_dir, modulePath)
|
|
309
|
+
modulePath = path.join(global.codecept_dir, modulePath);
|
|
311
310
|
}
|
|
312
311
|
// 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()`.
|
|
313
|
-
const builder = require(modulePath).default || require(modulePath)
|
|
314
|
-
return builder.build(data, options)
|
|
312
|
+
const builder = require(modulePath).default || require(modulePath);
|
|
313
|
+
return builder.build(data, options);
|
|
315
314
|
} catch (err) {
|
|
316
315
|
throw new Error(`Couldn't load factory file from ${modulePath}, check that
|
|
317
316
|
|
|
@@ -322,17 +321,17 @@ class ApiDataFactory extends Helper {
|
|
|
322
321
|
points to valid factory file.
|
|
323
322
|
Factory file should export an object with build method.
|
|
324
323
|
|
|
325
|
-
Current file error: ${err.message}`)
|
|
324
|
+
Current file error: ${err.message}`);
|
|
326
325
|
}
|
|
327
326
|
}
|
|
328
327
|
|
|
329
328
|
_fetchId(body, factory) {
|
|
330
329
|
if (this.config.factories[factory].fetchId) {
|
|
331
|
-
return this.config.factories[factory].fetchId(body)
|
|
330
|
+
return this.config.factories[factory].fetchId(body);
|
|
332
331
|
}
|
|
333
|
-
if (body.id) return body.id
|
|
334
|
-
if (body[factory] && body[factory].id) return body[factory].id
|
|
335
|
-
return null
|
|
332
|
+
if (body.id) return body.id;
|
|
333
|
+
if (body[factory] && body[factory].id) return body[factory].id;
|
|
334
|
+
return null;
|
|
336
335
|
}
|
|
337
336
|
|
|
338
337
|
/**
|
|
@@ -343,27 +342,27 @@ Current file error: ${err.message}`)
|
|
|
343
342
|
* @param {*} data
|
|
344
343
|
*/
|
|
345
344
|
_requestCreate(factory, data) {
|
|
346
|
-
let request = createRequestFromFunction(this.factories[factory].create, data)
|
|
345
|
+
let request = createRequestFromFunction(this.factories[factory].create, data);
|
|
347
346
|
|
|
348
347
|
if (!request) {
|
|
349
|
-
const method = Object.keys(this.factories[factory].create)[0]
|
|
350
|
-
const url = this.factories[factory].create[method]
|
|
348
|
+
const method = Object.keys(this.factories[factory].create)[0];
|
|
349
|
+
const url = this.factories[factory].create[method];
|
|
351
350
|
request = {
|
|
352
351
|
method,
|
|
353
352
|
url,
|
|
354
353
|
data,
|
|
355
|
-
}
|
|
354
|
+
};
|
|
356
355
|
}
|
|
357
356
|
|
|
358
|
-
request.baseURL = this.config.endpoint
|
|
357
|
+
request.baseURL = this.config.endpoint;
|
|
359
358
|
|
|
360
359
|
return this.restHelper._executeRequest(request).then((resp) => {
|
|
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
|
-
})
|
|
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
|
+
});
|
|
367
366
|
}
|
|
368
367
|
|
|
369
368
|
/**
|
|
@@ -374,40 +373,37 @@ Current file error: ${err.message}`)
|
|
|
374
373
|
* @param {*} id
|
|
375
374
|
*/
|
|
376
375
|
_requestDelete(factory, id) {
|
|
377
|
-
if (!this.factories[factory].delete) return
|
|
378
|
-
let request = createRequestFromFunction(this.factories[factory].delete, id)
|
|
376
|
+
if (!this.factories[factory].delete) return;
|
|
377
|
+
let request = createRequestFromFunction(this.factories[factory].delete, id);
|
|
379
378
|
|
|
380
379
|
if (!request) {
|
|
381
|
-
const method = Object.keys(this.factories[factory].delete)[0]
|
|
380
|
+
const method = Object.keys(this.factories[factory].delete)[0];
|
|
382
381
|
|
|
383
|
-
const url = this.factories[factory].delete[method].replace('{id}', id)
|
|
382
|
+
const url = this.factories[factory].delete[method].replace('{id}', id);
|
|
384
383
|
|
|
385
384
|
request = {
|
|
386
385
|
method,
|
|
387
386
|
url,
|
|
388
|
-
}
|
|
387
|
+
};
|
|
389
388
|
}
|
|
390
389
|
|
|
391
|
-
request.baseURL = this.config.endpoint
|
|
390
|
+
request.baseURL = this.config.endpoint;
|
|
392
391
|
|
|
393
392
|
if (request.url.match(/^undefined/)) {
|
|
394
|
-
return this.debugSection(
|
|
395
|
-
'Please configure the delete request in your ApiDataFactory helper',
|
|
396
|
-
"delete: () => ({ method: 'DELETE', url: '/api/users' })",
|
|
397
|
-
)
|
|
393
|
+
return this.debugSection('Please configure the delete request in your ApiDataFactory helper', 'delete: () => ({ method: \'DELETE\', url: \'/api/users\' })');
|
|
398
394
|
}
|
|
399
395
|
|
|
400
396
|
return this.restHelper._executeRequest(request).then(() => {
|
|
401
|
-
const idx = this.created[factory].indexOf(id)
|
|
402
|
-
this.debugSection('Deleted Id', `Id: ${id}`)
|
|
403
|
-
this.created[factory].splice(idx, 1)
|
|
404
|
-
})
|
|
397
|
+
const idx = this.created[factory].indexOf(id);
|
|
398
|
+
this.debugSection('Deleted Id', `Id: ${id}`);
|
|
399
|
+
this.created[factory].splice(idx, 1);
|
|
400
|
+
});
|
|
405
401
|
}
|
|
406
402
|
}
|
|
407
403
|
|
|
408
|
-
|
|
404
|
+
export default ApiDataFactory;
|
|
409
405
|
|
|
410
406
|
function createRequestFromFunction(param, data) {
|
|
411
|
-
if (typeof param !== 'function') return
|
|
412
|
-
return param(data)
|
|
407
|
+
if (typeof param !== 'function') return;
|
|
408
|
+
return param(data);
|
|
413
409
|
}
|