ui5-test-runner 5.7.1 → 5.7.3
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/index.js +15 -3
- package/package.json +10 -8
- package/src/capabilities/index.js +7 -1
- package/src/capabilities/tests/basic/index.js +0 -2
- package/src/capabilities/tests/basic/ui5.html +1 -1
- package/src/clean.js +29 -0
- package/src/defaults/happy-dom.js +123 -0
- package/src/defaults/jsdom/compatibility.js +2 -2
- package/src/defaults/jsdom.js +6 -0
- package/src/defaults/report/default.html +2 -0
- package/src/job.js +1 -1
- package/src/npm.js +35 -9
- package/src/output.js +48 -3
- package/src/report.js +8 -0
package/index.js
CHANGED
|
@@ -16,6 +16,8 @@ const { start } = require('./src/start')
|
|
|
16
16
|
const { executeIf } = require('./src/if')
|
|
17
17
|
const { batch } = require('./src/batch')
|
|
18
18
|
const { end } = require('./src/end')
|
|
19
|
+
const { checkLatest } = require('./src/npm')
|
|
20
|
+
const { cleanHandles } = require('./src/clean')
|
|
19
21
|
|
|
20
22
|
function send (message) {
|
|
21
23
|
if (process.send) {
|
|
@@ -50,11 +52,12 @@ async function main () {
|
|
|
50
52
|
job = fromCmdLine(process.cwd(), process.argv.slice(2))
|
|
51
53
|
output = getOutput(job)
|
|
52
54
|
await recreateDir(job.reportDir)
|
|
53
|
-
output.version()
|
|
55
|
+
const { name, version } = output.version()
|
|
54
56
|
if (job.batchMode) {
|
|
55
57
|
output.batchMode()
|
|
56
58
|
}
|
|
57
59
|
output.reportOnJobProgress()
|
|
60
|
+
checkLatest(job, name, version)
|
|
58
61
|
if (job.mode === 'capabilities') {
|
|
59
62
|
return capabilities(job)
|
|
60
63
|
}
|
|
@@ -82,7 +85,10 @@ async function main () {
|
|
|
82
85
|
output.debug('reserve', 'configuration', configuration)
|
|
83
86
|
const server = serve(configuration)
|
|
84
87
|
if (job.logServer) {
|
|
85
|
-
server
|
|
88
|
+
server
|
|
89
|
+
.on('incoming', output.logServerIncoming)
|
|
90
|
+
.on('redirected', output.logServerRedirected)
|
|
91
|
+
.on('closed', output.logServerClosed)
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
const { promise: serverStarted, resolve: serverReady, reject: serverError } = allocPromise()
|
|
@@ -145,10 +151,16 @@ async function main () {
|
|
|
145
151
|
await end(job)
|
|
146
152
|
}
|
|
147
153
|
output.stop()
|
|
148
|
-
await server.close()
|
|
154
|
+
await server.close({ close: true })
|
|
155
|
+
await new Promise(resolve => setTimeout(resolve, 100)) // wait for server handles to be released
|
|
156
|
+
if (job.logServer) {
|
|
157
|
+
output.logServerSummary()
|
|
158
|
+
}
|
|
149
159
|
if (startedCommand) {
|
|
150
160
|
await startedCommand.stop()
|
|
151
161
|
}
|
|
162
|
+
output.debug('main', 'terminated')
|
|
163
|
+
cleanHandles(job)
|
|
152
164
|
}
|
|
153
165
|
|
|
154
166
|
main()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui5-test-runner",
|
|
3
|
-
"version": "5.7.
|
|
3
|
+
"version": "5.7.3",
|
|
4
4
|
"description": "Standalone test runner for UI5",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"test:report": "node ./src/defaults/report.js ./test/report && reserve --config ./test/report/reserve.json",
|
|
23
23
|
"test:text-report": "node ./src/defaults/text-report.js ./test/report",
|
|
24
24
|
"build:doc": "node build/doc",
|
|
25
|
-
"clean": "npm uninstall -g ui5-test-runner puppeteer nyc selenium-webdriver playwright webdriverio jsdom"
|
|
25
|
+
"clean": "npm uninstall -g ui5-test-runner puppeteer nyc selenium-webdriver playwright webdriverio jsdom",
|
|
26
|
+
"update": "ncu -i --format group"
|
|
26
27
|
},
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|
|
@@ -47,21 +48,22 @@
|
|
|
47
48
|
"commander": "^12.1.0",
|
|
48
49
|
"ps-tree": "^1.2.0",
|
|
49
50
|
"punybind": "^1.2.1",
|
|
50
|
-
"punyexpr": "1.
|
|
51
|
-
"reserve": "2.
|
|
51
|
+
"punyexpr": "1.1.1",
|
|
52
|
+
"reserve": "2.3.1"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@openui5/types": "^1.
|
|
55
|
-
"@ui5/cli": "^4.0.
|
|
55
|
+
"@openui5/types": "^1.136.0",
|
|
56
|
+
"@ui5/cli": "^4.0.18",
|
|
56
57
|
"@ui5/middleware-code-coverage": "^2.0.1",
|
|
57
58
|
"dotenv": "^16.5.0",
|
|
58
59
|
"jest": "^29.7.0",
|
|
59
|
-
"nock": "^14.0.
|
|
60
|
+
"nock": "^14.0.5",
|
|
61
|
+
"npm-check-updates": "^18.0.1",
|
|
60
62
|
"nyc": "^17.1.0",
|
|
61
63
|
"rimraf": "^6.0.1",
|
|
62
64
|
"standard": "^17.1.2",
|
|
63
65
|
"typescript": "^5.8.3",
|
|
64
|
-
"ui5-tooling-transpile": "^3.
|
|
66
|
+
"ui5-tooling-transpile": "^3.8.0"
|
|
65
67
|
},
|
|
66
68
|
"optionalDependencies": {
|
|
67
69
|
"fsevents": "^2.3.3"
|
|
@@ -81,8 +81,14 @@ async function capabilities (job) {
|
|
|
81
81
|
})
|
|
82
82
|
const server = serve(configuration)
|
|
83
83
|
if (job.logServer) {
|
|
84
|
-
server
|
|
84
|
+
server
|
|
85
|
+
.on('incoming', output.logServerIncoming)
|
|
86
|
+
.on('redirected', output.logServerRedirected)
|
|
87
|
+
.on('closed', output.logServerClosed)
|
|
85
88
|
}
|
|
89
|
+
server.on('error', (error) => {
|
|
90
|
+
output.error('REserve error:', error)
|
|
91
|
+
})
|
|
86
92
|
await new Promise(resolve => server
|
|
87
93
|
.on('ready', ({ port }) => {
|
|
88
94
|
job.port = port
|
|
@@ -7,14 +7,12 @@ module.exports = [{
|
|
|
7
7
|
url: 'basic/index.html'
|
|
8
8
|
}, {
|
|
9
9
|
label: 'Loads a UI5 example',
|
|
10
|
-
for: capabilities => !capabilities.modules.includes('jsdom'), // does not work anymore on JSDOM
|
|
11
10
|
url: 'basic/ui5.html',
|
|
12
11
|
endpoint: ({ body }) => {
|
|
13
12
|
assert.strictEqual(body['sap.m.Button'], true)
|
|
14
13
|
}
|
|
15
14
|
}, {
|
|
16
15
|
label: 'Loads a UI5 inside an iframe',
|
|
17
|
-
for: capabilities => !capabilities.modules.includes('jsdom'), // does not work anymore on JSDOM
|
|
18
16
|
url: 'basic/iframe.html',
|
|
19
17
|
endpoint: ({ body }) => {
|
|
20
18
|
assert.strictEqual(body['sap.m.Button'], true)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
sap.ui.getCore().attachInit(function() {
|
|
15
15
|
const xhr = new XMLHttpRequest()
|
|
16
16
|
xhr.open('POST', '/_/log')
|
|
17
|
-
if (parent !== window) {
|
|
17
|
+
if (parent !== window && parent.document.location.toString() !== 'about:blank') {
|
|
18
18
|
xhr.setRequestHeader('x-page-url', parent.document.location.toString())
|
|
19
19
|
}
|
|
20
20
|
xhr.send('{"sap.m.Button":' + !!sap.m.Button + '}')
|
package/src/clean.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { getOutput } = require('./output')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
cleanHandles (job) {
|
|
5
|
+
const output = getOutput(job)
|
|
6
|
+
const activeHandles = process._getActiveHandles ? process._getActiveHandles() : []
|
|
7
|
+
let displayWarning = true
|
|
8
|
+
for (const handle of activeHandles) {
|
|
9
|
+
const className = handle && handle.constructor && handle.constructor.name
|
|
10
|
+
output.debug('handle', 'active handle', className)
|
|
11
|
+
if (className === 'TLSSocket') {
|
|
12
|
+
if (displayWarning) {
|
|
13
|
+
displayWarning = false
|
|
14
|
+
output.detectedLeakOfHandles()
|
|
15
|
+
}
|
|
16
|
+
let info
|
|
17
|
+
if (handle._httpMessage) {
|
|
18
|
+
const { path, method, host, protocol } = handle._httpMessage
|
|
19
|
+
info = `${method} ${protocol}//${host}${path}`
|
|
20
|
+
} else {
|
|
21
|
+
const { localAddress, localPort, remoteAddress, remotePort } = handle
|
|
22
|
+
info = `from ${localAddress}:${localPort} to ${remoteAddress}:${remotePort}`
|
|
23
|
+
}
|
|
24
|
+
output.debug('handle', 'TLS socket', info)
|
|
25
|
+
handle.destroy()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = (attributes) => {
|
|
4
|
+
console.log(JSON.stringify(attributes, (key, value) => {
|
|
5
|
+
if (key === 'headers' && typeof value === 'object') {
|
|
6
|
+
const literal = {}
|
|
7
|
+
value.forEach((headerValue, headerName) => {
|
|
8
|
+
literal[headerName] = headerValue
|
|
9
|
+
})
|
|
10
|
+
return literal
|
|
11
|
+
}
|
|
12
|
+
return value
|
|
13
|
+
}, 2))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
require('./browser')({
|
|
17
|
+
metadata: {
|
|
18
|
+
name: 'happy-dom',
|
|
19
|
+
options: [
|
|
20
|
+
['--debug [flag]', 'Enable more traces', false]
|
|
21
|
+
],
|
|
22
|
+
capabilities: {
|
|
23
|
+
modules: ['happy-dom'],
|
|
24
|
+
scripts: true,
|
|
25
|
+
traces: ['multiplex']
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
async run ({
|
|
30
|
+
settings: { url, scripts, modules }
|
|
31
|
+
// options
|
|
32
|
+
}) {
|
|
33
|
+
const happyDom = require(modules['happy-dom'])
|
|
34
|
+
const { Browser } = happyDom
|
|
35
|
+
const browser = new Browser({
|
|
36
|
+
settings: {
|
|
37
|
+
fetch: {
|
|
38
|
+
interceptor: {
|
|
39
|
+
beforeAsyncRequest: async ({ request: { method, url, headers } }) => {
|
|
40
|
+
log({
|
|
41
|
+
timestamp: new Date().toISOString(),
|
|
42
|
+
channel: 'network',
|
|
43
|
+
type: 'request',
|
|
44
|
+
async: true,
|
|
45
|
+
request: { method, url, headers }
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
beforeSyncRequest: ({ request: { method, url, headers } }) => {
|
|
49
|
+
log({
|
|
50
|
+
timestamp: new Date().toISOString(),
|
|
51
|
+
channel: 'network',
|
|
52
|
+
type: 'request',
|
|
53
|
+
async: false,
|
|
54
|
+
request: { method, url, headers }
|
|
55
|
+
})
|
|
56
|
+
},
|
|
57
|
+
afterAsyncResponse: async ({ request: { method, url, headers }, response, window }) => {
|
|
58
|
+
const body = await response.text()
|
|
59
|
+
log({
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
channel: 'network',
|
|
62
|
+
type: 'response',
|
|
63
|
+
async: true,
|
|
64
|
+
request: { method, url, headers },
|
|
65
|
+
response: {
|
|
66
|
+
...response,
|
|
67
|
+
body
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
return new window.Response(body, {
|
|
71
|
+
status: response.status,
|
|
72
|
+
statusText: response.statusText,
|
|
73
|
+
headers: response.headers
|
|
74
|
+
})
|
|
75
|
+
},
|
|
76
|
+
afterSyncResponse: ({ request: { method, url, headers }, response }) => {
|
|
77
|
+
log({
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
channel: 'network',
|
|
80
|
+
type: 'response',
|
|
81
|
+
async: false,
|
|
82
|
+
request: { method, url, headers },
|
|
83
|
+
response: {
|
|
84
|
+
...response,
|
|
85
|
+
body: response.body.toString('utf8')
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
console: {
|
|
93
|
+
error: (...args) => log({
|
|
94
|
+
timestamp: new Date().toISOString(),
|
|
95
|
+
channel: 'console',
|
|
96
|
+
type: 'error',
|
|
97
|
+
message: args.join(' ')
|
|
98
|
+
}),
|
|
99
|
+
warn: (...args) => log({
|
|
100
|
+
timestamp: new Date().toISOString(),
|
|
101
|
+
channel: 'console',
|
|
102
|
+
type: 'warning',
|
|
103
|
+
message: args.join(' ')
|
|
104
|
+
}),
|
|
105
|
+
info: (...args) => log({
|
|
106
|
+
timestamp: new Date().toISOString(),
|
|
107
|
+
channel: 'console',
|
|
108
|
+
type: 'info',
|
|
109
|
+
message: args.join(' ')
|
|
110
|
+
}),
|
|
111
|
+
log: (...args) => log({
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
channel: 'console',
|
|
114
|
+
type: 'log',
|
|
115
|
+
message: args.join(' ')
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
const page = browser.newPage()
|
|
120
|
+
scripts.forEach(script => page.mainFrame.window.eval(script))
|
|
121
|
+
page.goto(url)
|
|
122
|
+
}
|
|
123
|
+
})
|
|
@@ -115,8 +115,8 @@ function fixCaseSensitiveSelectors ({ Document }) {
|
|
|
115
115
|
const { querySelector, querySelectorAll } = Document.prototype
|
|
116
116
|
Object.assign(Document.prototype, {
|
|
117
117
|
querySelector (selectors) {
|
|
118
|
-
const result = querySelector.call(this, selectors)
|
|
119
|
-
if (result
|
|
118
|
+
const result = querySelector.call(this, selectors)
|
|
119
|
+
if (result === null && selectors.match(uppercaseTag)) {
|
|
120
120
|
console.log(JSON.stringify({
|
|
121
121
|
timestamp: new Date().toISOString(),
|
|
122
122
|
channel: 'debug',
|
package/src/defaults/jsdom.js
CHANGED
|
@@ -23,6 +23,12 @@ require('./browser')({
|
|
|
23
23
|
const { JSDOM, VirtualConsole } = jsdom
|
|
24
24
|
|
|
25
25
|
const virtualConsole = new VirtualConsole()
|
|
26
|
+
virtualConsole.on('jsdomError', (...args) => console.log(JSON.stringify({
|
|
27
|
+
timestamp: new Date().toISOString(),
|
|
28
|
+
channel: 'console',
|
|
29
|
+
type: 'jsdomError',
|
|
30
|
+
message: args.join(' ')
|
|
31
|
+
})))
|
|
26
32
|
virtualConsole.on('error', (...args) => console.log(JSON.stringify({
|
|
27
33
|
timestamp: new Date().toISOString(),
|
|
28
34
|
channel: 'console',
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
<head>
|
|
3
3
|
<title>ui5-test-runner</title>
|
|
4
4
|
<link rel="stylesheet" href="/_/report/styles.css">
|
|
5
|
+
<script>window.module = window.module || {}</script>
|
|
5
6
|
<script src="/_/punyexpr.js"></script>
|
|
7
|
+
<script>window.punyexpr = module.exports.punyexpr</script>
|
|
6
8
|
<script src="/_/punybind.js"></script>
|
|
7
9
|
<script src="/_/report/common.js"></script>
|
|
8
10
|
<script src="/_/report/main.js"></script>
|
package/src/job.js
CHANGED
|
@@ -150,7 +150,7 @@ function getCommand (cwd) {
|
|
|
150
150
|
.option('--start-timeout <timeout>', '[💻🔗] Maximum waiting time for the start command (based on when the first URL becomes available)', timeout, 5000)
|
|
151
151
|
|
|
152
152
|
.option('--end <script>', '[💻🔗] End script (will receive path to `job.js`)', string)
|
|
153
|
-
.option('--end-timeout <timeout>', '[💻🔗] Maximum waiting time for the end script', timeout,
|
|
153
|
+
.option('--end-timeout <timeout>', '[💻🔗] Maximum waiting time for the end script', timeout, 15000)
|
|
154
154
|
|
|
155
155
|
// Specific to legacy (and might be used with url if pointing to local project)
|
|
156
156
|
.option('--ui5 <url>', '[💻📡] UI5 url', url, 'https://ui5.sap.com')
|
package/src/npm.js
CHANGED
|
@@ -73,11 +73,41 @@ async function findDependencyPath (job, name) {
|
|
|
73
73
|
return [globalPath, justInstalled]
|
|
74
74
|
}
|
|
75
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
|
+
output: {
|
|
85
|
+
debug: noop,
|
|
86
|
+
resolvedPackage: noop,
|
|
87
|
+
packageNotLatest: noop
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function checkLatest (nullableJob, name, installedVersion) {
|
|
93
|
+
const { job, output } = getSafeJobAndOutput(nullableJob)
|
|
94
|
+
if (!job.offline) {
|
|
95
|
+
output.debug('npm', `fetching latest version of package ${name}`)
|
|
96
|
+
const latestVersion = await npm(job, 'view', name, 'version')
|
|
97
|
+
if (latestVersion !== installedVersion) {
|
|
98
|
+
output.packageNotLatest(name, latestVersion)
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
output.debug('npm', `offline=${job.offline}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
76
105
|
module.exports = {
|
|
77
106
|
resolveDependencyPath,
|
|
107
|
+
checkLatest,
|
|
78
108
|
|
|
79
|
-
async resolvePackage (
|
|
80
|
-
const output =
|
|
109
|
+
async resolvePackage (nullableJob, name) {
|
|
110
|
+
const { job, output } = getSafeJobAndOutput(nullableJob)
|
|
81
111
|
let modulePath
|
|
82
112
|
let justInstalled = false
|
|
83
113
|
output.debug('npm', `resolving dependency path of package ${name}...`)
|
|
@@ -94,14 +124,10 @@ module.exports = {
|
|
|
94
124
|
const installedPackage = require(join(modulePath, 'package.json'))
|
|
95
125
|
const { version: installedVersion } = installedPackage
|
|
96
126
|
output.resolvedPackage(name, modulePath, installedVersion)
|
|
97
|
-
if (!justInstalled
|
|
98
|
-
|
|
99
|
-
const latestVersion = await npm(job, 'view', name, 'version')
|
|
100
|
-
if (latestVersion !== installedVersion) {
|
|
101
|
-
output.packageNotLatest(name, latestVersion)
|
|
102
|
-
}
|
|
127
|
+
if (!justInstalled) {
|
|
128
|
+
checkLatest(job, name, installedVersion)
|
|
103
129
|
} else {
|
|
104
|
-
output.debug('npm', `justInstalled=${justInstalled}
|
|
130
|
+
output.debug('npm', `justInstalled=${justInstalled}`)
|
|
105
131
|
}
|
|
106
132
|
return modulePath
|
|
107
133
|
}
|
package/src/output.js
CHANGED
|
@@ -15,6 +15,10 @@ const interactive = process.stdout.columns !== undefined && !inJest
|
|
|
15
15
|
const $output = Symbol('output')
|
|
16
16
|
const $outputStart = Symbol('output-start')
|
|
17
17
|
const $outputProgress = Symbol('output-progress')
|
|
18
|
+
const $logServerIncomingCount = Symbol('log-server-incoming')
|
|
19
|
+
const $logServerRedirectedCount = Symbol('log-server-redirected')
|
|
20
|
+
const $logServerClosedCount = Symbol('log-server-closed')
|
|
21
|
+
const $logServerRequests = Symbol('log-server-requests')
|
|
18
22
|
|
|
19
23
|
if (!interactive) {
|
|
20
24
|
const UTF8_BOM_CODE = '\ufeff'
|
|
@@ -270,6 +274,7 @@ function build (job) {
|
|
|
270
274
|
if (job.debugDevMode) {
|
|
271
275
|
log(job, p80()`⚠️ Development mode ⚠️`)
|
|
272
276
|
}
|
|
277
|
+
return { name, version }
|
|
273
278
|
},
|
|
274
279
|
|
|
275
280
|
serving: url => {
|
|
@@ -294,8 +299,18 @@ function build (job) {
|
|
|
294
299
|
}
|
|
295
300
|
},
|
|
296
301
|
|
|
297
|
-
|
|
298
|
-
if (url.startsWith('/_/
|
|
302
|
+
logServerIncoming: wrap(({ id, method, url }) => {
|
|
303
|
+
if (url.startsWith('/_/')) {
|
|
304
|
+
return // avoids pollution
|
|
305
|
+
}
|
|
306
|
+
job[$logServerIncomingCount] = (job[$logServerIncomingCount] || 0) + 1
|
|
307
|
+
job[$logServerRequests] ??= {}
|
|
308
|
+
job[$logServerRequests][id] = { method, url }
|
|
309
|
+
log(job, p80()`🛜 INC ${id.toString(36).toUpperCase().padStart(4, ' ')} ${method.padEnd(7, ' ')} ${pad.lt(url)}`)
|
|
310
|
+
}),
|
|
311
|
+
|
|
312
|
+
logServerRedirected: wrap(({ id, method, url, statusCode, timeSpent }) => {
|
|
313
|
+
if (url.startsWith('/_/')) {
|
|
299
314
|
return // avoids pollution
|
|
300
315
|
}
|
|
301
316
|
let statusText
|
|
@@ -304,7 +319,33 @@ function build (job) {
|
|
|
304
319
|
} else {
|
|
305
320
|
statusText = statusCode
|
|
306
321
|
}
|
|
307
|
-
|
|
322
|
+
job[$logServerRedirectedCount] = (job[$logServerRedirectedCount] || 0) + 1
|
|
323
|
+
const request = job[$logServerRequests][id]
|
|
324
|
+
request.redirected = true
|
|
325
|
+
if (request.closed) {
|
|
326
|
+
delete job[$logServerRequests][id]
|
|
327
|
+
}
|
|
328
|
+
log(job, p80()`🛜 SRV ${id.toString(36).toUpperCase().padStart(4, ' ')} ${method.padEnd(7, ' ')} ${pad.lt(url)} ${statusText} ${timeSpent.toString().padStart(4, ' ')}ms`)
|
|
329
|
+
}),
|
|
330
|
+
|
|
331
|
+
logServerClosed: wrap(({ id, method, url }) => {
|
|
332
|
+
if (url.startsWith('/_/')) {
|
|
333
|
+
return // avoids pollution
|
|
334
|
+
}
|
|
335
|
+
job[$logServerClosedCount] = (job[$logServerClosedCount] || 0) + 1
|
|
336
|
+
const request = job[$logServerRequests][id]
|
|
337
|
+
request.closed = true
|
|
338
|
+
if (request.redirected) {
|
|
339
|
+
delete job[$logServerRequests][id]
|
|
340
|
+
}
|
|
341
|
+
log(job, p80()`🛜 CLS ${id.toString(36).toUpperCase().padStart(4, ' ')} ${method.padEnd(7, ' ')} ${pad.lt(url)}`)
|
|
342
|
+
}),
|
|
343
|
+
|
|
344
|
+
logServerSummary: wrap(() => {
|
|
345
|
+
log(job, p80()`🛜 requests: ${job[$logServerIncomingCount] || 0} incoming, ${job[$logServerRedirectedCount] || 0} redirected, ${job[$logServerClosedCount] || 0} closed.`)
|
|
346
|
+
if (job[$logServerRequests] && Object.keys(job[$logServerRequests]).length) {
|
|
347
|
+
log(job, job[$logServerRequests])
|
|
348
|
+
}
|
|
308
349
|
}),
|
|
309
350
|
|
|
310
351
|
status (status) {
|
|
@@ -384,6 +425,10 @@ function build (job) {
|
|
|
384
425
|
wrap(() => log(job, `⚠️ [PKGVRS] latest version of ${name} is ${latestVersion}`))()
|
|
385
426
|
},
|
|
386
427
|
|
|
428
|
+
detectedLeakOfHandles () {
|
|
429
|
+
wrap(() => log(job, '⚠️ [HDLEAK] leaking Node.js handle(s) detected. This may cause issues with the shutdown'))()
|
|
430
|
+
},
|
|
431
|
+
|
|
387
432
|
browserStart (url) {
|
|
388
433
|
const text = p80()`${getElapsed(job)} >> ${pad.lt(url)} [${filename(url)}]`
|
|
389
434
|
if (interactive) {
|
package/src/report.js
CHANGED
|
@@ -53,9 +53,14 @@ module.exports = {
|
|
|
53
53
|
job.end = new Date()
|
|
54
54
|
job.failed = !!job.failed
|
|
55
55
|
job.testPageHashes = job.testPageUrls.map(url => filename(url))
|
|
56
|
+
output.debug('report', 'saving job...')
|
|
56
57
|
await save(job)
|
|
58
|
+
output.debug('report', 'job saved.')
|
|
59
|
+
output.debug('report', 'generating text report...')
|
|
57
60
|
await generateTextReport(job)
|
|
61
|
+
output.debug('report', 'text report generated.')
|
|
58
62
|
const promises = job.reportGenerator.map(generator => {
|
|
63
|
+
output.debug('report', 'launching', generator, '...')
|
|
59
64
|
const { promise, resolve } = allocPromise()
|
|
60
65
|
const childProcess = fork(
|
|
61
66
|
generator,
|
|
@@ -70,13 +75,16 @@ module.exports = {
|
|
|
70
75
|
)
|
|
71
76
|
const buffers = output.monitor(childProcess, false)
|
|
72
77
|
childProcess.on('close', exitCode => {
|
|
78
|
+
output.debug('report', generator, 'ended with exit code', exitCode)
|
|
73
79
|
if (exitCode !== 0) {
|
|
74
80
|
output.reportGeneratorFailed(generator, exitCode, buffers)
|
|
75
81
|
}
|
|
76
82
|
resolve()
|
|
83
|
+
output.debug('report', generator, 'resolved')
|
|
77
84
|
})
|
|
78
85
|
return promise
|
|
79
86
|
})
|
|
87
|
+
output.debug('report', 'generators count:', promises.length)
|
|
80
88
|
await Promise.all(promises)
|
|
81
89
|
job.status = 'Reports generated'
|
|
82
90
|
}
|