codeceptjs 3.6.4 → 3.6.5-beta.1
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 -63
- package/lib/assert/empty.js +19 -19
- package/lib/assert/equal.js +32 -30
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +42 -42
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +17 -18
- package/lib/command/configMigrate.js +57 -52
- package/lib/command/definitions.js +88 -88
- package/lib/command/dryRun.js +65 -63
- package/lib/command/generate.js +191 -181
- package/lib/command/info.js +39 -37
- package/lib/command/init.js +289 -286
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +22 -22
- package/lib/command/run-workers.js +63 -63
- package/lib/command/run.js +24 -26
- package/lib/command/utils.js +64 -63
- package/lib/data/context.js +60 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/helper/AI.js +67 -65
- package/lib/helper/ApiDataFactory.js +72 -69
- package/lib/helper/Appium.js +409 -379
- package/lib/helper/ExpectHelper.js +214 -248
- package/lib/helper/FileSystem.js +77 -78
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +49 -50
- package/lib/helper/JSONResponse.js +64 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -12
- package/lib/helper/Nightmare.js +664 -572
- package/lib/helper/Playwright.js +1320 -1211
- package/lib/helper/Protractor.js +663 -629
- package/lib/helper/Puppeteer.js +1232 -1124
- package/lib/helper/REST.js +87 -72
- package/lib/helper/TestCafe.js +490 -491
- package/lib/helper/WebDriver.js +1294 -1156
- package/lib/interfaces/bdd.js +38 -51
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +122 -111
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -23
- 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 -51
- package/lib/listener/timeout.js +53 -53
- package/lib/plugin/allure.js +14 -14
- package/lib/plugin/autoDelay.js +29 -36
- package/lib/plugin/autoLogin.js +70 -66
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +92 -77
- package/lib/plugin/customLocator.js +20 -19
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +37 -37
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +66 -63
- package/lib/plugin/pauseOnFail.js +10 -10
- package/lib/plugin/retryFailedStep.js +31 -38
- package/lib/plugin/retryTo.js +28 -28
- package/lib/plugin/screenshotOnFail.js +107 -86
- package/lib/plugin/selenoid.js +131 -117
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +102 -92
- package/lib/plugin/stepTimeout.js +23 -22
- package/lib/plugin/subtitles.js +34 -34
- package/lib/plugin/tryTo.js +39 -29
- package/lib/plugin/wdio.js +77 -72
- package/lib/template/heal.js +11 -14
- package/package.json +4 -2
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -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/promiseBasedTypes.d.ts +238 -0
- package/typings/types.d.ts +32 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
3
|
|
|
4
|
-
const Container = require('../container')
|
|
5
|
-
const recorder = require('../recorder')
|
|
6
|
-
const event = require('../event')
|
|
7
|
-
const output = require('../output')
|
|
8
|
-
const { fileExists, clearString } = require('../utils')
|
|
9
|
-
const Codeceptjs = require('../index')
|
|
4
|
+
const Container = require('../container')
|
|
5
|
+
const recorder = require('../recorder')
|
|
6
|
+
const event = require('../event')
|
|
7
|
+
const output = require('../output')
|
|
8
|
+
const { fileExists, clearString } = require('../utils')
|
|
9
|
+
const Codeceptjs = require('../index')
|
|
10
10
|
|
|
11
11
|
const defaultConfig = {
|
|
12
12
|
uniqueScreenshotNames: false,
|
|
13
13
|
disableScreenshots: false,
|
|
14
14
|
fullPageScreenshots: false,
|
|
15
|
-
}
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
const supportedHelpers = require('./standardActingHelpers')
|
|
17
|
+
const supportedHelpers = require('./standardActingHelpers')
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Creates screenshot on failure. Screenshot is saved into `output` directory.
|
|
@@ -43,118 +43,139 @@ const supportedHelpers = require('./standardActingHelpers');
|
|
|
43
43
|
*
|
|
44
44
|
*/
|
|
45
45
|
module.exports = function (config) {
|
|
46
|
-
const helpers = Container.helpers()
|
|
47
|
-
let helper
|
|
46
|
+
const helpers = Container.helpers()
|
|
47
|
+
let helper
|
|
48
48
|
|
|
49
49
|
for (const helperName of supportedHelpers) {
|
|
50
50
|
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
51
|
-
helper = helpers[helperName]
|
|
51
|
+
helper = helpers[helperName]
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
if (!helper) return
|
|
55
|
+
if (!helper) return // no helpers for screenshot
|
|
56
56
|
|
|
57
|
-
const options = Object.assign(defaultConfig, helper.options, config)
|
|
57
|
+
const options = Object.assign(defaultConfig, helper.options, config)
|
|
58
58
|
|
|
59
59
|
if (helpers.Mochawesome) {
|
|
60
60
|
if (helpers.Mochawesome.config) {
|
|
61
|
-
options.uniqueScreenshotNames = helpers.Mochawesome.config.uniqueScreenshotNames
|
|
61
|
+
options.uniqueScreenshotNames = helpers.Mochawesome.config.uniqueScreenshotNames
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
if (Codeceptjs.container.mocha()) {
|
|
66
|
-
options.reportDir =
|
|
67
|
-
|
|
66
|
+
options.reportDir =
|
|
67
|
+
Codeceptjs.container.mocha().options.reporterOptions &&
|
|
68
|
+
Codeceptjs.container.mocha().options.reporterOptions.reportDir
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
if (options.disableScreenshots) {
|
|
71
72
|
// old version of disabling screenshots
|
|
72
|
-
return
|
|
73
|
+
return
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
event.dispatcher.on(event.test.failed, (test) => {
|
|
76
77
|
if (test.ctx?._runnable.title.includes('hook: ')) {
|
|
77
|
-
output.plugin(
|
|
78
|
-
|
|
78
|
+
output.plugin(
|
|
79
|
+
'screenshotOnFail',
|
|
80
|
+
'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.',
|
|
81
|
+
)
|
|
82
|
+
return
|
|
79
83
|
}
|
|
80
|
-
recorder.add(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (options.uniqueScreenshotNames && test) {
|
|
89
|
-
const uuid = _getUUID(test);
|
|
90
|
-
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
|
|
91
|
-
} else {
|
|
92
|
-
fileName += '.failed.png';
|
|
93
|
-
}
|
|
94
|
-
output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot');
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
if (options.reportDir) {
|
|
98
|
-
fileName = path.join(options.reportDir, fileName);
|
|
99
|
-
const mochaReportDir = path.resolve(process.cwd(), options.reportDir);
|
|
100
|
-
if (!fileExists(mochaReportDir)) {
|
|
101
|
-
fs.mkdirSync(mochaReportDir);
|
|
102
|
-
}
|
|
84
|
+
recorder.add(
|
|
85
|
+
'screenshot of failed test',
|
|
86
|
+
async () => {
|
|
87
|
+
let fileName = clearString(test.title)
|
|
88
|
+
const dataType = 'image/png'
|
|
89
|
+
// This prevents data driven to be included in the failed screenshot file name
|
|
90
|
+
if (fileName.indexOf('{') !== -1) {
|
|
91
|
+
fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
|
|
103
92
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
93
|
+
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook')
|
|
94
|
+
fileName = clearString(`${test.title}_${test.ctx.test.title}`)
|
|
95
|
+
if (options.uniqueScreenshotNames && test) {
|
|
96
|
+
const uuid = _getUUID(test)
|
|
97
|
+
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`
|
|
98
|
+
} else {
|
|
99
|
+
fileName += '.failed.png'
|
|
110
100
|
}
|
|
101
|
+
output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot')
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
if (options.reportDir) {
|
|
105
|
+
fileName = path.join(options.reportDir, fileName)
|
|
106
|
+
const mochaReportDir = path.resolve(process.cwd(), options.reportDir)
|
|
107
|
+
if (!fileExists(mochaReportDir)) {
|
|
108
|
+
fs.mkdirSync(mochaReportDir)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
await helper.saveScreenshot(fileName, options.fullPageScreenshots)
|
|
112
|
+
|
|
113
|
+
if (!test.artifacts) test.artifacts = {}
|
|
114
|
+
test.artifacts.screenshot = path.join(global.output_dir, fileName)
|
|
115
|
+
if (
|
|
116
|
+
Container.mocha().options.reporterOptions['mocha-junit-reporter'] &&
|
|
117
|
+
Container.mocha().options.reporterOptions['mocha-junit-reporter'].options.attachments
|
|
118
|
+
) {
|
|
119
|
+
test.attachments = [path.join(global.output_dir, fileName)]
|
|
120
|
+
}
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
const allureReporter = Container.plugins('allure')
|
|
123
|
+
if (allureReporter) {
|
|
124
|
+
allureReporter.addAttachment(
|
|
125
|
+
'Main session - Last Seen Screenshot',
|
|
126
|
+
fs.readFileSync(path.join(global.output_dir, fileName)),
|
|
127
|
+
dataType,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if (helper.activeSessionName) {
|
|
131
|
+
const sessions = helper.sessionPages || helper.sessionWindows
|
|
132
|
+
for (const sessionName in sessions) {
|
|
133
|
+
const screenshotFileName = `${sessionName}_${fileName}`
|
|
134
|
+
test.artifacts[`${sessionName.replace(/ /g, '_')}_screenshot`] = path.join(
|
|
135
|
+
global.output_dir,
|
|
136
|
+
screenshotFileName,
|
|
137
|
+
)
|
|
138
|
+
allureReporter.addAttachment(
|
|
139
|
+
`${sessionName} - Last Seen Screenshot`,
|
|
140
|
+
fs.readFileSync(path.join(global.output_dir, screenshotFileName)),
|
|
141
|
+
dataType,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
122
144
|
}
|
|
123
145
|
}
|
|
124
|
-
}
|
|
125
146
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
helper.isRunning = false;
|
|
147
|
+
const cucumberReporter = Container.plugins('cucumberJsonReporter')
|
|
148
|
+
if (cucumberReporter) {
|
|
149
|
+
cucumberReporter.addScreenshot(test.artifacts.screenshot)
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
output.plugin(err)
|
|
153
|
+
if (
|
|
154
|
+
err &&
|
|
155
|
+
err.type &&
|
|
156
|
+
err.type === 'RuntimeError' &&
|
|
157
|
+
err.message &&
|
|
158
|
+
(err.message.indexOf('was terminated due to') > -1 ||
|
|
159
|
+
err.message.indexOf('no such window: target window already closed') > -1)
|
|
160
|
+
) {
|
|
161
|
+
output.log(`Can't make screenshot, ${err}`)
|
|
162
|
+
helper.isRunning = false
|
|
163
|
+
}
|
|
144
164
|
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
165
|
+
},
|
|
166
|
+
true,
|
|
167
|
+
)
|
|
168
|
+
})
|
|
148
169
|
|
|
149
170
|
function _getUUID(test) {
|
|
150
171
|
if (test.uuid) {
|
|
151
|
-
return test.uuid
|
|
172
|
+
return test.uuid
|
|
152
173
|
}
|
|
153
174
|
|
|
154
175
|
if (test.ctx && test.ctx.test.uuid) {
|
|
155
|
-
return test.ctx.test.uuid
|
|
176
|
+
return test.ctx.test.uuid
|
|
156
177
|
}
|
|
157
178
|
|
|
158
|
-
return Math.floor(new Date().getTime() / 1000)
|
|
179
|
+
return Math.floor(new Date().getTime() / 1000)
|
|
159
180
|
}
|
|
160
|
-
}
|
|
181
|
+
}
|
package/lib/plugin/selenoid.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
const util = require('util')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const axios = require('axios').default
|
|
5
|
-
const exec = util.promisify(require('child_process').exec)
|
|
6
|
-
const { clearString, deepMerge } = require('../utils')
|
|
7
|
-
const {
|
|
8
|
-
container, event, recorder, output,
|
|
9
|
-
} = require('../index');
|
|
1
|
+
const util = require('util')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const axios = require('axios').default
|
|
5
|
+
const exec = util.promisify(require('child_process').exec)
|
|
6
|
+
const { clearString, deepMerge } = require('../utils')
|
|
7
|
+
const { container, event, recorder, output } = require('../index')
|
|
10
8
|
|
|
11
9
|
const defaultBrowserConfig = {
|
|
12
10
|
chrome: {
|
|
@@ -29,7 +27,7 @@ const defaultBrowserConfig = {
|
|
|
29
27
|
},
|
|
30
28
|
},
|
|
31
29
|
},
|
|
32
|
-
}
|
|
30
|
+
}
|
|
33
31
|
|
|
34
32
|
const dockerCreateScriptArr = [
|
|
35
33
|
'docker create --rm --name $name$',
|
|
@@ -41,29 +39,30 @@ const dockerCreateScriptArr = [
|
|
|
41
39
|
`-e OVERRIDE_VIDEO_OUTPUT_DIR=${global.output_dir}/video/`,
|
|
42
40
|
'$additionalParams$',
|
|
43
41
|
'aerokube/selenoid:latest-release -log-output-dir /opt/selenoid/logs',
|
|
44
|
-
]
|
|
42
|
+
]
|
|
45
43
|
|
|
46
44
|
const dockerImageCheckScript = [
|
|
47
45
|
'docker images',
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
].join(' ')
|
|
52
|
-
|
|
53
|
-
let dockerCreateScript = dockerCreateScriptArr.join(' ')
|
|
54
|
-
let dockerStartScript = 'docker start $name$'
|
|
55
|
-
let dockerStopScript = 'docker stop $name$'
|
|
56
|
-
let seleniumUrl = 'http://localhost:$port$'
|
|
57
|
-
|
|
58
|
-
const supportedHelpers = ['WebDriver']
|
|
59
|
-
const SELENOID_START_TIMEOUT = 2000
|
|
60
|
-
const SELENOID_STOP_TIMEOUT = 10000
|
|
61
|
-
const wait = time
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
46
|
+
"--filter reference='selenoid/video-recorder'",
|
|
47
|
+
"--filter reference='selenoid/chrome:latest'",
|
|
48
|
+
"--filter reference='selenoid/firefox:latest'",
|
|
49
|
+
].join(' ')
|
|
50
|
+
|
|
51
|
+
let dockerCreateScript = dockerCreateScriptArr.join(' ')
|
|
52
|
+
let dockerStartScript = 'docker start $name$'
|
|
53
|
+
let dockerStopScript = 'docker stop $name$'
|
|
54
|
+
let seleniumUrl = 'http://localhost:$port$'
|
|
55
|
+
|
|
56
|
+
const supportedHelpers = ['WebDriver']
|
|
57
|
+
const SELENOID_START_TIMEOUT = 2000
|
|
58
|
+
const SELENOID_STOP_TIMEOUT = 10000
|
|
59
|
+
const wait = (time) =>
|
|
60
|
+
new Promise((res) => {
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
res()
|
|
64
|
+
}, time)
|
|
65
|
+
})
|
|
67
66
|
|
|
68
67
|
/**
|
|
69
68
|
* [Selenoid](https://aerokube.com/selenoid/) plugin automatically starts browsers and video recording.
|
|
@@ -181,18 +180,18 @@ const wait = time => new Promise((res) => {
|
|
|
181
180
|
*/
|
|
182
181
|
|
|
183
182
|
const selenoid = (config) => {
|
|
184
|
-
const helpers = container.helpers()
|
|
185
|
-
let helperName
|
|
183
|
+
const helpers = container.helpers()
|
|
184
|
+
let helperName
|
|
186
185
|
|
|
187
186
|
for (const name of supportedHelpers) {
|
|
188
187
|
if (Object.keys(helpers).indexOf(name) > -1) {
|
|
189
|
-
helperName = name
|
|
188
|
+
helperName = name
|
|
190
189
|
}
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
if (!helperName) {
|
|
194
|
-
output.print(`Selenoid plugin supported only for: ${supportedHelpers.toString()}`)
|
|
195
|
-
return
|
|
193
|
+
output.print(`Selenoid plugin supported only for: ${supportedHelpers.toString()}`)
|
|
194
|
+
return // no helpers for Selenoid
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
const {
|
|
@@ -202,169 +201,184 @@ const selenoid = (config) => {
|
|
|
202
201
|
additionalParams = '',
|
|
203
202
|
autoCreate = true,
|
|
204
203
|
port = 4444,
|
|
205
|
-
} = config
|
|
206
|
-
const passedTests = []
|
|
204
|
+
} = config
|
|
205
|
+
const passedTests = []
|
|
207
206
|
|
|
208
|
-
recorder.startUnlessRunning()
|
|
209
|
-
replaceScriptConfig({ name, additionalParams, port })
|
|
207
|
+
recorder.startUnlessRunning()
|
|
208
|
+
replaceScriptConfig({ name, additionalParams, port })
|
|
210
209
|
|
|
211
210
|
if (autoStart) {
|
|
212
211
|
event.dispatcher.on(event.all.before, () => {
|
|
213
212
|
recorder.add('Starting selenoid', () => {
|
|
214
|
-
output.debug('Staring Selenoid... ')
|
|
213
|
+
output.debug('Staring Selenoid... ')
|
|
215
214
|
return createAndStart(autoCreate)
|
|
216
215
|
.then(() => output.debug('Selenoid started'))
|
|
217
|
-
.catch((err) => {
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
.catch((err) => {
|
|
217
|
+
throw new Error(err.stack)
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
})
|
|
220
221
|
|
|
221
222
|
event.dispatcher.on(event.all.after, () => {
|
|
222
223
|
recorder.add('Stopping selenoid', () => {
|
|
223
|
-
output.debug('Stopping Selenoid...')
|
|
224
|
+
output.debug('Stopping Selenoid...')
|
|
224
225
|
return wait(SELENOID_STOP_TIMEOUT)
|
|
225
226
|
.then(() => deletePassedTests(passedTests))
|
|
226
227
|
.then(stopSelenoid)
|
|
227
228
|
.then(() => output.debug('Selenoid stopped'))
|
|
228
|
-
.catch((err) => {
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
.catch((err) => {
|
|
230
|
+
throw new Error(err.stack)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
})
|
|
231
234
|
}
|
|
232
235
|
|
|
233
236
|
event.dispatcher.on(event.all.before, () => {
|
|
234
237
|
switch (helperName) {
|
|
235
|
-
case 'WebDriver':
|
|
238
|
+
case 'WebDriver':
|
|
239
|
+
setOptionsForWebdriver(config)
|
|
240
|
+
break
|
|
236
241
|
}
|
|
237
|
-
})
|
|
242
|
+
})
|
|
238
243
|
|
|
239
244
|
event.dispatcher.on(event.test.before, (test) => {
|
|
240
245
|
switch (helperName) {
|
|
241
|
-
case 'WebDriver':
|
|
246
|
+
case 'WebDriver':
|
|
247
|
+
setTestConfigForWebdriver(test)
|
|
248
|
+
break
|
|
242
249
|
}
|
|
243
|
-
})
|
|
250
|
+
})
|
|
244
251
|
|
|
245
252
|
if (config.enableVideo) {
|
|
246
253
|
event.dispatcher.on(event.test.passed, (test) => {
|
|
247
254
|
if (deletePassed) {
|
|
248
|
-
passedTests.push(test.title)
|
|
255
|
+
passedTests.push(test.title)
|
|
249
256
|
} else {
|
|
250
|
-
test.artifacts.video = videoSaved(test)
|
|
257
|
+
test.artifacts.video = videoSaved(test)
|
|
251
258
|
}
|
|
252
|
-
})
|
|
259
|
+
})
|
|
253
260
|
|
|
254
261
|
event.dispatcher.on(event.test.failed, (test) => {
|
|
255
|
-
test.artifacts.video = videoSaved(test)
|
|
256
|
-
})
|
|
262
|
+
test.artifacts.video = videoSaved(test)
|
|
263
|
+
})
|
|
257
264
|
}
|
|
258
|
-
}
|
|
265
|
+
}
|
|
259
266
|
|
|
260
|
-
module.exports = selenoid
|
|
267
|
+
module.exports = selenoid
|
|
261
268
|
|
|
262
269
|
function videoSaved(test) {
|
|
263
|
-
const fileName = `${clearString(test.title)}.mp4
|
|
264
|
-
const videoFile = path.join(global.output_dir, 'video', fileName)
|
|
265
|
-
output.debug(`Video has been saved to file://${videoFile}`)
|
|
266
|
-
const allureReporter = container.plugins('allure')
|
|
270
|
+
const fileName = `${clearString(test.title)}.mp4`
|
|
271
|
+
const videoFile = path.join(global.output_dir, 'video', fileName)
|
|
272
|
+
output.debug(`Video has been saved to file://${videoFile}`)
|
|
273
|
+
const allureReporter = container.plugins('allure')
|
|
267
274
|
if (allureReporter) {
|
|
268
|
-
allureReporter.addAttachment('Video', fs.readFileSync(videoFile), 'video/mp4')
|
|
275
|
+
allureReporter.addAttachment('Video', fs.readFileSync(videoFile), 'video/mp4')
|
|
269
276
|
}
|
|
270
|
-
return videoFile
|
|
277
|
+
return videoFile
|
|
271
278
|
}
|
|
272
279
|
|
|
273
280
|
const createSelenoidConfig = () => {
|
|
274
|
-
const configPath = path.join(global.codecept_dir, 'browsers.json')
|
|
281
|
+
const configPath = path.join(global.codecept_dir, 'browsers.json')
|
|
275
282
|
return new Promise((res, rej) => {
|
|
276
283
|
try {
|
|
277
284
|
if (fs.existsSync(configPath)) {
|
|
278
|
-
res(true)
|
|
285
|
+
res(true)
|
|
279
286
|
} else {
|
|
280
|
-
const data = new Uint8Array(Buffer.from(JSON.stringify(defaultBrowserConfig)))
|
|
281
|
-
fs.writeFileSync(configPath, data)
|
|
282
|
-
res(true)
|
|
287
|
+
const data = new Uint8Array(Buffer.from(JSON.stringify(defaultBrowserConfig)))
|
|
288
|
+
fs.writeFileSync(configPath, data)
|
|
289
|
+
res(true)
|
|
283
290
|
}
|
|
284
291
|
} catch (err) {
|
|
285
|
-
rej(err.stack)
|
|
292
|
+
rej(err.stack)
|
|
286
293
|
}
|
|
287
|
-
})
|
|
288
|
-
}
|
|
294
|
+
})
|
|
295
|
+
}
|
|
289
296
|
|
|
290
|
-
const createSelenoid = () => exec(dockerCreateScript)
|
|
297
|
+
const createSelenoid = () => exec(dockerCreateScript)
|
|
291
298
|
|
|
292
|
-
const startSelenoid = () => exec(dockerStartScript)
|
|
299
|
+
const startSelenoid = () => exec(dockerStartScript)
|
|
293
300
|
|
|
294
|
-
const stopSelenoid = () => exec(dockerStopScript)
|
|
301
|
+
const stopSelenoid = () => exec(dockerStopScript)
|
|
295
302
|
|
|
296
|
-
const checkDockerImage = () => exec(dockerImageCheckScript)
|
|
303
|
+
const checkDockerImage = () => exec(dockerImageCheckScript)
|
|
297
304
|
|
|
298
305
|
const pullImage = async () => {
|
|
299
|
-
const { stdout } = await checkDockerImage()
|
|
300
|
-
const pulls = []
|
|
301
|
-
let resultPromise
|
|
306
|
+
const { stdout } = await checkDockerImage()
|
|
307
|
+
const pulls = []
|
|
308
|
+
let resultPromise
|
|
302
309
|
|
|
303
|
-
output.print('Pulling in Selenoid containers. This may take a while when running the first time...')
|
|
310
|
+
output.print('Pulling in Selenoid containers. This may take a while when running the first time...')
|
|
304
311
|
|
|
305
|
-
console.time('Pulled containers')
|
|
312
|
+
console.time('Pulled containers')
|
|
306
313
|
if (!stdout.includes('selenoid/video-recorder')) {
|
|
307
|
-
output.debug('Pulling selenoid/video-recorder...')
|
|
308
|
-
resultPromise = exec('docker pull selenoid/video-recorder:latest-release')
|
|
309
|
-
|
|
310
|
-
|
|
314
|
+
output.debug('Pulling selenoid/video-recorder...')
|
|
315
|
+
resultPromise = exec('docker pull selenoid/video-recorder:latest-release').then(() =>
|
|
316
|
+
output.debug('Pulled in selenoid/video-recorder'),
|
|
317
|
+
)
|
|
318
|
+
pulls.push(resultPromise)
|
|
311
319
|
}
|
|
312
320
|
if (!stdout.includes('selenoid/chrome')) {
|
|
313
|
-
output.debug('Pulling selenoid/chrome...')
|
|
314
|
-
resultPromise = exec('docker pull selenoid/chrome:latest')
|
|
315
|
-
|
|
316
|
-
|
|
321
|
+
output.debug('Pulling selenoid/chrome...')
|
|
322
|
+
resultPromise = exec('docker pull selenoid/chrome:latest').then(() =>
|
|
323
|
+
output.debug('Pulled in selenoid/video-recorder'),
|
|
324
|
+
)
|
|
325
|
+
pulls.push(resultPromise)
|
|
317
326
|
}
|
|
318
327
|
if (!stdout.includes('selenoid/firefox')) {
|
|
319
|
-
output.debug('Pulling selenoid/firefox...')
|
|
320
|
-
resultPromise = exec('docker pull selenoid/firefox:latest')
|
|
321
|
-
|
|
322
|
-
pulls.push(resultPromise);
|
|
328
|
+
output.debug('Pulling selenoid/firefox...')
|
|
329
|
+
resultPromise = exec('docker pull selenoid/firefox:latest').then(() => output.debug('Pulled in selenoid/chrome'))
|
|
330
|
+
pulls.push(resultPromise)
|
|
323
331
|
}
|
|
324
332
|
|
|
325
333
|
return Promise.all(pulls).then(() => {
|
|
326
|
-
console.timeEnd('Pulled containers')
|
|
327
|
-
})
|
|
328
|
-
}
|
|
334
|
+
console.timeEnd('Pulled containers')
|
|
335
|
+
})
|
|
336
|
+
}
|
|
329
337
|
|
|
330
338
|
function createAndStart(autoCreate) {
|
|
331
|
-
const selenoidCreated = autoCreate ? createSelenoidConfig().then(createSelenoid).then(pullImage) : Promise.resolve()
|
|
332
|
-
return selenoidCreated.then(startSelenoid).then(() => wait(SELENOID_START_TIMEOUT))
|
|
339
|
+
const selenoidCreated = autoCreate ? createSelenoidConfig().then(createSelenoid).then(pullImage) : Promise.resolve()
|
|
340
|
+
return selenoidCreated.then(startSelenoid).then(() => wait(SELENOID_START_TIMEOUT))
|
|
333
341
|
}
|
|
334
342
|
|
|
335
343
|
function deletePassedTests(passedTests) {
|
|
336
|
-
const deleteVideoPromiseList = passedTests
|
|
337
|
-
|
|
344
|
+
const deleteVideoPromiseList = passedTests
|
|
345
|
+
.map(clearString)
|
|
346
|
+
.map((test) => axios.delete(`${seleniumUrl}/video/${test}.mp4`))
|
|
347
|
+
const deleteLogPromiseList = passedTests
|
|
348
|
+
.map(clearString)
|
|
349
|
+
.map((test) => axios.delete(`${seleniumUrl}/logs/${test}.log`))
|
|
338
350
|
|
|
339
351
|
return Promise.all(deleteVideoPromiseList.concat(deleteLogPromiseList))
|
|
340
352
|
.then(() => output.debug('Deleted videos and logs for all passed tests'))
|
|
341
|
-
.catch(err => output.error(`Error while deleting video and log files ${err.stack}`))
|
|
353
|
+
.catch((err) => output.error(`Error while deleting video and log files ${err.stack}`))
|
|
342
354
|
}
|
|
343
355
|
|
|
344
356
|
function setOptionsForWebdriver(config) {
|
|
345
|
-
const WebDriver = container.helpers('WebDriver')
|
|
346
|
-
WebDriver._setConfig(
|
|
347
|
-
|
|
348
|
-
|
|
357
|
+
const WebDriver = container.helpers('WebDriver')
|
|
358
|
+
WebDriver._setConfig(
|
|
359
|
+
deepMerge(WebDriver.options, {
|
|
360
|
+
capabilities: { 'selenoid:options': config },
|
|
361
|
+
}),
|
|
362
|
+
)
|
|
349
363
|
}
|
|
350
364
|
|
|
351
365
|
function setTestConfigForWebdriver(test) {
|
|
352
|
-
const WebDriver = container.helpers('WebDriver')
|
|
353
|
-
const fileName = clearString(test.title)
|
|
354
|
-
const { options } = WebDriver
|
|
366
|
+
const WebDriver = container.helpers('WebDriver')
|
|
367
|
+
const fileName = clearString(test.title)
|
|
368
|
+
const { options } = WebDriver
|
|
355
369
|
recorder.add('setting selenoid capabilities', () => {
|
|
356
|
-
options.capabilities['selenoid:options'].name = test.title
|
|
357
|
-
options.capabilities['selenoid:options'].videoName = `${fileName}.mp4
|
|
358
|
-
options.capabilities['selenoid:options'].logName = `${fileName}.log
|
|
359
|
-
WebDriver._setConfig(options)
|
|
360
|
-
})
|
|
370
|
+
options.capabilities['selenoid:options'].name = test.title
|
|
371
|
+
options.capabilities['selenoid:options'].videoName = `${fileName}.mp4`
|
|
372
|
+
options.capabilities['selenoid:options'].logName = `${fileName}.log`
|
|
373
|
+
WebDriver._setConfig(options)
|
|
374
|
+
})
|
|
361
375
|
}
|
|
362
376
|
|
|
363
377
|
function replaceScriptConfig(config) {
|
|
364
378
|
for (const key of Object.keys(config)) {
|
|
365
|
-
dockerCreateScript = dockerCreateScript.replace(new RegExp(`\\$${key}\\$`, 'g'), config[key])
|
|
379
|
+
dockerCreateScript = dockerCreateScript.replace(new RegExp(`\\$${key}\\$`, 'g'), config[key])
|
|
366
380
|
}
|
|
367
|
-
dockerStartScript = dockerStartScript.replace('$name$', config.name)
|
|
368
|
-
dockerStopScript = dockerStopScript.replace('$name$', config.name)
|
|
369
|
-
seleniumUrl = seleniumUrl.replace('$port$', config.port)
|
|
381
|
+
dockerStartScript = dockerStartScript.replace('$name$', config.name)
|
|
382
|
+
dockerStopScript = dockerStopScript.replace('$name$', config.name)
|
|
383
|
+
seleniumUrl = seleniumUrl.replace('$port$', config.port)
|
|
370
384
|
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
const standardActingHelpers = [
|
|
2
|
-
'Playwright',
|
|
3
|
-
'WebDriver',
|
|
4
|
-
'Puppeteer',
|
|
5
|
-
'Appium',
|
|
6
|
-
'TestCafe',
|
|
7
|
-
];
|
|
1
|
+
const standardActingHelpers = ['Playwright', 'WebDriver', 'Puppeteer', 'Appium', 'TestCafe']
|
|
8
2
|
|
|
9
|
-
module.exports = standardActingHelpers
|
|
3
|
+
module.exports = standardActingHelpers
|