ui5-test-runner 5.13.1 → 6.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +20 -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 -133
  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/tests.js DELETED
@@ -1,183 +0,0 @@
1
- 'use strict'
2
-
3
- const { start } = require('./browsers')
4
- const { instrument } = require('./coverage')
5
- const { globallyTimedOut } = require('./timeout')
6
- const { save, generate } = require('./report')
7
- const { getOutput } = require('./output')
8
- const {
9
- $statusProgressTotal,
10
- $statusProgressCount,
11
- $proxifiedUrls
12
- } = require('./symbols')
13
- const { UTRError } = require('./error')
14
- const { parallelize } = require('./parallelize')
15
-
16
- function task (job, method) {
17
- return async (url, index, { length }) => {
18
- if (job[$statusProgressCount] === undefined) {
19
- job[$statusProgressCount] = 0
20
- }
21
- job[$statusProgressTotal] = length
22
- const output = getOutput(job)
23
- if (globallyTimedOut(job)) {
24
- output.globalTimeout(url)
25
- job.failed = true
26
- job.timedOut = true
27
- } else if (job.failFast && job.failed) {
28
- output.failFast(url)
29
- } else {
30
- try {
31
- await method(job, url)
32
- } catch (error) {
33
- job.failed = true
34
- }
35
- }
36
- ++job[$statusProgressCount]
37
- }
38
- }
39
-
40
- async function probeUrl (job, url) {
41
- const parsedUrl = new URL(url)
42
- if (parsedUrl.port === '0') {
43
- parsedUrl.port = job.port
44
- url = parsedUrl.toString()
45
- }
46
- const output = getOutput(job)
47
- try {
48
- let scripts
49
- if (job.browserCapabilities.scripts) {
50
- scripts = [
51
- '(function () { window[\'ui5-test-runner/probe\'] = true }())',
52
- 'post.js',
53
- 'qunit-redirect.js'
54
- ]
55
- if (job.jest) {
56
- scripts.push('jest2qunit.js')
57
- }
58
- }
59
- await start(job, url, scripts)
60
- } catch (error) {
61
- output.startFailed(url, error)
62
- throw error
63
- }
64
- }
65
-
66
- async function runTestPage (job, url) {
67
- const output = getOutput(job)
68
- try {
69
- let scripts
70
- if (job.browserCapabilities.scripts) {
71
- scripts = []
72
- if (job.qunitBatchSize) {
73
- scripts.push(
74
- `(function () { window['ui5-test-runner/batch'] = ${job.qunitBatchSize} }())`
75
- )
76
- }
77
- scripts.push(
78
- 'post.js',
79
- 'qunit-hooks.js'
80
- )
81
- if (job.jest) {
82
- scripts.push('jest2qunit.js')
83
- }
84
- if (job.coverage && !job.coverageProxy) {
85
- scripts.push(
86
- 'opa-iframe-coverage.js',
87
- 'ui5-coverage.js' // TODO detect if middleware exists before injecting this
88
- )
89
- }
90
- }
91
- if (job.coverageProxy) {
92
- const { origin } = new URL(url)
93
- const proxifiedUrl = url.replace(origin, `http://localhost:${job.port}`)
94
- if (!job[$proxifiedUrls]) {
95
- job[$proxifiedUrls] = {}
96
- }
97
- job[$proxifiedUrls][proxifiedUrl] = url
98
- await start(job, proxifiedUrl, scripts)
99
- job.qunitPages[url] = job.qunitPages[proxifiedUrl]
100
- delete job.qunitPages[proxifiedUrl]
101
- } else {
102
- await start(job, url, scripts)
103
- }
104
- } catch (error) {
105
- output.startFailed(url, error)
106
- throw error
107
- }
108
- }
109
-
110
- async function process (job) {
111
- const output = getOutput(job)
112
- job.start = new Date()
113
- job.failed = false
114
- await instrument(job)
115
- await save(job)
116
- job.testPageUrls = []
117
-
118
- let probingRound = 0
119
- const parallel = job.probeParallel || job.parallel
120
- const confirmedTestPageUrls = []
121
- job.status = 'Probing urls'
122
- do {
123
- ++probingRound
124
- if (probingRound >= 2) {
125
- if (job.testPageUrls.length === 0) {
126
- break
127
- }
128
- job.status = `Probing urls (${probingRound})`
129
- job.url = job.testPageUrls.filter(url => !confirmedTestPageUrls.includes(url))
130
- if (job.url.length) {
131
- job.testPageUrls = []
132
- } else {
133
- job.testPageUrls = confirmedTestPageUrls
134
- break
135
- }
136
- }
137
- try {
138
- await parallelize(task(job, probeUrl), job.url, parallel)
139
- } catch (e) {
140
- output.genericError(e)
141
- job.failed = true
142
- break
143
- }
144
- job.testPageUrls.forEach(url => {
145
- if ((job.url.includes(url) && !confirmedTestPageUrls.includes(url)) ||
146
- (url.includes('/resources/sap/ui/test/starter/Test.qunit.html?testsuite=') && url.includes('&test='))
147
- ) {
148
- confirmedTestPageUrls.push(url)
149
- getOutput(job).debug('probe', 'confirmed:', url)
150
- }
151
- })
152
- getOutput(job).debug('probe', 'from', job.url.length, 'to', job.testPageUrls.length, 'confirmed', confirmedTestPageUrls.length)
153
- } while (job.deepProbe)
154
-
155
- /* istanbul ignore else */
156
- if (!job.debugProbeOnly && !job.failed) {
157
- if (job.testPageUrls.length !== 0) {
158
- job.status = 'Executing test pages'
159
- try {
160
- await parallelize(task(job, runTestPage), job.testPageUrls, job.parallel)
161
- } catch (e) {
162
- output.genericError(e)
163
- job.failed = true
164
- }
165
- } else if (Object.keys(job.qunitPages || []).length === 0) {
166
- output.noTestPageFound()
167
- job.failed = true
168
- }
169
- }
170
-
171
- await generate(job)
172
- }
173
-
174
- module.exports = {
175
- async execute (job) {
176
- if (job.mode !== 'url') {
177
- job.url = [`http://${job.localhost}:${job.port}/${job.testsuite}`]
178
- } else if (!job.browserCapabilities.scripts) {
179
- throw UTRError.BROWSER_MISS_SCRIPTS_CAPABILITY()
180
- }
181
- return process(job)
182
- }
183
- }
package/src/timeout.js DELETED
@@ -1,53 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = {
4
- getPageTimeout (job) {
5
- if (job.pageTimeout || job.globalTimeout) {
6
- if (job.globalTimeout) {
7
- return Math.min(job.globalTimeout - (new Date() - job.start), job.pageTimeout || Number.MAX_SAFE_INTEGER)
8
- }
9
- return job.pageTimeout
10
- }
11
- return 0
12
- },
13
-
14
- globallyTimedOut (job) {
15
- if (job.globalTimeout) {
16
- return new Date() - job.start > job.globalTimeout
17
- }
18
- return false
19
- },
20
-
21
- pageTimedOut (job, url) {
22
- const page = job.qunitPages && job.qunitPages[url]
23
- if (page) {
24
- const now = new Date()
25
- page.end = now
26
- page.timedOut = true
27
- page.modules.forEach(module => {
28
- module.tests.forEach(test => {
29
- if (!test.report) {
30
- ++page.failed
31
- if (test.start && !test.end) {
32
- test.end = now
33
- }
34
- test.logs ??= []
35
- test.logs.push({
36
- result: false,
37
- message: 'Page timed out'
38
- })
39
- test.report = {
40
- skipped: false,
41
- todo: false,
42
- failed: 1,
43
- passed: 0,
44
- total: 1
45
- }
46
- }
47
- })
48
- })
49
- }
50
- job.failed = true
51
- job.timedOut = true
52
- }
53
- }
package/src/tools.js DELETED
@@ -1,179 +0,0 @@
1
- 'use strict'
2
-
3
- const { dirname } = require('path')
4
- const { mkdir, rm, stat } = require('fs').promises
5
- const { createHash } = require('crypto')
6
- const { createWriteStream } = require('fs')
7
- const http = require('http')
8
- const https = require('https')
9
- const { unlink } = require('fs/promises')
10
-
11
- const recursive = { recursive: true }
12
-
13
- const stripUrlHash = url => url.split('#')[0]
14
-
15
- const filename = url => {
16
- const hash = createHash('shake256', {
17
- outputLength: 8
18
- })
19
- hash.update(stripUrlHash(url))
20
- return hash.digest('base64')
21
- .replace(/=/g, '')
22
- .replace(/\+/g, '_')
23
- .replace(/\//g, '$')
24
- }
25
-
26
- const cleanDir = async dir => {
27
- try {
28
- await stat(dir)
29
- await rm(dir, recursive)
30
- } catch (err) {
31
- // Ignore
32
- }
33
- }
34
-
35
- const $op = Symbol('pad.op')
36
- const $x = Symbol('pad.x')
37
- const $lt = Symbol('pad.lt')
38
- const $w = Symbol('pad.w')
39
- function pad (width) {
40
- if (!width) {
41
- width = process.stdout.columns || 80
42
- }
43
- const ops = {
44
- [$x] (widthLeft) {
45
- return ''.padStart(widthLeft, this.text)
46
- },
47
- [$lt] (widthLeft) {
48
- const { text, padding } = this
49
- if (text.length <= widthLeft) {
50
- return text.padEnd(widthLeft, padding)
51
- }
52
- return '...' + text.substring(text.length - widthLeft + 3)
53
- },
54
- [$w] (widthLeft, result, opIndex) {
55
- const { text } = this
56
- if (text.length < widthLeft && !text.includes('\n')) {
57
- return text.padEnd(widthLeft, ' ')
58
- }
59
- const lines = []
60
- text.split(/\r?\n/).forEach(line => {
61
- if (line.length <= widthLeft) {
62
- lines.push(line.padEnd(widthLeft, ' '))
63
- } else {
64
- for (let offset = 0; offset < line.length; offset += widthLeft - 1) {
65
- const part = line.slice(offset, offset + widthLeft - 1)
66
- if (part.length < widthLeft - 1) {
67
- lines.push(part.padEnd(widthLeft, ' '))
68
- } else {
69
- lines.push(`${part}↵`)
70
- }
71
- }
72
- }
73
- })
74
- const before = result.slice(0, opIndex).join('')
75
- const after = result.slice(opIndex + 1).join('')
76
- return lines.join(after + '\n' + before)
77
- }
78
- }
79
- return (strings, ...values) => {
80
- const result = []
81
- let op
82
- let opIndex
83
- const length = strings.reduce((total, string, index) => {
84
- result.push(string)
85
- total += string.length
86
- let value = values[index]
87
- if (value === null || value === undefined) {
88
- return total
89
- }
90
- if (value[$op]) {
91
- if (opIndex !== undefined) {
92
- throw new Error('Only one operator is allowed')
93
- }
94
- op = value
95
- opIndex = result.length
96
- result.push(value)
97
- } else {
98
- if (typeof value !== 'string') {
99
- value = value.toString()
100
- }
101
- result.push(value)
102
- total += value.length
103
- }
104
- return total
105
- }, 0)
106
- if (op !== undefined) {
107
- const widthLeft = width - length
108
- result[opIndex] = ops[op[$op]].call(op, widthLeft, result, opIndex)
109
- }
110
- return result.join('')
111
- }
112
- }
113
-
114
- pad.x = (text) => ({ [$op]: $x, text })
115
- pad.lt = (text, padding = ' ') => ({ [$op]: $lt, text, padding })
116
- pad.w = (text) => ({ [$op]: $w, text })
117
-
118
- function allocPromise () {
119
- let resolve
120
- let reject
121
- const promise = new Promise((_resolve, _reject) => {
122
- resolve = _resolve
123
- reject = _reject
124
- })
125
- return { promise, resolve, reject }
126
- }
127
-
128
- async function download (url, filename) {
129
- const { hostname, port, origin } = new URL(url)
130
- const error = reason => new Error(`Error downloading ${url} to ${filename}, ${reason}`)
131
- const options = {
132
- hostname,
133
- port,
134
- path: url.substring(origin.length),
135
- method: 'GET'
136
- }
137
- const protocol = url.startsWith('https:') ? https : http
138
- await mkdir(dirname(filename), recursive)
139
- const output = createWriteStream(filename)
140
- const { promise, resolve, reject } = allocPromise()
141
- const request = protocol.request(options, async response => {
142
- if (response.statusCode !== 200) {
143
- reject(error(`server responded with ${response.statusCode}`))
144
- output.end()
145
- try {
146
- await unlink(filename)
147
- } catch (e) {
148
- // ignore
149
- }
150
- return
151
- }
152
- response.on('error', reason => {
153
- reject(error(`response failed : ${reason.toString()}`))
154
- })
155
- response
156
- .pipe(output)
157
- .on('finish', () => {
158
- resolve(filename)
159
- })
160
- })
161
- request.on('error', reason => {
162
- reject(error(`request failed : ${reason.toString()}`))
163
- })
164
- request.end()
165
- return promise
166
- }
167
-
168
- module.exports = {
169
- stripUrlHash,
170
- filename,
171
- cleanDir,
172
- createDir: dir => mkdir(dir, recursive),
173
- recreateDir: dir => cleanDir(dir).then(() => mkdir(dir, recursive)),
174
- extractPageUrl: headers => headers['x-page-url'],
175
- allocPromise,
176
- noop () {},
177
- pad,
178
- download
179
- }
package/src/ui5.js DELETED
@@ -1,199 +0,0 @@
1
- 'use strict'
2
-
3
- const { dirname, join } = require('path')
4
- const { createWriteStream } = require('fs')
5
- const { mkdir, unlink, stat } = require('fs').promises
6
- const { capture } = require('reserve')
7
- const { getOutput, newProgress } = require('./output')
8
- const { download } = require('./tools')
9
- const { $statusProgressCount, $statusProgressTotal } = require('./symbols')
10
- const { parallelize } = require('./parallelize')
11
- const { relative: relativePath } = require('path')
12
-
13
- const buildCacheBase = job => {
14
- const [, hostName] = /https?:\/\/([^/]*)/.exec(job.ui5)
15
- const [, version] = /(\d+\.\d+\.\d+)?$/.exec(job.ui5)
16
- return join(job.cache || '', hostName.replace(':', '_'), version || '')
17
- }
18
-
19
- const ui5mappings = async job => {
20
- const output = getOutput(job)
21
- const cacheBase = buildCacheBase(job)
22
- const match = /\/((?:test-)?resources\/.*)/ // Captured value never starts with /
23
- const ifCacheEnabled = () => job.cache
24
- const uncachable = {}
25
- const cachingInProgress = {}
26
-
27
- let { ui5 } = job
28
- if (!ui5.endsWith('/')) {
29
- ui5 += '/'
30
- }
31
- const mappingUrl = new URL('$1', ui5).toString()
32
-
33
- const inJest = typeof jest !== 'undefined'
34
- /* istanbul ignore next */
35
- if (!inJest) {
36
- const versionUrl = mappingUrl.replace('$1', 'resources/sap-ui-version.json')
37
- const versionResponse = await fetch(versionUrl)
38
- if (versionResponse.status !== 200) {
39
- output.log('Unable to fetch UI5 version: ' + versionResponse.status + ' ' + versionResponse.statusText)
40
- throw new Error('Unable to fetch UI5 version')
41
- }
42
- const version = await versionResponse.json()
43
- const { version: coreVersion } = version.libraries.find(({ name }) => name === 'sap.ui.core')
44
- output.log('UI5 version used by the local server: ' + coreVersion)
45
- }
46
-
47
- const mappings = [{
48
- /* Prevent caching issues :
49
- * - Caching was not possible (99% URL does not exist)
50
- * - Caching is in progress (must wait for the end of the writing stream)
51
- */
52
- match,
53
- 'if-match': ifCacheEnabled,
54
- custom: async (request, response, path) => {
55
- if (uncachable[path]) {
56
- response.writeHead(404)
57
- response.end()
58
- return
59
- }
60
- const cachingPromise = cachingInProgress[path]
61
- /* istanbul ignore next */ // Hard to reproduce
62
- if (cachingPromise) {
63
- await cachingPromise
64
- }
65
- }
66
- }, { // UI5 from cache
67
- match,
68
- 'if-match': ifCacheEnabled,
69
- cwd: cacheBase,
70
- file: '$1',
71
- static: !job.debugDevMode
72
- }, { // UI5 caching
73
- method: 'GET',
74
- match,
75
- 'if-match': ifCacheEnabled,
76
- custom: async (request, response, path) => {
77
- const filePath = /([^?#]+)/.exec(unescape(path))[1] // filter URL parameters & hash (assuming resources are static)
78
- const cachePath = join(cacheBase, filePath)
79
- const cacheFolder = dirname(cachePath)
80
- await mkdir(cacheFolder, { recursive: true })
81
- if (cachingInProgress[path]) {
82
- return request.url // loop back to use cached result
83
- }
84
- const file = createWriteStream(cachePath)
85
- cachingInProgress[path] = capture(response, file)
86
- .catch(reason => {
87
- file.end()
88
- uncachable[path] = true
89
- if (response.statusCode !== 404) {
90
- output.failedToCacheUI5resource(path, response.statusCode)
91
- }
92
- return unlink(cachePath)
93
- })
94
- .then(() => {
95
- delete cachingInProgress[path]
96
- })
97
- }
98
- }, { // UI5 from url
99
- method: ['GET', 'HEAD'],
100
- match,
101
- url: mappingUrl,
102
- 'ignore-unverifiable-certificate': true
103
- }]
104
-
105
- for (let { relative, source } of job.libs) {
106
- if (source.endsWith('/') || source.endsWith('\\')) {
107
- source = source.substring(0, source.length - 1)
108
- }
109
- const relativeUrl = relative.replace(/\//g, '\\/')
110
- if (source.startsWith(job.webapp)) {
111
- if (relative === '*') {
112
- // Special handling to support webapp/resources folder (/!\ coverage won't be extracted for those files)
113
- output.debug('libs', '* map to webapp sub directory (expected resources), use file access')
114
- mappings.unshift({
115
- match: /\/resources\/(.*)/,
116
- cwd: source,
117
- file: '$1',
118
- static: !job.watch && !job.debugDevMode
119
- })
120
- } else {
121
- // Use redirection to support local coverage instrumentation
122
- const relativeAbsoluteUrl = '/' + relativePath(job.webapp, source).replace(/\\/g, '/')
123
- output.debug('libs', `${relative} maps to webapp sub directory, use internal redirection to ${relativeAbsoluteUrl}`)
124
- mappings.unshift({
125
- match: new RegExp(`\\/resources\\/${relativeUrl}(.*)`),
126
- custom: (request, response, $1) => `${relativeAbsoluteUrl}${$1}`
127
- })
128
- }
129
- } else {
130
- mappings.unshift({
131
- match: new RegExp(`\\/resources\\/${relativeUrl}(.*)`),
132
- cwd: source,
133
- file: '$1',
134
- static: !job.watch && !job.debugDevMode
135
- }, {
136
- match: new RegExp(`\\/resources\\/${relativeUrl}(.*)`),
137
- custom: (request, response, $1) => {
138
- if ($1 === undefined) {
139
- output.debug('libs', `Unable to map ${relative} : $1 is undefined`)
140
- } else {
141
- output.debug('libs', `Unable to map ${relative}/${$1} to ${join(source, $1)}`)
142
- }
143
- return 404
144
- }
145
- })
146
- }
147
- }
148
-
149
- return mappings
150
- }
151
-
152
- module.exports = {
153
- preload: async job => {
154
- const cacheBase = buildCacheBase(job)
155
-
156
- const get = async (path, expectedSize) => {
157
- const filePath = join(cacheBase, 'resources/' + path)
158
- try {
159
- const info = await stat(filePath)
160
- if (expectedSize !== undefined && info.isFile() && info.size === expectedSize) {
161
- return filePath
162
- }
163
- } catch (e) {
164
- // ignore
165
- }
166
- return download((new URL('resources/' + path, job.ui5)).toString(), filePath)
167
- }
168
-
169
- const lib = async name => {
170
- progress.label = name
171
- progress.count = 0
172
- const libPath = name.replace(/\./g, '/') + '/'
173
- const { resources } = require(await get(libPath + 'resources.json'))
174
- progress.total = resources.length
175
- progress.label = `${name} (${resources.length} files)`
176
- await parallelize(async ({ name, size }) => {
177
- await get(libPath + name, size)
178
- ++progress.count
179
- }, resources, 8)
180
- ++job[$statusProgressCount]
181
- }
182
-
183
- job.status = 'Preloading UI5'
184
- job[$statusProgressCount] = 0
185
- job[$statusProgressTotal] = job.preload.length + 1
186
- await get('sap-ui-version.json')
187
- await get('sap-ui-core.js')
188
- const progress = newProgress(job)
189
- await parallelize(lib, ['sap.ui.core', ...job.preload], 1)
190
- progress.done()
191
- },
192
-
193
- mappings: async job => {
194
- if (job.disableUi5) {
195
- return []
196
- }
197
- return ui5mappings(job)
198
- }
199
- }
package/src/unhandled.js DELETED
@@ -1,32 +0,0 @@
1
- 'use strict'
2
-
3
- const { extractPageUrl, noop } = require('./tools')
4
- const { join } = require('path')
5
- const { writeFile } = require('fs')
6
- const { getOutput } = require('./output')
7
-
8
- module.exports = job => {
9
- const unhandled = join(job.reportDir, 'unhandled.txt')
10
- let outputUnhandled = true
11
- return [{
12
- custom: ({ headers, method, url }) => {
13
- if (method === 'GET' && url.match(/favicon\.ico$|-preload\.js$|-dbg(\.[^.]+)*\.js$|i18n_\w+\.properties$/)) {
14
- return 404 // expected
15
- }
16
- let status
17
- if (method === 'GET') {
18
- status = 404
19
- } else {
20
- status = 500
21
- }
22
- if (outputUnhandled) {
23
- getOutput(job).unhandled()
24
- outputUnhandled = false
25
- }
26
- writeFile(unhandled, `${extractPageUrl(headers) || headers.referer} ${status} ${method} ${url}\n`, {
27
- flag: 'a'
28
- }, noop)
29
- return status
30
- }
31
- }]
32
- }