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.
- 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 +20 -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 -133
- 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/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
|
-
}
|