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.
Files changed (186) hide show
  1. package/README.md +3 -2
  2. package/dist/Npm.js +80 -0
  3. package/dist/browsers/IBrowser.js +1 -0
  4. package/dist/browsers/factory.js +9 -0
  5. package/dist/browsers/puppeteer.js +158 -0
  6. package/dist/cli.js +17 -0
  7. package/dist/configuration/CommandLine.js +112 -0
  8. package/dist/configuration/Configuration.js +1 -0
  9. package/dist/configuration/ConfigurationValidator.js +79 -0
  10. package/dist/configuration/Option.js +1 -0
  11. package/dist/configuration/OptionValidationError.js +15 -0
  12. package/dist/configuration/indexedOptions.js +13 -0
  13. package/dist/configuration/options.js +191 -0
  14. package/dist/configuration/validators/OptionValidator.js +1 -0
  15. package/dist/configuration/validators/boolean.js +15 -0
  16. package/dist/configuration/validators/browser.js +11 -0
  17. package/dist/configuration/validators/fsEntry.js +70 -0
  18. package/dist/configuration/validators/index.js +20 -0
  19. package/dist/configuration/validators/integer.js +10 -0
  20. package/dist/configuration/validators/percent.js +17 -0
  21. package/dist/configuration/validators/regexp.js +20 -0
  22. package/dist/configuration/validators/string.js +7 -0
  23. package/dist/configuration/validators/timeout.js +24 -0
  24. package/dist/configuration/validators/url.js +8 -0
  25. package/dist/modes/ModeFunction.js +1 -0
  26. package/dist/modes/Modes.js +9 -0
  27. package/dist/modes/execute.js +27 -0
  28. package/dist/modes/help.js +3 -0
  29. package/dist/modes/log/ILogStorage.js +1 -0
  30. package/dist/modes/log/LogMetrics.js +9 -0
  31. package/dist/modes/log/LogReader.js +37 -0
  32. package/dist/modes/log/LogStorage.js +68 -0
  33. package/dist/modes/log/REserve.js +101 -0
  34. package/dist/modes/log/index.js +58 -0
  35. package/dist/modes/test/REserve.js +31 -0
  36. package/dist/modes/test/agent.js +8 -0
  37. package/dist/modes/test/browser.js +37 -0
  38. package/dist/modes/test/index.js +66 -0
  39. package/dist/modes/test/pageTask.js +145 -0
  40. package/dist/modes/test/report.js +3 -0
  41. package/dist/modes/test/server.js +109 -0
  42. package/dist/modes/version.js +11 -0
  43. package/dist/platform/Exit.js +139 -0
  44. package/dist/platform/FileSystem.js +13 -0
  45. package/dist/platform/Host.js +10 -0
  46. package/dist/platform/Http.js +38 -0
  47. package/dist/platform/Path.js +5 -0
  48. package/dist/platform/Process.js +133 -0
  49. package/dist/platform/Terminal.js +47 -0
  50. package/dist/platform/Thread.js +43 -0
  51. package/dist/platform/ZLib.js +7 -0
  52. package/dist/platform/assert.js +17 -0
  53. package/dist/platform/constants.js +5 -0
  54. package/dist/platform/environment.js +28 -0
  55. package/dist/platform/index.js +13 -0
  56. package/dist/platform/logger/ILogger.js +1 -0
  57. package/dist/platform/logger/allCompressed.js +54 -0
  58. package/dist/platform/logger/compress.js +277 -0
  59. package/dist/platform/logger/output/BaseLoggerOutput.js +158 -0
  60. package/dist/platform/logger/output/InteractiveLoggerOutput.js +102 -0
  61. package/dist/platform/logger/output/StaticLoggerOutput.js +32 -0
  62. package/dist/platform/logger/output/factory.js +10 -0
  63. package/dist/platform/logger/output.js +58 -0
  64. package/dist/platform/logger/proxy.js +6 -0
  65. package/dist/platform/logger/toInternalLogAttributes.js +22 -0
  66. package/dist/platform/logger/types.js +7 -0
  67. package/dist/platform/logger.js +138 -0
  68. package/dist/platform/mock.js +104 -0
  69. package/dist/platform/version.js +8 -0
  70. package/dist/platform/workerBootstrap.js +21 -0
  71. package/dist/reports/html.js +46 -0
  72. package/dist/types/AgentState.js +1 -0
  73. package/dist/types/CommonTestReportFormat.js +50 -0
  74. package/dist/types/IError.js +1 -0
  75. package/dist/types/IUserInterfaceController.js +1 -0
  76. package/dist/types/typeUtilities.js +1 -0
  77. package/dist/ui/agent.js +3 -0
  78. package/dist/ui/html-report.js +2 -0
  79. package/dist/ui/lib.js +1 -0
  80. package/dist/ui/log-viewer.js +2 -0
  81. package/dist/utils/node/Folder.js +28 -0
  82. package/dist/utils/node/FramedStreamReader.js +86 -0
  83. package/dist/utils/node/FramedStreamWriter.js +27 -0
  84. package/dist/utils/shared/ProgressBar.js +43 -0
  85. package/dist/utils/shared/TestReportBuilder.js +48 -0
  86. package/dist/utils/shared/memoize.js +19 -0
  87. package/dist/utils/shared/object.js +8 -0
  88. package/dist/utils/shared/parallelize.js +59 -0
  89. package/dist/utils/shared/string.js +23 -0
  90. package/dist/utils/shared/toIError.js +17 -0
  91. package/package.json +73 -50
  92. package/.releaserc +0 -5
  93. package/index.js +0 -175
  94. package/jest.config.json +0 -31
  95. package/src/add-test-pages.js +0 -67
  96. package/src/batch.js +0 -214
  97. package/src/browsers.js +0 -319
  98. package/src/capabilities/index.js +0 -204
  99. package/src/capabilities/tests/basic/iframe.html +0 -8
  100. package/src/capabilities/tests/basic/index.html +0 -12
  101. package/src/capabilities/tests/basic/index.js +0 -20
  102. package/src/capabilities/tests/basic/ui5.html +0 -24
  103. package/src/capabilities/tests/dynamic-include/index.js +0 -21
  104. package/src/capabilities/tests/dynamic-include/mix.html +0 -11
  105. package/src/capabilities/tests/dynamic-include/one.html +0 -11
  106. package/src/capabilities/tests/dynamic-include/post.js +0 -3
  107. package/src/capabilities/tests/dynamic-include/test.js +0 -1
  108. package/src/capabilities/tests/dynamic-include/two.html +0 -11
  109. package/src/capabilities/tests/index.js +0 -16
  110. package/src/capabilities/tests/local-storage/index.html +0 -16
  111. package/src/capabilities/tests/local-storage/index.js +0 -21
  112. package/src/capabilities/tests/screenshot/index.html +0 -23
  113. package/src/capabilities/tests/screenshot/index.js +0 -24
  114. package/src/capabilities/tests/scripts/coverage.html +0 -32
  115. package/src/capabilities/tests/scripts/iframe.html +0 -18
  116. package/src/capabilities/tests/scripts/index.js +0 -59
  117. package/src/capabilities/tests/scripts/qunit.html +0 -22
  118. package/src/capabilities/tests/scripts/testsuite.html +0 -10
  119. package/src/capabilities/tests/scripts/testsuite.js +0 -8
  120. package/src/capabilities/tests/timeout/index.html +0 -21
  121. package/src/capabilities/tests/timeout/index.js +0 -19
  122. package/src/capabilities/tests/traces/index.html +0 -18
  123. package/src/capabilities/tests/traces/index.js +0 -81
  124. package/src/capabilities/tests/ui5/focus.html +0 -89
  125. package/src/capabilities/tests/ui5/index.js +0 -39
  126. package/src/capabilities/tests/ui5/language.html +0 -50
  127. package/src/capabilities/tests/ui5/timezone.html +0 -27
  128. package/src/clean.js +0 -22
  129. package/src/cors.js +0 -21
  130. package/src/coverage.js +0 -384
  131. package/src/csv-reader.js +0 -36
  132. package/src/csv-writer.js +0 -55
  133. package/src/defaults/.nycrc.json +0 -4
  134. package/src/defaults/browser.js +0 -217
  135. package/src/defaults/happy-dom.js +0 -123
  136. package/src/defaults/jsdom/compatibility.js +0 -163
  137. package/src/defaults/jsdom/debug.js +0 -23
  138. package/src/defaults/jsdom/resource-loader.js +0 -44
  139. package/src/defaults/jsdom/sap.ui.test.matchers.visible.js +0 -39
  140. package/src/defaults/jsdom.js +0 -95
  141. package/src/defaults/json-report.js +0 -36
  142. package/src/defaults/junit-xml-report.js +0 -90
  143. package/src/defaults/playwright.js +0 -142
  144. package/src/defaults/puppeteer.js +0 -124
  145. package/src/defaults/report/common.js +0 -38
  146. package/src/defaults/report/decompress.js +0 -19
  147. package/src/defaults/report/default.html +0 -99
  148. package/src/defaults/report/main.js +0 -69
  149. package/src/defaults/report/progress.js +0 -60
  150. package/src/defaults/report/styles.css +0 -66
  151. package/src/defaults/report.js +0 -91
  152. package/src/defaults/scan-ui5.js +0 -26
  153. package/src/defaults/selenium-webdriver/chrome.js +0 -39
  154. package/src/defaults/selenium-webdriver/edge.js +0 -24
  155. package/src/defaults/selenium-webdriver/firefox.js +0 -30
  156. package/src/defaults/selenium-webdriver.js +0 -129
  157. package/src/defaults/text-report.js +0 -108
  158. package/src/defaults/webdriverio.js +0 -80
  159. package/src/end.js +0 -62
  160. package/src/endpoints.js +0 -219
  161. package/src/error.js +0 -54
  162. package/src/get-job-progress.js +0 -78
  163. package/src/handle.js +0 -43
  164. package/src/if.js +0 -10
  165. package/src/inject/jest2qunit.js +0 -289
  166. package/src/inject/opa-iframe-coverage.js +0 -22
  167. package/src/inject/post.js +0 -141
  168. package/src/inject/qunit-hooks.js +0 -107
  169. package/src/inject/qunit-redirect.js +0 -65
  170. package/src/inject/ui5-coverage.js +0 -33
  171. package/src/job-mode.js +0 -65
  172. package/src/job.js +0 -493
  173. package/src/npm.js +0 -136
  174. package/src/options.js +0 -95
  175. package/src/output.js +0 -739
  176. package/src/parallelize.js +0 -63
  177. package/src/qunit-hooks.js +0 -219
  178. package/src/report.js +0 -89
  179. package/src/reserve.js +0 -25
  180. package/src/start.js +0 -129
  181. package/src/symbols.js +0 -8
  182. package/src/tests.js +0 -183
  183. package/src/timeout.js +0 -53
  184. package/src/tools.js +0 -179
  185. package/src/ui5.js +0 -199
  186. 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
- }