ui5-test-runner 5.13.0 → 6.0.0-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/README.md +3 -2
- package/dist/Npm.js +80 -0
- package/dist/browsers/IBrowser.js +1 -0
- package/dist/browsers/factory.js +9 -0
- package/dist/browsers/puppeteer.js +158 -0
- package/dist/cli.js +17 -0
- package/dist/configuration/CommandLine.js +112 -0
- package/dist/configuration/Configuration.js +1 -0
- package/dist/configuration/ConfigurationValidator.js +79 -0
- package/dist/configuration/Option.js +1 -0
- package/dist/configuration/OptionValidationError.js +15 -0
- package/dist/configuration/indexedOptions.js +13 -0
- package/dist/configuration/options.js +191 -0
- package/dist/configuration/validators/OptionValidator.js +1 -0
- package/dist/configuration/validators/boolean.js +15 -0
- package/dist/configuration/validators/browser.js +11 -0
- package/dist/configuration/validators/fsEntry.js +70 -0
- package/dist/configuration/validators/index.js +20 -0
- package/dist/configuration/validators/integer.js +10 -0
- package/dist/configuration/validators/percent.js +17 -0
- package/dist/configuration/validators/regexp.js +20 -0
- package/dist/configuration/validators/string.js +7 -0
- package/dist/configuration/validators/timeout.js +24 -0
- package/dist/configuration/validators/url.js +8 -0
- package/dist/modes/ModeFunction.js +1 -0
- package/dist/modes/Modes.js +9 -0
- package/dist/modes/execute.js +27 -0
- package/dist/modes/help.js +3 -0
- package/dist/modes/log/ILogStorage.js +1 -0
- package/dist/modes/log/LogMetrics.js +9 -0
- package/dist/modes/log/LogReader.js +37 -0
- package/dist/modes/log/LogStorage.js +68 -0
- package/dist/modes/log/REserve.js +101 -0
- package/dist/modes/log/index.js +58 -0
- package/dist/modes/test/REserve.js +31 -0
- package/dist/modes/test/agent.js +8 -0
- package/dist/modes/test/browser.js +37 -0
- package/dist/modes/test/index.js +66 -0
- package/dist/modes/test/pageTask.js +145 -0
- package/dist/modes/test/report.js +3 -0
- package/dist/modes/test/server.js +109 -0
- package/dist/modes/version.js +11 -0
- package/dist/platform/Exit.js +139 -0
- package/dist/platform/FileSystem.js +13 -0
- package/dist/platform/Host.js +10 -0
- package/dist/platform/Http.js +38 -0
- package/dist/platform/Path.js +5 -0
- package/dist/platform/Process.js +133 -0
- package/dist/platform/Terminal.js +47 -0
- package/dist/platform/Thread.js +43 -0
- package/dist/platform/ZLib.js +7 -0
- package/dist/platform/assert.js +17 -0
- package/dist/platform/constants.js +5 -0
- package/dist/platform/environment.js +28 -0
- package/dist/platform/index.js +13 -0
- package/dist/platform/logger/ILogger.js +1 -0
- package/dist/platform/logger/allCompressed.js +54 -0
- package/dist/platform/logger/compress.js +277 -0
- package/dist/platform/logger/output/BaseLoggerOutput.js +158 -0
- package/dist/platform/logger/output/InteractiveLoggerOutput.js +102 -0
- package/dist/platform/logger/output/StaticLoggerOutput.js +32 -0
- package/dist/platform/logger/output/factory.js +10 -0
- package/dist/platform/logger/output.js +58 -0
- package/dist/platform/logger/proxy.js +6 -0
- package/dist/platform/logger/toInternalLogAttributes.js +22 -0
- package/dist/platform/logger/types.js +7 -0
- package/dist/platform/logger.js +138 -0
- package/dist/platform/mock.js +104 -0
- package/dist/platform/version.js +8 -0
- package/dist/platform/workerBootstrap.js +21 -0
- package/dist/reports/html.js +46 -0
- package/dist/types/AgentState.js +1 -0
- package/dist/types/CommonTestReportFormat.js +50 -0
- package/dist/types/IError.js +1 -0
- package/dist/types/IUserInterfaceController.js +1 -0
- package/dist/types/typeUtilities.js +1 -0
- package/dist/ui/agent.js +3 -0
- package/dist/ui/html-report.js +2 -0
- package/dist/ui/lib.js +1 -0
- package/dist/ui/log-viewer.js +2 -0
- package/dist/utils/node/Folder.js +28 -0
- package/dist/utils/node/FramedStreamReader.js +86 -0
- package/dist/utils/node/FramedStreamWriter.js +27 -0
- package/dist/utils/shared/ProgressBar.js +43 -0
- package/dist/utils/shared/TestReportBuilder.js +48 -0
- package/dist/utils/shared/memoize.js +19 -0
- package/dist/utils/shared/object.js +8 -0
- package/dist/utils/shared/parallelize.js +59 -0
- package/dist/utils/shared/string.js +23 -0
- package/dist/utils/shared/toIError.js +17 -0
- package/package.json +73 -50
- package/.releaserc +0 -5
- package/index.js +0 -175
- package/jest.config.json +0 -31
- package/src/add-test-pages.js +0 -67
- package/src/batch.js +0 -214
- package/src/browsers.js +0 -319
- package/src/capabilities/index.js +0 -204
- package/src/capabilities/tests/basic/iframe.html +0 -8
- package/src/capabilities/tests/basic/index.html +0 -12
- package/src/capabilities/tests/basic/index.js +0 -20
- package/src/capabilities/tests/basic/ui5.html +0 -24
- package/src/capabilities/tests/dynamic-include/index.js +0 -21
- package/src/capabilities/tests/dynamic-include/mix.html +0 -11
- package/src/capabilities/tests/dynamic-include/one.html +0 -11
- package/src/capabilities/tests/dynamic-include/post.js +0 -3
- package/src/capabilities/tests/dynamic-include/test.js +0 -1
- package/src/capabilities/tests/dynamic-include/two.html +0 -11
- package/src/capabilities/tests/index.js +0 -16
- package/src/capabilities/tests/local-storage/index.html +0 -16
- package/src/capabilities/tests/local-storage/index.js +0 -21
- package/src/capabilities/tests/screenshot/index.html +0 -23
- package/src/capabilities/tests/screenshot/index.js +0 -24
- package/src/capabilities/tests/scripts/coverage.html +0 -32
- package/src/capabilities/tests/scripts/iframe.html +0 -18
- package/src/capabilities/tests/scripts/index.js +0 -59
- package/src/capabilities/tests/scripts/qunit.html +0 -22
- package/src/capabilities/tests/scripts/testsuite.html +0 -10
- package/src/capabilities/tests/scripts/testsuite.js +0 -8
- package/src/capabilities/tests/timeout/index.html +0 -21
- package/src/capabilities/tests/timeout/index.js +0 -19
- package/src/capabilities/tests/traces/index.html +0 -18
- package/src/capabilities/tests/traces/index.js +0 -81
- package/src/capabilities/tests/ui5/focus.html +0 -89
- package/src/capabilities/tests/ui5/index.js +0 -39
- package/src/capabilities/tests/ui5/language.html +0 -50
- package/src/capabilities/tests/ui5/timezone.html +0 -27
- package/src/clean.js +0 -22
- package/src/cors.js +0 -21
- package/src/coverage.js +0 -384
- package/src/csv-reader.js +0 -36
- package/src/csv-writer.js +0 -55
- package/src/defaults/.nycrc.json +0 -4
- package/src/defaults/browser.js +0 -217
- package/src/defaults/happy-dom.js +0 -123
- package/src/defaults/jsdom/compatibility.js +0 -163
- package/src/defaults/jsdom/debug.js +0 -23
- package/src/defaults/jsdom/resource-loader.js +0 -44
- package/src/defaults/jsdom/sap.ui.test.matchers.visible.js +0 -39
- package/src/defaults/jsdom.js +0 -95
- package/src/defaults/json-report.js +0 -36
- package/src/defaults/junit-xml-report.js +0 -90
- package/src/defaults/playwright.js +0 -142
- package/src/defaults/puppeteer.js +0 -124
- package/src/defaults/report/common.js +0 -38
- package/src/defaults/report/decompress.js +0 -19
- package/src/defaults/report/default.html +0 -99
- package/src/defaults/report/main.js +0 -69
- package/src/defaults/report/progress.js +0 -60
- package/src/defaults/report/styles.css +0 -66
- package/src/defaults/report.js +0 -91
- package/src/defaults/scan-ui5.js +0 -26
- package/src/defaults/selenium-webdriver/chrome.js +0 -39
- package/src/defaults/selenium-webdriver/edge.js +0 -24
- package/src/defaults/selenium-webdriver/firefox.js +0 -30
- package/src/defaults/selenium-webdriver.js +0 -129
- package/src/defaults/text-report.js +0 -108
- package/src/defaults/webdriverio.js +0 -80
- package/src/end.js +0 -62
- package/src/endpoints.js +0 -219
- package/src/error.js +0 -54
- package/src/get-job-progress.js +0 -78
- package/src/handle.js +0 -43
- package/src/if.js +0 -10
- package/src/inject/jest2qunit.js +0 -289
- package/src/inject/opa-iframe-coverage.js +0 -22
- package/src/inject/post.js +0 -141
- package/src/inject/qunit-hooks.js +0 -107
- package/src/inject/qunit-redirect.js +0 -65
- package/src/inject/ui5-coverage.js +0 -33
- package/src/job-mode.js +0 -65
- package/src/job.js +0 -493
- package/src/npm.js +0 -136
- package/src/options.js +0 -95
- package/src/output.js +0 -739
- package/src/parallelize.js +0 -63
- package/src/qunit-hooks.js +0 -219
- package/src/report.js +0 -89
- package/src/reserve.js +0 -25
- package/src/start.js +0 -129
- package/src/symbols.js +0 -8
- package/src/tests.js +0 -183
- package/src/timeout.js +0 -53
- package/src/tools.js +0 -179
- package/src/ui5.js +0 -199
- package/src/unhandled.js +0 -32
package/src/job.js
DELETED
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Command, Option, InvalidArgumentError } = require('commander')
|
|
4
|
-
const { statSync, accessSync, constants } = require('fs')
|
|
5
|
-
const { dirname, join, isAbsolute } = require('path')
|
|
6
|
-
const { name, description, version = 'dev' } = require(join(__dirname, '../package.json'))
|
|
7
|
-
const { getOutput } = require('./output')
|
|
8
|
-
const { $valueSources, $remoteOnLegacy } = require('./symbols')
|
|
9
|
-
const { buildAndCheckMode } = require('./job-mode')
|
|
10
|
-
const { boolean, integer, timeout, url, arrayOf, regex, percent, string } = require('./options')
|
|
11
|
-
|
|
12
|
-
const $status = Symbol('status')
|
|
13
|
-
|
|
14
|
-
function toLongName (name) {
|
|
15
|
-
return name.replace(/([A-Z])([a-z]+)/g, (match, firstLetter, reminder) => `-${firstLetter.toLowerCase()}${reminder}`)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function buildArgs (parameters) {
|
|
19
|
-
const before = []
|
|
20
|
-
const after = []
|
|
21
|
-
let browser = []
|
|
22
|
-
Object.keys(parameters).forEach(name => {
|
|
23
|
-
if (name === '--' || name === 'browserArgs') {
|
|
24
|
-
browser = parameters[name]
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
const value = parameters[name]
|
|
28
|
-
let args
|
|
29
|
-
if (name.startsWith('!')) {
|
|
30
|
-
args = after
|
|
31
|
-
name = name.substring(1)
|
|
32
|
-
} else {
|
|
33
|
-
args = before
|
|
34
|
-
}
|
|
35
|
-
const longName = `--${toLongName(name)}`
|
|
36
|
-
args.push(longName)
|
|
37
|
-
if (!longName.startsWith('--no-') && value !== null) {
|
|
38
|
-
if (Array.isArray(value)) {
|
|
39
|
-
args.push(...value)
|
|
40
|
-
} else {
|
|
41
|
-
args.push(value)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
const stringify = args => args.map(value => value.toString())
|
|
46
|
-
return {
|
|
47
|
-
before: stringify(before),
|
|
48
|
-
after: stringify(after),
|
|
49
|
-
browser: stringify(browser)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function lib (value) {
|
|
54
|
-
if (value.includes('=')) {
|
|
55
|
-
const [relative, source] = value.split('=')
|
|
56
|
-
return { relative, source }
|
|
57
|
-
} else {
|
|
58
|
-
return { relative: '', source: value }
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function mapping (value) {
|
|
63
|
-
try {
|
|
64
|
-
const [, match, handler, mapping] = /([^=]*)=(file|url)\((.*)\)/.exec(value)
|
|
65
|
-
return {
|
|
66
|
-
match,
|
|
67
|
-
[handler]: mapping
|
|
68
|
-
}
|
|
69
|
-
} catch (e) {
|
|
70
|
-
throw new InvalidArgumentError('Invalid mapping')
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function getCommand (cwd) {
|
|
75
|
-
const command = new Command()
|
|
76
|
-
command.exitOverride()
|
|
77
|
-
|
|
78
|
-
const DEBUG_OPTION = '(🐞 for debugging purpose)'
|
|
79
|
-
const EXPERIMENTAL_OPTION = '[⚠️ experimental]'
|
|
80
|
-
const DANGEROUS_OPTION = '[💣 use carefully]'
|
|
81
|
-
|
|
82
|
-
command
|
|
83
|
-
.name(name)
|
|
84
|
-
.description(description)
|
|
85
|
-
.version(version)
|
|
86
|
-
|
|
87
|
-
.option('--capabilities', '🧪 Capabilities tester for browser')
|
|
88
|
-
.option('-u, --url <url...>', '🔗 URL of the testsuite / page to test', arrayOf(url))
|
|
89
|
-
|
|
90
|
-
// Common to all modes
|
|
91
|
-
.addOption(
|
|
92
|
-
new Option('-c, --cwd <path>', '[💻🔗🧪] Set working directory')
|
|
93
|
-
.default(cwd, 'current working directory')
|
|
94
|
-
)
|
|
95
|
-
.option('--config <json>', '[💻🔗🧪] Configuration file (relative to cwd)', string, 'ui5-test-runner.json')
|
|
96
|
-
.option('--port <port>', '[💻🔗🧪] Port to use (0 to use any free one)', integer, 0)
|
|
97
|
-
.option('-r, --report-dir <path>', '[💻🔗🧪] Directory to output test reports (relative to cwd)', 'report')
|
|
98
|
-
.option('-pt, --page-timeout <timeout>', '[💻🔗🧪📡] Limit the page execution time, fails the page if it takes longer than the timeout (0 means no timeout)', timeout, 0)
|
|
99
|
-
.option('-f, --fail-fast [flag]', '[💻🔗🧪📡] Stop the execution after the first failing page', boolean, false)
|
|
100
|
-
.option('-fo, --fail-opa-fast [flag]', '[💻🔗📡] Stop the OPA page execution after the first failing test', boolean, false)
|
|
101
|
-
.option('-k, --keep-alive [flag]', '[💻🔗🧪] Keep the server alive', boolean, false)
|
|
102
|
-
.option('-l, --log-server [flag]', '[💻🔗🧪📡] Log inner server traces', boolean, false)
|
|
103
|
-
.option('-p, --parallel <count>', '[💻🔗🧪] Number of parallel tests executions', integer, 2)
|
|
104
|
-
.option('-b, --browser <command>', '[💻🔗🧪📡] Browser instantiation command (relative to cwd or use $/ for provided ones)', '$/puppeteer.js')
|
|
105
|
-
.option('--browser-args <argument...>', '[💻🔗🧪📡] Browser instantiation command parameters (use -- instead)')
|
|
106
|
-
.option('--alternate-npm-path <path>', '[💻🔗📡] Alternate NPM path to look for packages (priority: local, alternate, global)')
|
|
107
|
-
.option('--no-npm-install', '[💻🔗🧪📡] Prevent any NPM install (execution may fail if a dependency is missing)')
|
|
108
|
-
.option('-bt, --browser-close-timeout <timeout>', '[💻🔗🧪📡] Maximum waiting time for browser close', timeout, 2000)
|
|
109
|
-
.option('-br, --browser-retry <count>', '[💻🔗🧪📡] Browser instantiation retries : if the command fails unexpectedly, it is re-executed (0 means no retry)', 1)
|
|
110
|
-
.option('-oi, --output-interval <interval>', '[💻🔗🧪📡] Interval for reporting progress on non interactive output (CI/CD) (0 means no output)', timeout, 30000)
|
|
111
|
-
.option('--offline [flag]', '[💻🔗🧪📡] Limit network usage (implies --no-npm-install)', boolean, false)
|
|
112
|
-
.option('--env <name=value...>', '[💻🔗🧪📡] Set environment variable', arrayOf(string))
|
|
113
|
-
.option('--localhost <host>', `[💻🔗🧪📡] ${DANGEROUS_OPTION} Hostname for legacy URLs and callbacks`, string, 'localhost')
|
|
114
|
-
.option('--ci [flag]', '[💻🔗🧪📡] CI mode (no interactive output)', boolean, false)
|
|
115
|
-
.option('--deep-probe [flag]', '[💻🔗🧪📡] Deep probe (recursive, slower)', boolean, false)
|
|
116
|
-
.option('--probe-parallel <count>', '[💻🔗🧪📡] Number of parallel probes (0 to use --parallel)', integer, 0)
|
|
117
|
-
|
|
118
|
-
// Common to legacy and url
|
|
119
|
-
.option('--webapp <path>', '[💻🔗] Base folder of the web application (relative to cwd)', 'webapp')
|
|
120
|
-
.option('-pf, --page-filter <regexp>', '[💻🔗📡] Filter out pages not matching the regexp')
|
|
121
|
-
.option('-pp, --page-params <params>', '[💻🔗📡] Add parameters to page URL')
|
|
122
|
-
.option('--page-close-timeout <timeout>', '[💻🔗📡] Maximum waiting time for page close', timeout, 250)
|
|
123
|
-
.option('-t, --global-timeout <timeout>', '[💻🔗📡] Limit the pages execution time, fail the page if it takes longer than the timeout (0 means no timeout)', timeout, 0)
|
|
124
|
-
.option('--screenshot [flag]', '[💻🔗📡] Take screenshots during the tests execution (if supported by the browser)', boolean, true)
|
|
125
|
-
.option('--no-screenshot', '[💻🔗📡] Disable screenshots during the tests execution (but not on failure, see --screenshot-on-failure)')
|
|
126
|
-
.option('--screenshot-on-failure <flag>', '[💻🔗📡] Take a screenshot when a test fails (even if --screenshot is false)', boolean, true)
|
|
127
|
-
.option('-st, --screenshot-timeout <timeout>', '[💻🔗📡] Maximum waiting time for browser screenshot', timeout, 5000)
|
|
128
|
-
.option('-so, --split-opa [flag]', '[💻🔗📡] Split OPA tests using QUnit modules', boolean, false)
|
|
129
|
-
.option('-rg, --report-generator <path...>', '[💻🔗📡] Report generator paths (relative to cwd or use $/ for provided ones)', ['$/report.js'])
|
|
130
|
-
.option('--progress-page <path>', '[💻🔗📡] Progress page path (relative to cwd or use $/ for provided ones)', '$/report/default.html')
|
|
131
|
-
.option('--jest [flag]', `[💻🔗📡] ${EXPERIMENTAL_OPTION} Simulate jest environment`)
|
|
132
|
-
.option('--qunit-batch-size <size>', `[💻🔗📡] ${EXPERIMENTAL_OPTION} QUnit hooks batch size (disables screenshots)`, integer, 0)
|
|
133
|
-
|
|
134
|
-
.option('--coverage [flag]', '[💻🔗📡] Enable or disable code coverage', boolean)
|
|
135
|
-
.option('--no-coverage', '[💻🔗📡] Disable code coverage')
|
|
136
|
-
.option('-cs, --coverage-settings <path>', '[💻🔗📡] Path to a custom .nycrc.json file providing settings for instrumentation (relative to cwd or use $/ for provided ones)', '$/.nycrc.json')
|
|
137
|
-
.option('-ctd, --coverage-temp-dir <path>', '[💻🔗] Directory to output raw coverage information to (relative to cwd)', '.nyc_output')
|
|
138
|
-
.option('-crd, --coverage-report-dir <path>', '[💻🔗] Directory to store the coverage report files (relative to cwd)', 'coverage')
|
|
139
|
-
.option('-cr, --coverage-reporters <reporter...>', '[💻🔗📡] List of nyc reporters to use (text is always used)', ['lcov', 'cobertura'])
|
|
140
|
-
.option('-ccb, --coverage-check-branches <percent>', '[💻🔗📡] What % of branches must be covered', percent, 0)
|
|
141
|
-
.option('-ccf, --coverage-check-functions <percent>', '[💻🔗📡] What % of functions must be covered', percent, 0)
|
|
142
|
-
.option('-ccl, --coverage-check-lines <percent>', '[💻🔗📡] What % of lines must be covered', percent, 0)
|
|
143
|
-
.option('-ccs, --coverage-check-statements <percent>', '[💻🔗📡] What % of statements must be covered', percent, 0)
|
|
144
|
-
.option('-crs, --coverage-remote-scanner <path>', '[💻🔗📡] Scan for files when all coverage is requested', '$/scan-ui5.js')
|
|
145
|
-
.option('-s, --serve-only [flag]', '[💻🔗] Serve only', boolean, false)
|
|
146
|
-
|
|
147
|
-
.option('-w, --watch [flag]', '[💻🔗] Monitor the webapp folder (or the one specified with --watch-folder) and re-execute tests on change', boolean, false)
|
|
148
|
-
.option('--watch-folder <path>', '[💻🔗] Folder to monitor with watch (enables --watch if not specified)', string)
|
|
149
|
-
|
|
150
|
-
.option('--start <command>', '[💻🔗] Start command (might be an NPM script or a shell command) ⚠️ the command is killed on tests completion', string)
|
|
151
|
-
.option('--start-wait-url <command>', '[💻🔗] URL to wait for (🔗 defaulted to first url)', url)
|
|
152
|
-
.option('--start-wait-method <method>', '[💻🔗] HTTP method to check the waited URL', 'GET')
|
|
153
|
-
|
|
154
|
-
.option('--start-timeout <timeout>', '[💻🔗] Maximum waiting time for the start command (based on when the first URL becomes available, also used for termination)', timeout, 5000)
|
|
155
|
-
|
|
156
|
-
.option('--end <script>', '[💻🔗] End script (will receive path to `job.js`)', string)
|
|
157
|
-
.option('--end-timeout <timeout>', '[💻🔗] Maximum waiting time for the end script', timeout, 15000)
|
|
158
|
-
|
|
159
|
-
// Specific to legacy (and might be used with url if pointing to local project)
|
|
160
|
-
.option('--ui5 <url>', '[💻📡] UI5 url', url, 'https://ui5.sap.com')
|
|
161
|
-
.option('--disable-ui5 [flag]', '[💻📡] Disable UI5 mapping (also disable libs)', boolean, false)
|
|
162
|
-
.option('--libs <lib...>', '[💻📡] Library mapping (<relative>=<path> or <path>), use *=webapp/resources to map resources sub folder', arrayOf(lib))
|
|
163
|
-
.option('--mappings <mapping...>', '[💻📡] Custom mapping (<match>=<file|url>(<config>))', arrayOf(mapping))
|
|
164
|
-
.option('--cache <path>', '[💻📡] Cache UI5 resources locally in the given folder (empty to disable)')
|
|
165
|
-
.option('--preload <library...>', '[💻📡] Preload UI5 libraries in the cache folder (only if --cache is used)', arrayOf(string))
|
|
166
|
-
.option('--testsuite <path>', '[💻] Path of the testsuite file (relative to webapp, URL parameters are supported)', 'test/testsuite.qunit.html')
|
|
167
|
-
|
|
168
|
-
// Specific to coverage in url mode (experimental)
|
|
169
|
-
.option('-cp, --coverage-proxy [flag]', `[🔗] ${EXPERIMENTAL_OPTION} use internal proxy to instrument remote files`, boolean, false)
|
|
170
|
-
.option('-cpi, --coverage-proxy-include <regexp>', `[🔗] ${EXPERIMENTAL_OPTION} urls to instrument for coverage`, regex, '.*')
|
|
171
|
-
.option('-cpe, --coverage-proxy-exclude <regexp>', `[🔗] ${EXPERIMENTAL_OPTION} urls to ignore for coverage`, regex, '/((test-)?resources|tests?)/')
|
|
172
|
-
|
|
173
|
-
// Batch mode related
|
|
174
|
-
.addOption(new Option('--batch-mode', 'Changes the way options are defaulted (in particular coverage temporary folders)', boolean).hideHelp())
|
|
175
|
-
.option('--batch <specification...>', 'Batch specification', arrayOf(string))
|
|
176
|
-
.option('--batch-id <id>', 'Batch id (used for naming report folder)', string)
|
|
177
|
-
.option('--batch-label <label>', 'Batch label (used while reporting on execution)', string)
|
|
178
|
-
.option('--if <condition>', 'Condition runner execution', string)
|
|
179
|
-
|
|
180
|
-
.addOption(new Option('--debug-dev-mode', DEBUG_OPTION, boolean).hideHelp())
|
|
181
|
-
.addOption(new Option('--debug-probe-only', DEBUG_OPTION, boolean).hideHelp())
|
|
182
|
-
.addOption(new Option('--debug-keep-browser-open', DEBUG_OPTION, boolean).hideHelp())
|
|
183
|
-
.addOption(new Option('--debug-memory', DEBUG_OPTION, boolean).hideHelp())
|
|
184
|
-
.addOption(new Option('--debug-handles', DEBUG_OPTION, boolean).hideHelp())
|
|
185
|
-
.addOption(new Option('--debug-keep-report', DEBUG_OPTION, boolean).hideHelp())
|
|
186
|
-
.addOption(new Option('--debug-capabilities-test <name>', DEBUG_OPTION).hideHelp())
|
|
187
|
-
.addOption(new Option('--debug-capabilities-no-timeout', DEBUG_OPTION, boolean).hideHelp())
|
|
188
|
-
.addOption(new Option('--debug-capabilities-no-script', DEBUG_OPTION, boolean).hideHelp())
|
|
189
|
-
.addOption(new Option('--debug-coverage-no-custom-fs', DEBUG_OPTION, boolean).hideHelp())
|
|
190
|
-
.addOption(new Option('--debug-verbose <module...>', DEBUG_OPTION, arrayOf(string), []).hideHelp())
|
|
191
|
-
|
|
192
|
-
return command
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function parse (cwd, args) {
|
|
196
|
-
const command = getCommand(cwd)
|
|
197
|
-
|
|
198
|
-
command.parse(args, { from: 'user' })
|
|
199
|
-
const options = command.opts()
|
|
200
|
-
|
|
201
|
-
return Object.assign({
|
|
202
|
-
initialCwd: cwd,
|
|
203
|
-
browserArgs: command.args,
|
|
204
|
-
[$valueSources]: Object.keys(options).reduce((valueSources, name) => {
|
|
205
|
-
if (name !== 'browserArgs') {
|
|
206
|
-
valueSources[name] = command.getOptionValueSource(name)
|
|
207
|
-
}
|
|
208
|
-
return valueSources
|
|
209
|
-
}, {})
|
|
210
|
-
}, options)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function checkAccess ({ path, label, file /*, write */ }) {
|
|
214
|
-
try {
|
|
215
|
-
const mode = constants.R_OK
|
|
216
|
-
// if (write) {
|
|
217
|
-
// mode |= constants.W_OK
|
|
218
|
-
// }
|
|
219
|
-
accessSync(path, mode)
|
|
220
|
-
} catch (error) {
|
|
221
|
-
throw new Error(`Unable to access ${label || path}, check your settings`)
|
|
222
|
-
}
|
|
223
|
-
const stat = statSync(path)
|
|
224
|
-
if (file) {
|
|
225
|
-
if (!stat.isFile()) {
|
|
226
|
-
throw new Error(`Unable to access ${label}, file expected`)
|
|
227
|
-
}
|
|
228
|
-
} else {
|
|
229
|
-
if (!stat.isDirectory()) {
|
|
230
|
-
throw new Error(`Unable to access ${label}, folder expected`)
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function finalize (job) {
|
|
236
|
-
function toAbsolute (path, from = job.cwd) {
|
|
237
|
-
path = path.replace(/📂report\b/, job.reportDir)
|
|
238
|
-
if (!isAbsolute(path)) {
|
|
239
|
-
path = join(from, path)
|
|
240
|
-
}
|
|
241
|
-
if (path.endsWith('/') || path.endsWith('\\')) {
|
|
242
|
-
return path.substring(0, path.length - 1)
|
|
243
|
-
}
|
|
244
|
-
return path
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function checkDefault (path) {
|
|
248
|
-
if (path.startsWith('$/')) {
|
|
249
|
-
return join(__dirname, './defaults', path.replace('$/', ''))
|
|
250
|
-
}
|
|
251
|
-
return path
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function updateToAbsolute (member, from = job.cwd) {
|
|
255
|
-
job[member] = toAbsolute(job[member], from)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
'browser,coverageSettings,coverageRemoteScanner,progressPage'
|
|
259
|
-
.split(',')
|
|
260
|
-
.forEach(setting => { job[setting] = checkDefault(job[setting]) })
|
|
261
|
-
updateToAbsolute('cwd', job.initialCwd)
|
|
262
|
-
'webapp,browser,reportDir,coverageSettings,coverageTempDir,coverageReportDir'
|
|
263
|
-
.split(',')
|
|
264
|
-
.forEach(setting => updateToAbsolute(setting))
|
|
265
|
-
if (job.cache) {
|
|
266
|
-
updateToAbsolute('cache')
|
|
267
|
-
if (job.preload && job.offline) {
|
|
268
|
-
throw new Error('--preload cannot be used with --offline')
|
|
269
|
-
}
|
|
270
|
-
} else if (job.preload) {
|
|
271
|
-
throw new Error('--preload cannot be used without --cache')
|
|
272
|
-
}
|
|
273
|
-
if (job.alternateNpmPath) {
|
|
274
|
-
checkAccess({ path: job.alternateNpmPath, label: 'Alternate NPM path' })
|
|
275
|
-
}
|
|
276
|
-
job.mode = buildAndCheckMode(job)
|
|
277
|
-
if (job.mode === 'legacy') {
|
|
278
|
-
checkAccess({ path: job.webapp, label: 'webapp folder' })
|
|
279
|
-
|
|
280
|
-
const [, testsuiteFile] = job.testsuite.match(/([^?]*)(\?.*)?$/)
|
|
281
|
-
const testsuitePath = toAbsolute(testsuiteFile, job.webapp)
|
|
282
|
-
checkAccess({ path: testsuitePath, label: 'testsuite', file: true })
|
|
283
|
-
} else if (job.mode === 'url') {
|
|
284
|
-
if (job[$valueSources].coverage !== 'cli') {
|
|
285
|
-
job.coverage = false
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
checkAccess({ path: job.browser, label: 'browser command', file: true })
|
|
289
|
-
job.reportGenerator = job.reportGenerator.map(setting => {
|
|
290
|
-
const path = toAbsolute(checkDefault(setting), job.cwd)
|
|
291
|
-
checkAccess({ path, label: 'report generator', file: true })
|
|
292
|
-
return path
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
if (!job.libs) {
|
|
296
|
-
job.libs = []
|
|
297
|
-
} else {
|
|
298
|
-
job.libs.forEach(libMapping => {
|
|
299
|
-
libMapping.source = toAbsolute(libMapping.source)
|
|
300
|
-
let description
|
|
301
|
-
if (libMapping.relative) {
|
|
302
|
-
description = `lib mapping of ${libMapping.relative}`
|
|
303
|
-
} else {
|
|
304
|
-
description = 'generic lib mapping'
|
|
305
|
-
}
|
|
306
|
-
checkAccess({ path: libMapping.source, label: `${description} (${libMapping.source})` })
|
|
307
|
-
})
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (!job.env) {
|
|
311
|
-
job.env = {}
|
|
312
|
-
} else {
|
|
313
|
-
job.env = job.env.reduce((dictionary, env) => {
|
|
314
|
-
const equalPos = env.indexOf('=')
|
|
315
|
-
if (equalPos === -1) {
|
|
316
|
-
dictionary[env] = ''
|
|
317
|
-
} else {
|
|
318
|
-
dictionary[env.slice(0, equalPos)] = env.slice(equalPos + 1)
|
|
319
|
-
}
|
|
320
|
-
return dictionary
|
|
321
|
-
}, {})
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (job.watchFolder) {
|
|
325
|
-
job.watch = true
|
|
326
|
-
job.watchFolder = updateToAbsolute(job.watchFolder)
|
|
327
|
-
} else if (job.watch) {
|
|
328
|
-
job.watchFolder = job.webapp
|
|
329
|
-
}
|
|
330
|
-
if (job.watchFolder) {
|
|
331
|
-
checkAccess({ path: job.watchFolder, label: 'Folder to watch' })
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const output = getOutput(job)
|
|
335
|
-
|
|
336
|
-
if (job.coverage) {
|
|
337
|
-
function overrideIfNotSet (option, valueFromSettings) {
|
|
338
|
-
if (valueFromSettings && job[$valueSources][option] !== 'cli') {
|
|
339
|
-
output.debug('coverage', `${option} extracted from nyc settings : ${valueFromSettings}`)
|
|
340
|
-
job[option] = valueFromSettings
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function overrideDirIfNotSet (option, valueFromSettings) {
|
|
345
|
-
if (valueFromSettings && !isAbsolute(valueFromSettings)) {
|
|
346
|
-
valueFromSettings = join(dirname(job.coverageSettings), valueFromSettings)
|
|
347
|
-
}
|
|
348
|
-
overrideIfNotSet(option, valueFromSettings)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
checkAccess({ path: job.coverageSettings, file: true, label: 'coverage settings' })
|
|
352
|
-
|
|
353
|
-
let settings
|
|
354
|
-
try {
|
|
355
|
-
settings = require(job.coverageSettings)
|
|
356
|
-
} catch (e) {
|
|
357
|
-
throw new Error(`Unable to read ${job.coverageSettings} as JSON`)
|
|
358
|
-
}
|
|
359
|
-
overrideDirIfNotSet('coverageReportDir', settings['report-dir'])
|
|
360
|
-
overrideDirIfNotSet('coverageTempDir', settings['temp-dir'])
|
|
361
|
-
overrideIfNotSet('coverageReporters', settings.reporter)
|
|
362
|
-
|
|
363
|
-
checkAccess({ path: job.coverageRemoteScanner, label: 'coverage remote scanner', file: true })
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (job.mode === 'url') {
|
|
367
|
-
const port = job.port.toString()
|
|
368
|
-
job[$remoteOnLegacy] = job.url && job.url.every(url => {
|
|
369
|
-
// ignore host name since the machine might be exposed with any name
|
|
370
|
-
const parsedUrl = new URL(url)
|
|
371
|
-
return parsedUrl.port === port
|
|
372
|
-
})
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (job.qunitBatchSize) {
|
|
376
|
-
job.screenshot = false
|
|
377
|
-
job.screenshotOnFailure = false
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
job[$status] = 'Starting'
|
|
381
|
-
Object.defineProperty(job, 'status', {
|
|
382
|
-
get () {
|
|
383
|
-
return job[$status]
|
|
384
|
-
},
|
|
385
|
-
set (value) {
|
|
386
|
-
job[$status] = value
|
|
387
|
-
output.status(value)
|
|
388
|
-
},
|
|
389
|
-
enumerable: false,
|
|
390
|
-
configurable: false
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
// Because start and end are already used
|
|
394
|
-
job.startCommand = job.start
|
|
395
|
-
delete job.start
|
|
396
|
-
job.endScript = job.end
|
|
397
|
-
delete job.end
|
|
398
|
-
|
|
399
|
-
if (job.startCommand) {
|
|
400
|
-
if (!job.startWaitUrl) {
|
|
401
|
-
job.startWaitUrl = job.url[0]
|
|
402
|
-
}
|
|
403
|
-
if (!job.startWaitUrl) {
|
|
404
|
-
throw new Error('Start command defined but no URL to wait for')
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (job.batchMode) {
|
|
409
|
-
job.outputInterval = 1000
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/* istanbul ignore next */
|
|
413
|
-
if (process.env.DEBUG_ON_FAILED) {
|
|
414
|
-
let failed
|
|
415
|
-
Object.defineProperty(job, 'failed', {
|
|
416
|
-
get () {
|
|
417
|
-
return failed
|
|
418
|
-
},
|
|
419
|
-
set (value) {
|
|
420
|
-
if (value) {
|
|
421
|
-
// eslint-disable-next-line no-debugger
|
|
422
|
-
debugger
|
|
423
|
-
}
|
|
424
|
-
failed = value
|
|
425
|
-
},
|
|
426
|
-
enumerable: true,
|
|
427
|
-
configurable: false
|
|
428
|
-
})
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
function fromCmdLine (cwd, cmdLineArgs) {
|
|
433
|
-
let job = parse(cwd, cmdLineArgs)
|
|
434
|
-
|
|
435
|
-
let defaultPath
|
|
436
|
-
const isConfigSet = job[$valueSources].config === 'cli'
|
|
437
|
-
if (isAbsolute(job.config)) {
|
|
438
|
-
defaultPath = job.config
|
|
439
|
-
} else {
|
|
440
|
-
defaultPath = join(job.cwd, job.config)
|
|
441
|
-
if (!isAbsolute(defaultPath)) {
|
|
442
|
-
defaultPath = join(job.initialCwd, defaultPath)
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
let hasDefaultSettings = false
|
|
446
|
-
try {
|
|
447
|
-
checkAccess({ path: defaultPath, file: true })
|
|
448
|
-
hasDefaultSettings = true
|
|
449
|
-
} catch (e) {
|
|
450
|
-
if (isConfigSet) {
|
|
451
|
-
throw e
|
|
452
|
-
}
|
|
453
|
-
// ignore
|
|
454
|
-
}
|
|
455
|
-
if (hasDefaultSettings) {
|
|
456
|
-
const defaults = require(defaultPath)
|
|
457
|
-
if (defaults.cwd && !isAbsolute(defaults.cwd)) {
|
|
458
|
-
// make it relative to the configuration file
|
|
459
|
-
defaults.cwd = join(dirname(defaultPath), defaults.cwd)
|
|
460
|
-
} else if (isConfigSet) {
|
|
461
|
-
defaults.cwd = dirname(defaultPath)
|
|
462
|
-
}
|
|
463
|
-
const { before, after, browser } = buildArgs(defaults)
|
|
464
|
-
const sep = cmdLineArgs.indexOf('--')
|
|
465
|
-
const args = sep === -1
|
|
466
|
-
? [...before, ...cmdLineArgs, ...after, '--', ...browser]
|
|
467
|
-
: [...before, ...cmdLineArgs.slice(0, sep), ...after, '--', ...browser, ...cmdLineArgs.slice(sep + 1)]
|
|
468
|
-
job = parse(cwd, args)
|
|
469
|
-
job.configContent = defaults
|
|
470
|
-
job.configArgs = args
|
|
471
|
-
} else {
|
|
472
|
-
job.configContent = 'none'
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
job.cmdLineArgs = cmdLineArgs
|
|
476
|
-
finalize(job)
|
|
477
|
-
return job
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function fromObject (cwd, parameters) {
|
|
481
|
-
const { before, browser } = buildArgs(parameters)
|
|
482
|
-
if (browser.length) {
|
|
483
|
-
return fromCmdLine(cwd, [...before, '--', ...browser])
|
|
484
|
-
}
|
|
485
|
-
return fromCmdLine(cwd, [...before])
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
module.exports = {
|
|
489
|
-
getCommand,
|
|
490
|
-
fromCmdLine,
|
|
491
|
-
fromObject,
|
|
492
|
-
toLongName
|
|
493
|
-
}
|
package/src/npm.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
const { exec } = require('child_process')
|
|
2
|
-
const { sep, join } = require('path')
|
|
3
|
-
const { stat } = require('fs/promises')
|
|
4
|
-
const { UTRError } = require('./error')
|
|
5
|
-
const { getOutput } = require('./output')
|
|
6
|
-
|
|
7
|
-
function npm (job, ...args) {
|
|
8
|
-
return new Promise((resolve, reject) => {
|
|
9
|
-
const childProcess = exec(`npm ${args.join(' ')}`, (err, stdout, stderr) => {
|
|
10
|
-
if (err) {
|
|
11
|
-
reject(UTRError.NPM_FAILED(stderr))
|
|
12
|
-
} else {
|
|
13
|
-
resolve(stdout.trim())
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
if (args[0] === 'install') {
|
|
17
|
-
getOutput(job).monitor(childProcess)
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function folderExists (path) {
|
|
23
|
-
try {
|
|
24
|
-
const result = await stat(path)
|
|
25
|
-
return result.isDirectory()
|
|
26
|
-
} catch (e) {
|
|
27
|
-
return false
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let localRoot
|
|
32
|
-
let globalRoot
|
|
33
|
-
|
|
34
|
-
function resolveDependencyPath (name) {
|
|
35
|
-
require(name)
|
|
36
|
-
const pattern = `${sep}node_modules${sep}${name}${sep}`
|
|
37
|
-
const path = Object.keys(require.cache).filter(path => path.includes(pattern))[0]
|
|
38
|
-
if (path) {
|
|
39
|
-
const pos = path.indexOf(pattern)
|
|
40
|
-
return path.substring(0, pos + pattern.length - 1)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function findDependencyPath (job, name) {
|
|
45
|
-
if (!localRoot) {
|
|
46
|
-
[localRoot, globalRoot] = await Promise.all([
|
|
47
|
-
npm(job, 'root'),
|
|
48
|
-
npm(job, 'root', '--global')
|
|
49
|
-
])
|
|
50
|
-
}
|
|
51
|
-
const localPath = join(localRoot, name)
|
|
52
|
-
if (await folderExists(localPath)) {
|
|
53
|
-
return [localPath, false]
|
|
54
|
-
}
|
|
55
|
-
if (job.alternateNpmPath) {
|
|
56
|
-
const alternatePath = join(job.alternateNpmPath, name)
|
|
57
|
-
if (await folderExists(alternatePath)) {
|
|
58
|
-
return [alternatePath, false]
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
const globalPath = join(globalRoot, name)
|
|
62
|
-
let justInstalled = false
|
|
63
|
-
if (!await folderExists(globalPath)) {
|
|
64
|
-
if (!job.npmInstall || job.offline) {
|
|
65
|
-
throw UTRError.NPM_DEPENDENCY_NOT_FOUND(name)
|
|
66
|
-
}
|
|
67
|
-
const previousStatus = job.status
|
|
68
|
-
job.status = `Installing ${name}...`
|
|
69
|
-
await npm(job, 'install', name, '-g')
|
|
70
|
-
justInstalled = true
|
|
71
|
-
job.status = previousStatus
|
|
72
|
-
}
|
|
73
|
-
return [globalPath, justInstalled]
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const noop = () => {}
|
|
77
|
-
|
|
78
|
-
function getSafeJobAndOutput (nullableJob) {
|
|
79
|
-
if (nullableJob) {
|
|
80
|
-
return { job: nullableJob, output: getOutput(nullableJob) }
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
job: {
|
|
84
|
-
offline: true
|
|
85
|
-
},
|
|
86
|
-
output: {
|
|
87
|
-
debug: noop,
|
|
88
|
-
resolvedPackage: noop,
|
|
89
|
-
packageNotLatest: noop
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function checkLatest (nullableJob, name, installedVersion) {
|
|
95
|
-
const { job, output } = getSafeJobAndOutput(nullableJob)
|
|
96
|
-
if (!job.offline) {
|
|
97
|
-
output.debug('npm', `fetching latest version of package ${name}`)
|
|
98
|
-
const latestVersion = await npm(job, 'view', name, 'version')
|
|
99
|
-
if (latestVersion !== installedVersion) {
|
|
100
|
-
output.packageNotLatest(name, latestVersion)
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
output.debug('npm', `offline=${job.offline}`)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
module.exports = {
|
|
108
|
-
resolveDependencyPath,
|
|
109
|
-
checkLatest,
|
|
110
|
-
|
|
111
|
-
async resolvePackage (nullableJob, name) {
|
|
112
|
-
const { job, output } = getSafeJobAndOutput(nullableJob)
|
|
113
|
-
let modulePath
|
|
114
|
-
let justInstalled = false
|
|
115
|
-
output.debug('npm', `resolving dependency path of package ${name}...`)
|
|
116
|
-
try {
|
|
117
|
-
modulePath = resolveDependencyPath(name)
|
|
118
|
-
} catch (e) {
|
|
119
|
-
output.debug('npm', e)
|
|
120
|
-
}
|
|
121
|
-
if (!modulePath) {
|
|
122
|
-
output.debug('npm', `finding dependency path of package ${name}...`);
|
|
123
|
-
[modulePath, justInstalled] = await findDependencyPath(job, name)
|
|
124
|
-
}
|
|
125
|
-
output.debug('npm', `opening installed package ${name}`)
|
|
126
|
-
const installedPackage = require(join(modulePath, 'package.json'))
|
|
127
|
-
const { version: installedVersion } = installedPackage
|
|
128
|
-
output.resolvedPackage(name, modulePath, installedVersion)
|
|
129
|
-
if (!justInstalled) {
|
|
130
|
-
checkLatest(job, name, installedVersion)
|
|
131
|
-
} else {
|
|
132
|
-
output.debug('npm', `justInstalled=${justInstalled}`)
|
|
133
|
-
}
|
|
134
|
-
return modulePath
|
|
135
|
-
}
|
|
136
|
-
}
|