codeceptjs 4.0.0-beta.1 → 4.0.0-beta.10.esm-aria
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 +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +71 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +238 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +300 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +124 -50
- package/lib/container.js +751 -260
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +47 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +115 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -879
- package/typings/types.d.ts +547 -996
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
package/lib/helper/FileSystem.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import assert from 'assert'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import fs from 'fs'
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
|
|
5
|
+
import Helper from '@codeceptjs/helper'
|
|
6
|
+
import { fileExists } from '../utils.js'
|
|
7
|
+
import { fileIncludes } from '../assert/include.js'
|
|
8
|
+
import { fileEquals } from '../assert/equal.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Helper for testing filesystem.
|
|
@@ -30,15 +30,20 @@ import * as output from '../output.js';
|
|
|
30
30
|
*
|
|
31
31
|
* ## Methods
|
|
32
32
|
*/
|
|
33
|
-
|
|
34
|
-
constructor(
|
|
35
|
-
super(
|
|
36
|
-
this.dir = global.codecept_dir
|
|
37
|
-
this.file = ''
|
|
33
|
+
class FileSystem extends Helper {
|
|
34
|
+
constructor() {
|
|
35
|
+
super()
|
|
36
|
+
this.dir = global.codecept_dir
|
|
37
|
+
this.file = ''
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
_before() {
|
|
41
|
-
|
|
41
|
+
try {
|
|
42
|
+
this.debugSection('Dir', this.dir)
|
|
43
|
+
} catch (e) {
|
|
44
|
+
// Fallback debug for ESM transition
|
|
45
|
+
console.log(`[Dir] ${this.dir}`)
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
/**
|
|
@@ -47,8 +52,13 @@ export default class FileSystem extends Helper {
|
|
|
47
52
|
* @param {string} openPath
|
|
48
53
|
*/
|
|
49
54
|
amInPath(openPath) {
|
|
50
|
-
this.dir = path.join(global.codecept_dir, openPath)
|
|
51
|
-
|
|
55
|
+
this.dir = path.join(global.codecept_dir, openPath)
|
|
56
|
+
try {
|
|
57
|
+
this.debugSection('Dir', this.dir)
|
|
58
|
+
} catch (e) {
|
|
59
|
+
// Fallback debug for ESM transition
|
|
60
|
+
console.log(`[Dir] ${this.dir}`)
|
|
61
|
+
}
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
/**
|
|
@@ -57,7 +67,7 @@ export default class FileSystem extends Helper {
|
|
|
57
67
|
* @param {string} text
|
|
58
68
|
*/
|
|
59
69
|
writeToFile(name, text) {
|
|
60
|
-
fs.writeFileSync(path.join(this.dir, name), text)
|
|
70
|
+
fs.writeFileSync(path.join(this.dir, name), text)
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
/**
|
|
@@ -65,9 +75,14 @@ export default class FileSystem extends Helper {
|
|
|
65
75
|
* @param {string} name
|
|
66
76
|
*/
|
|
67
77
|
seeFile(name) {
|
|
68
|
-
this.file = path.join(this.dir, name)
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
this.file = path.join(this.dir, name)
|
|
79
|
+
try {
|
|
80
|
+
this.debugSection('File', this.file)
|
|
81
|
+
} catch (e) {
|
|
82
|
+
// Fallback debug for ESM transition
|
|
83
|
+
console.log(`[File] ${this.file}`)
|
|
84
|
+
}
|
|
85
|
+
assert.ok(fileExists(this.file), `File ${name} not found in ${this.dir}`)
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
/**
|
|
@@ -83,31 +98,36 @@ export default class FileSystem extends Helper {
|
|
|
83
98
|
* @param {number} [sec=1] seconds to wait
|
|
84
99
|
*/
|
|
85
100
|
async waitForFile(name, sec = 1) {
|
|
86
|
-
if (sec === 0) assert.fail('Use `seeFile` instead of waiting 0 seconds!')
|
|
87
|
-
const waitTimeout = sec * 1000
|
|
88
|
-
this.file = path.join(this.dir, name)
|
|
89
|
-
|
|
101
|
+
if (sec === 0) assert.fail('Use `seeFile` instead of waiting 0 seconds!')
|
|
102
|
+
const waitTimeout = sec * 1000
|
|
103
|
+
this.file = path.join(this.dir, name)
|
|
104
|
+
try {
|
|
105
|
+
this.debugSection('File', this.file)
|
|
106
|
+
} catch (e) {
|
|
107
|
+
// Fallback debug for ESM transition
|
|
108
|
+
console.log(`[File] ${this.file}`)
|
|
109
|
+
}
|
|
90
110
|
return isFileExists(this.file, waitTimeout).catch(() => {
|
|
91
|
-
throw new Error(`file (${name}) still not present in directory ${this.dir} after ${waitTimeout / 1000} sec`)
|
|
92
|
-
})
|
|
111
|
+
throw new Error(`file (${name}) still not present in directory ${this.dir} after ${waitTimeout / 1000} sec`)
|
|
112
|
+
})
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
/**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
* Checks that file with a name including given text exists in the current directory.
|
|
117
|
+
*
|
|
118
|
+
*```js
|
|
119
|
+
* I.handleDownloads();
|
|
120
|
+
* I.click('Download as PDF');
|
|
121
|
+
* I.amInPath('output/downloads');
|
|
122
|
+
* I.seeFileNameMatching('.pdf');
|
|
123
|
+
* ```
|
|
124
|
+
* @param {string} text
|
|
125
|
+
*/
|
|
106
126
|
seeFileNameMatching(text) {
|
|
107
127
|
assert.ok(
|
|
108
128
|
this.grabFileNames().some(file => file.includes(text)),
|
|
109
129
|
`File name which contains ${text} not found in ${this.dir}`,
|
|
110
|
-
)
|
|
130
|
+
)
|
|
111
131
|
}
|
|
112
132
|
|
|
113
133
|
/**
|
|
@@ -116,8 +136,8 @@ export default class FileSystem extends Helper {
|
|
|
116
136
|
* @param {string} [encoding='utf8']
|
|
117
137
|
*/
|
|
118
138
|
seeInThisFile(text, encoding = 'utf8') {
|
|
119
|
-
const content = getFileContents(this.file, encoding)
|
|
120
|
-
fileIncludes(this.file).assert(text, content)
|
|
139
|
+
const content = getFileContents(this.file, encoding)
|
|
140
|
+
fileIncludes(this.file).assert(text, content)
|
|
121
141
|
}
|
|
122
142
|
|
|
123
143
|
/**
|
|
@@ -126,8 +146,8 @@ export default class FileSystem extends Helper {
|
|
|
126
146
|
* @param {string} [encoding='utf8']
|
|
127
147
|
*/
|
|
128
148
|
dontSeeInThisFile(text, encoding = 'utf8') {
|
|
129
|
-
const content = getFileContents(this.file, encoding)
|
|
130
|
-
fileIncludes(this.file).negate(text, content)
|
|
149
|
+
const content = getFileContents(this.file, encoding)
|
|
150
|
+
fileIncludes(this.file).negate(text, content)
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
/**
|
|
@@ -136,8 +156,8 @@ export default class FileSystem extends Helper {
|
|
|
136
156
|
* @param {string} [encoding='utf8']
|
|
137
157
|
*/
|
|
138
158
|
seeFileContentsEqual(text, encoding = 'utf8') {
|
|
139
|
-
const content = getFileContents(this.file, encoding)
|
|
140
|
-
fileEquals(this.file).assert(text, content)
|
|
159
|
+
const content = getFileContents(this.file, encoding)
|
|
160
|
+
fileEquals(this.file).assert(text, content)
|
|
141
161
|
}
|
|
142
162
|
|
|
143
163
|
/**
|
|
@@ -147,11 +167,11 @@ export default class FileSystem extends Helper {
|
|
|
147
167
|
* @param {string} [encodingReference='utf8']
|
|
148
168
|
*/
|
|
149
169
|
seeFileContentsEqualReferenceFile(pathToReferenceFile, encoding = 'utf8', encodingReference = '') {
|
|
150
|
-
const content = getFileContents(this.file, encoding)
|
|
151
|
-
assert.ok(fileExists(pathToReferenceFile), `Reference file ${pathToReferenceFile} not found.`)
|
|
152
|
-
encodingReference = encodingReference || encoding
|
|
153
|
-
const expectedContent = getFileContents(pathToReferenceFile, encodingReference)
|
|
154
|
-
fileEquals(this.file).assert(expectedContent, content)
|
|
170
|
+
const content = getFileContents(this.file, encoding)
|
|
171
|
+
assert.ok(fileExists(pathToReferenceFile), `Reference file ${pathToReferenceFile} not found.`)
|
|
172
|
+
encodingReference = encodingReference || encoding
|
|
173
|
+
const expectedContent = getFileContents(pathToReferenceFile, encodingReference)
|
|
174
|
+
fileEquals(this.file).assert(expectedContent, content)
|
|
155
175
|
}
|
|
156
176
|
|
|
157
177
|
/**
|
|
@@ -160,26 +180,27 @@ export default class FileSystem extends Helper {
|
|
|
160
180
|
* @param {string} [encoding='utf8']
|
|
161
181
|
*/
|
|
162
182
|
dontSeeFileContentsEqual(text, encoding = 'utf8') {
|
|
163
|
-
const content = getFileContents(this.file, encoding)
|
|
164
|
-
fileEquals(this.file).negate(text, content)
|
|
183
|
+
const content = getFileContents(this.file, encoding)
|
|
184
|
+
fileEquals(this.file).negate(text, content)
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
/**
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
188
|
+
* Returns file names in current directory.
|
|
189
|
+
*
|
|
190
|
+
* ```js
|
|
191
|
+
* I.handleDownloads();
|
|
192
|
+
* I.click('Download Files');
|
|
193
|
+
* I.amInPath('output/downloads');
|
|
194
|
+
* const downloadedFileNames = I.grabFileNames();
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
177
197
|
grabFileNames() {
|
|
178
|
-
return fs.readdirSync(this.dir)
|
|
179
|
-
.filter(item => !fs.lstatSync(path.join(this.dir, item)).isDirectory());
|
|
198
|
+
return fs.readdirSync(this.dir).filter(item => !fs.lstatSync(path.join(this.dir, item)).isDirectory())
|
|
180
199
|
}
|
|
181
200
|
}
|
|
182
201
|
|
|
202
|
+
export { FileSystem as default }
|
|
203
|
+
|
|
183
204
|
/**
|
|
184
205
|
* @param {string} file
|
|
185
206
|
* @param {string} [encoding='utf8']
|
|
@@ -187,9 +208,9 @@ export default class FileSystem extends Helper {
|
|
|
187
208
|
* @returns {string}
|
|
188
209
|
*/
|
|
189
210
|
function getFileContents(file, encoding = 'utf8') {
|
|
190
|
-
if (!file) assert.fail('No files were opened, please use seeFile action')
|
|
191
|
-
if (encoding === '') assert.fail('Encoding is an empty string, please set a valid encoding')
|
|
192
|
-
return fs.readFileSync(file, encoding)
|
|
211
|
+
if (!file) assert.fail('No files were opened, please use seeFile action')
|
|
212
|
+
if (encoding === '') assert.fail('Encoding is an empty string, please set a valid encoding')
|
|
213
|
+
return fs.readFileSync(file, encoding)
|
|
193
214
|
}
|
|
194
215
|
|
|
195
216
|
/**
|
|
@@ -201,26 +222,26 @@ function getFileContents(file, encoding = 'utf8') {
|
|
|
201
222
|
function isFileExists(file, timeout) {
|
|
202
223
|
return new Promise((resolve, reject) => {
|
|
203
224
|
const timer = setTimeout(() => {
|
|
204
|
-
watcher.close()
|
|
205
|
-
reject(new Error('File did not exists and was not created during the timeout.'))
|
|
206
|
-
}, timeout)
|
|
225
|
+
watcher.close()
|
|
226
|
+
reject(new Error('File did not exists and was not created during the timeout.'))
|
|
227
|
+
}, timeout)
|
|
207
228
|
|
|
208
|
-
const dir = path.dirname(file)
|
|
209
|
-
const basename = path.basename(file)
|
|
229
|
+
const dir = path.dirname(file)
|
|
230
|
+
const basename = path.basename(file)
|
|
210
231
|
const watcher = fs.watch(dir, (eventType, filename) => {
|
|
211
232
|
if (eventType === 'rename' && filename === basename) {
|
|
212
|
-
clearTimeout(timer)
|
|
213
|
-
watcher.close()
|
|
214
|
-
resolve()
|
|
233
|
+
clearTimeout(timer)
|
|
234
|
+
watcher.close()
|
|
235
|
+
resolve()
|
|
215
236
|
}
|
|
216
|
-
})
|
|
237
|
+
})
|
|
217
238
|
|
|
218
|
-
fs.access(file, fs.constants.R_OK,
|
|
239
|
+
fs.access(file, fs.constants.R_OK, err => {
|
|
219
240
|
if (!err) {
|
|
220
|
-
clearTimeout(timer)
|
|
221
|
-
watcher.close()
|
|
222
|
-
resolve()
|
|
241
|
+
clearTimeout(timer)
|
|
242
|
+
watcher.close()
|
|
243
|
+
resolve()
|
|
223
244
|
}
|
|
224
|
-
})
|
|
225
|
-
})
|
|
245
|
+
})
|
|
246
|
+
})
|
|
226
247
|
}
|
package/lib/helper/GraphQL.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import HelperModule from '@codeceptjs/helper'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests.
|
|
@@ -38,31 +38,35 @@ import Helper from '@codeceptjs/helper';
|
|
|
38
38
|
*/
|
|
39
39
|
class GraphQL extends Helper {
|
|
40
40
|
constructor(config) {
|
|
41
|
-
super(config)
|
|
42
|
-
this.axios = axios.create()
|
|
43
|
-
this.headers = {}
|
|
41
|
+
super(config)
|
|
42
|
+
this.axios = axios.create()
|
|
43
|
+
this.headers = {}
|
|
44
44
|
this.options = {
|
|
45
45
|
timeout: 10000,
|
|
46
46
|
defaultHeaders: {},
|
|
47
47
|
endpoint: '',
|
|
48
|
-
}
|
|
49
|
-
this.options = Object.assign(this.options, config)
|
|
50
|
-
this.headers = { ...this.options.defaultHeaders }
|
|
51
|
-
this.axios.defaults.headers = this.options.defaultHeaders
|
|
48
|
+
}
|
|
49
|
+
this.options = Object.assign(this.options, config)
|
|
50
|
+
this.headers = { ...this.options.defaultHeaders }
|
|
51
|
+
this.axios.defaults.headers = this.options.defaultHeaders
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
static _checkRequirements() {
|
|
55
55
|
try {
|
|
56
|
-
require('axios')
|
|
56
|
+
require('axios')
|
|
57
57
|
} catch (e) {
|
|
58
|
-
return ['axios']
|
|
58
|
+
return ['axios']
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
static _config() {
|
|
63
63
|
return [
|
|
64
|
-
{
|
|
65
|
-
|
|
64
|
+
{
|
|
65
|
+
name: 'endpoint',
|
|
66
|
+
message: 'Endpoint of API you are going to test',
|
|
67
|
+
default: 'http://localhost:3000/graphql',
|
|
68
|
+
},
|
|
69
|
+
]
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
/**
|
|
@@ -71,42 +75,39 @@ class GraphQL extends Helper {
|
|
|
71
75
|
* @param {object} request
|
|
72
76
|
*/
|
|
73
77
|
async _executeQuery(request) {
|
|
74
|
-
this.axios.defaults.timeout = request.timeout || this.options.timeout
|
|
78
|
+
this.axios.defaults.timeout = request.timeout || this.options.timeout
|
|
75
79
|
|
|
76
80
|
if (this.headers && this.headers.auth) {
|
|
77
|
-
request.auth = this.headers.auth
|
|
81
|
+
request.auth = this.headers.auth
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
request.headers = Object.assign(request.headers, {
|
|
81
85
|
'Content-Type': 'application/json',
|
|
82
|
-
})
|
|
86
|
+
})
|
|
83
87
|
|
|
84
|
-
request.headers = { ...this.headers, ...request.headers }
|
|
88
|
+
request.headers = { ...this.headers, ...request.headers }
|
|
85
89
|
|
|
86
90
|
if (this.config.onRequest) {
|
|
87
|
-
await this.config.onRequest(request)
|
|
91
|
+
await this.config.onRequest(request)
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
this.debugSection('Request', JSON.stringify(request))
|
|
94
|
+
this.debugSection('Request', JSON.stringify(request))
|
|
91
95
|
|
|
92
|
-
let response
|
|
96
|
+
let response
|
|
93
97
|
try {
|
|
94
|
-
response = await this.axios(request)
|
|
98
|
+
response = await this.axios(request)
|
|
95
99
|
} catch (err) {
|
|
96
|
-
if (!err.response) throw err
|
|
97
|
-
this.debugSection(
|
|
98
|
-
|
|
99
|
-
`Response error. Status code: ${err.response.status}`,
|
|
100
|
-
);
|
|
101
|
-
response = err.response;
|
|
100
|
+
if (!err.response) throw err
|
|
101
|
+
this.debugSection('Response', `Response error. Status code: ${err.response.status}`)
|
|
102
|
+
response = err.response
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
if (this.config.onResponse) {
|
|
105
|
-
await this.config.onResponse(response)
|
|
106
|
+
await this.config.onResponse(response)
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
this.debugSection('Response', JSON.stringify(response.data))
|
|
109
|
-
return response
|
|
109
|
+
this.debugSection('Response', JSON.stringify(response.data))
|
|
110
|
+
return response
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
/**
|
|
@@ -122,7 +123,7 @@ class GraphQL extends Helper {
|
|
|
122
123
|
method: 'POST',
|
|
123
124
|
data: operation,
|
|
124
125
|
headers,
|
|
125
|
-
}
|
|
126
|
+
}
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
@@ -148,15 +149,15 @@ class GraphQL extends Helper {
|
|
|
148
149
|
*/
|
|
149
150
|
async sendQuery(query, variables, options = {}, headers = {}) {
|
|
150
151
|
if (typeof query !== 'string') {
|
|
151
|
-
throw new Error(`query expected to be a String, instead received ${typeof query}`)
|
|
152
|
+
throw new Error(`query expected to be a String, instead received ${typeof query}`)
|
|
152
153
|
}
|
|
153
154
|
const operation = {
|
|
154
155
|
query,
|
|
155
156
|
variables,
|
|
156
157
|
...options,
|
|
157
|
-
}
|
|
158
|
-
const request = this._prepareGraphQLRequest(operation, headers)
|
|
159
|
-
return this._executeQuery(request)
|
|
158
|
+
}
|
|
159
|
+
const request = this._prepareGraphQLRequest(operation, headers)
|
|
160
|
+
return this._executeQuery(request)
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
/**
|
|
@@ -188,19 +189,19 @@ class GraphQL extends Helper {
|
|
|
188
189
|
*/
|
|
189
190
|
async sendMutation(mutation, variables, options = {}, headers = {}) {
|
|
190
191
|
if (typeof mutation !== 'string') {
|
|
191
|
-
throw new Error(`mutation expected to be a String, instead received ${typeof mutation}`)
|
|
192
|
+
throw new Error(`mutation expected to be a String, instead received ${typeof mutation}`)
|
|
192
193
|
}
|
|
193
194
|
const operation = {
|
|
194
195
|
query: mutation,
|
|
195
196
|
variables,
|
|
196
197
|
...options,
|
|
197
|
-
}
|
|
198
|
-
const request = this._prepareGraphQLRequest(operation, headers)
|
|
199
|
-
return this._executeQuery(request)
|
|
198
|
+
}
|
|
199
|
+
const request = this._prepareGraphQLRequest(operation, headers)
|
|
200
|
+
return this._executeQuery(request)
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
_setRequestTimeout(newTimeout) {
|
|
203
|
-
this.options.timeout = newTimeout
|
|
204
|
+
this.options.timeout = newTimeout
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
/**
|
|
@@ -209,7 +210,7 @@ class GraphQL extends Helper {
|
|
|
209
210
|
* @param {object} headers headers list
|
|
210
211
|
*/
|
|
211
212
|
haveRequestHeaders(headers) {
|
|
212
|
-
this.headers = { ...this.headers, ...headers }
|
|
213
|
+
this.headers = { ...this.headers, ...headers }
|
|
213
214
|
}
|
|
214
215
|
|
|
215
216
|
/**
|
|
@@ -223,7 +224,7 @@ class GraphQL extends Helper {
|
|
|
223
224
|
* @param {string | CodeceptJS.Secret} accessToken Bearer access token
|
|
224
225
|
*/
|
|
225
226
|
amBearerAuthenticated(accessToken) {
|
|
226
|
-
this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` })
|
|
227
|
+
this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` })
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
|
-
export default GraphQL
|
|
230
|
+
export default GraphQL
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
|
|
3
|
-
import
|
|
1
|
+
import path from 'path'
|
|
2
|
+
|
|
3
|
+
import HelperModule from '@codeceptjs/helper'
|
|
4
|
+
import GraphQL from './GraphQL.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Helper for managing remote data using GraphQL queries.
|
|
@@ -54,7 +55,7 @@ import GraphQL from './GraphQL';
|
|
|
54
55
|
* input: { ...buildObj },
|
|
55
56
|
* }))
|
|
56
57
|
* // 'attr'-id can be left out depending on the GraphQl resolvers
|
|
57
|
-
* .attr('name', () => faker.
|
|
58
|
+
* .attr('name', () => faker.person.findName())
|
|
58
59
|
* .attr('email', () => faker.interact.email())
|
|
59
60
|
* ```
|
|
60
61
|
* For more options see [rosie documentation](https://github.com/rosiejs/rosie).
|
|
@@ -150,52 +151,52 @@ import GraphQL from './GraphQL';
|
|
|
150
151
|
*/
|
|
151
152
|
class GraphQLDataFactory extends Helper {
|
|
152
153
|
constructor(config) {
|
|
153
|
-
super(config)
|
|
154
|
+
super(config)
|
|
154
155
|
|
|
155
156
|
const defaultConfig = {
|
|
156
157
|
cleanup: true,
|
|
157
158
|
GraphQL: {},
|
|
158
159
|
factories: {},
|
|
159
|
-
}
|
|
160
|
-
this.config = Object.assign(defaultConfig, this.config)
|
|
160
|
+
}
|
|
161
|
+
this.config = Object.assign(defaultConfig, this.config)
|
|
161
162
|
|
|
162
163
|
if (this.config.headers) {
|
|
163
|
-
this.config.GraphQL.defaultHeaders = this.config.headers
|
|
164
|
+
this.config.GraphQL.defaultHeaders = this.config.headers
|
|
164
165
|
}
|
|
165
166
|
if (this.config.onRequest) {
|
|
166
|
-
this.config.GraphQL.onRequest = this.config.onRequest
|
|
167
|
+
this.config.GraphQL.onRequest = this.config.onRequest
|
|
167
168
|
}
|
|
168
|
-
this.graphqlHelper = new GraphQL(Object.assign(this.config.GraphQL, { endpoint: this.config.endpoint }))
|
|
169
|
-
this.factories = this.config.factories
|
|
169
|
+
this.graphqlHelper = new GraphQL(Object.assign(this.config.GraphQL, { endpoint: this.config.endpoint }))
|
|
170
|
+
this.factories = this.config.factories
|
|
170
171
|
|
|
171
|
-
this.created = {}
|
|
172
|
-
Object.keys(this.factories).forEach(f => (this.created[f] = []))
|
|
172
|
+
this.created = {}
|
|
173
|
+
Object.keys(this.factories).forEach(f => (this.created[f] = []))
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
static _checkRequirements() {
|
|
176
177
|
try {
|
|
177
|
-
require('axios')
|
|
178
|
-
require('rosie')
|
|
178
|
+
require('axios')
|
|
179
|
+
require('rosie')
|
|
179
180
|
} catch (e) {
|
|
180
|
-
return ['axios', 'rosie']
|
|
181
|
+
return ['axios', 'rosie']
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
_after() {
|
|
185
186
|
if (!this.config.cleanup) {
|
|
186
|
-
return Promise.resolve()
|
|
187
|
+
return Promise.resolve()
|
|
187
188
|
}
|
|
188
|
-
const promises = []
|
|
189
|
+
const promises = []
|
|
189
190
|
// clean up all created items
|
|
190
191
|
for (const mutationName in this.created) {
|
|
191
|
-
const createdItems = this.created[mutationName]
|
|
192
|
-
if (!createdItems.length) continue
|
|
193
|
-
this.debug(`Deleting ${createdItems.length} ${mutationName}(s)`)
|
|
192
|
+
const createdItems = this.created[mutationName]
|
|
193
|
+
if (!createdItems.length) continue
|
|
194
|
+
this.debug(`Deleting ${createdItems.length} ${mutationName}(s)`)
|
|
194
195
|
for (const itemData of createdItems) {
|
|
195
|
-
promises.push(this._requestDelete(mutationName, itemData))
|
|
196
|
+
promises.push(this._requestDelete(mutationName, itemData))
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
|
-
return Promise.all(promises)
|
|
199
|
+
return Promise.all(promises)
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
/**
|
|
@@ -213,9 +214,9 @@ class GraphQLDataFactory extends Helper {
|
|
|
213
214
|
* @param {*} params predefined parameters
|
|
214
215
|
*/
|
|
215
216
|
mutateData(operation, params) {
|
|
216
|
-
const variables = this._createItem(operation, params)
|
|
217
|
-
this.debug(`Creating ${operation} ${JSON.stringify(variables)}`)
|
|
218
|
-
return this._requestCreate(operation, variables)
|
|
217
|
+
const variables = this._createItem(operation, params)
|
|
218
|
+
this.debug(`Creating ${operation} ${JSON.stringify(variables)}`)
|
|
219
|
+
return this._requestCreate(operation, variables)
|
|
219
220
|
}
|
|
220
221
|
|
|
221
222
|
/**
|
|
@@ -234,26 +235,26 @@ class GraphQLDataFactory extends Helper {
|
|
|
234
235
|
* @param {*} params
|
|
235
236
|
*/
|
|
236
237
|
mutateMultiple(operation, times, params) {
|
|
237
|
-
const promises = []
|
|
238
|
+
const promises = []
|
|
238
239
|
for (let i = 0; i < times; i++) {
|
|
239
|
-
promises.push(this.mutateData(operation, params))
|
|
240
|
+
promises.push(this.mutateData(operation, params))
|
|
240
241
|
}
|
|
241
|
-
return Promise.all(promises)
|
|
242
|
+
return Promise.all(promises)
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
_createItem(operation, data) {
|
|
245
246
|
if (!this.factories[operation]) {
|
|
246
|
-
throw new Error(`Mutation ${operation} is not defined in config.factories`)
|
|
247
|
+
throw new Error(`Mutation ${operation} is not defined in config.factories`)
|
|
247
248
|
}
|
|
248
|
-
let modulePath = this.factories[operation].factory
|
|
249
|
+
let modulePath = this.factories[operation].factory
|
|
249
250
|
try {
|
|
250
251
|
try {
|
|
251
|
-
require.resolve(modulePath)
|
|
252
|
+
require.resolve(modulePath)
|
|
252
253
|
} catch (e) {
|
|
253
|
-
modulePath = path.join(global.codecept_dir, modulePath)
|
|
254
|
+
modulePath = path.join(global.codecept_dir, modulePath)
|
|
254
255
|
}
|
|
255
|
-
const builder = require(modulePath)
|
|
256
|
-
return builder.build(data)
|
|
256
|
+
const builder = require(modulePath)
|
|
257
|
+
return builder.build(data)
|
|
257
258
|
} catch (err) {
|
|
258
259
|
throw new Error(`Couldn't load factory file from ${modulePath}, check that
|
|
259
260
|
|
|
@@ -264,7 +265,7 @@ class GraphQLDataFactory extends Helper {
|
|
|
264
265
|
points to valid factory file.
|
|
265
266
|
Factory file should export an object with build method.
|
|
266
267
|
|
|
267
|
-
Current file error: ${err.message}`)
|
|
268
|
+
Current file error: ${err.message}`)
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
271
|
|
|
@@ -276,13 +277,13 @@ class GraphQLDataFactory extends Helper {
|
|
|
276
277
|
* @param {*} variables to be sent along with the query
|
|
277
278
|
*/
|
|
278
279
|
_requestCreate(operation, variables) {
|
|
279
|
-
const { query } = this.factories[operation]
|
|
280
|
-
return this.graphqlHelper.sendMutation(query, variables).then(
|
|
281
|
-
const data = response.data.data[operation]
|
|
282
|
-
this.created[operation].push(data)
|
|
283
|
-
this.debugSection('Created', `record: ${data}`)
|
|
284
|
-
return data
|
|
285
|
-
})
|
|
280
|
+
const { query } = this.factories[operation]
|
|
281
|
+
return this.graphqlHelper.sendMutation(query, variables).then(response => {
|
|
282
|
+
const data = response.data.data[operation]
|
|
283
|
+
this.created[operation].push(data)
|
|
284
|
+
this.debugSection('Created', `record: ${data}`)
|
|
285
|
+
return data
|
|
286
|
+
})
|
|
286
287
|
}
|
|
287
288
|
|
|
288
289
|
/**
|
|
@@ -293,16 +294,15 @@ class GraphQLDataFactory extends Helper {
|
|
|
293
294
|
* @param {*} data of the record to be deleted.
|
|
294
295
|
*/
|
|
295
296
|
_requestDelete(operation, data) {
|
|
296
|
-
const deleteOperation = this.factories[operation].revert(data)
|
|
297
|
-
const { query, variables } = deleteOperation
|
|
297
|
+
const deleteOperation = this.factories[operation].revert(data)
|
|
298
|
+
const { query, variables } = deleteOperation
|
|
298
299
|
|
|
299
|
-
return this.graphqlHelper.sendMutation(query, variables)
|
|
300
|
-
.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
});
|
|
300
|
+
return this.graphqlHelper.sendMutation(query, variables).then(response => {
|
|
301
|
+
const idx = this.created[operation].indexOf(data)
|
|
302
|
+
this.debugSection('Deleted', `record: ${response.data.data}`)
|
|
303
|
+
this.created[operation].splice(idx, 1)
|
|
304
|
+
})
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
export default GraphQLDataFactory
|
|
308
|
+
export default GraphQLDataFactory
|