ui5-test-runner 5.2.0 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/browsers.js CHANGED
@@ -1,297 +1,301 @@
1
- 'use strict'
2
-
3
- const { fork } = require('child_process')
4
- const { join } = require('path')
5
- const { writeFile, readFile, open, stat, unlink } = require('fs/promises')
6
- const { recreateDir, filename, allocPromise } = require('./tools')
7
- const { getPageTimeout, pageTimedOut } = require('./timeout')
8
- const { getOutput, newProgress } = require('./output')
9
- const { resolvePackage } = require('./npm')
10
- const { UTRError } = require('./error')
11
- const { $browsers } = require('./symbols')
12
-
13
- let lastScreenshotId = 0
14
- const screenshots = {}
15
-
16
- async function instantiate (job, config) {
17
- const { dir, url } = config
18
- await recreateDir(dir)
19
- const browserConfig = {
20
- capabilities: job.browserCapabilities,
21
- modules: job.browserModules,
22
- ...config,
23
- args: job.browserArgs
24
- }
25
- const browserConfigPath = join(dir, 'browser.json')
26
- await writeFile(browserConfigPath, JSON.stringify(browserConfig, undefined, 2))
27
- const stdoutFilename = join(dir, 'stdout.txt')
28
- const stderrFilename = join(dir, 'stderr.txt')
29
- const stdout = await open(stdoutFilename, 'w')
30
- const stderr = await open(stderrFilename, 'w')
31
- const childProcess = fork(job.browser, [browserConfigPath], {
32
- stdio: [0, stdout, stderr, 'ipc']
33
- })
34
- const { promise, resolve } = allocPromise()
35
- childProcess.on('close', async code => {
36
- await stdout.close()
37
- await stderr.close()
38
- if (code !== 0) {
39
- getOutput(job).browserFailed(url, code, dir)
40
- }
41
- resolve(code)
42
- })
43
- childProcess.closed = promise
44
- childProcess.stdoutFilename = stdoutFilename
45
- childProcess.stderrFilename = stderrFilename
46
- return childProcess
47
- }
48
-
49
- async function probe (job) {
50
- if (job.browserCapabilities) {
51
- return
52
- }
53
- const output = getOutput(job)
54
- job.status = 'Probing browser instantiation command'
55
-
56
- async function execute (folder) {
57
- const dir = join(job.reportDir, folder)
58
- const capabilities = join(dir, 'capabilities.json')
59
- const childProcess = await instantiate(job, {
60
- url: 'about:blank',
61
- capabilities,
62
- dir
63
- })
64
- const code = await childProcess.closed
65
- if (code !== 0) {
66
- throw UTRError.BROWSER_PROBE_FAILED(code.toString())
67
- }
68
- let browserCapabilities
69
- try {
70
- browserCapabilities = Object.assign({
71
- modules: [],
72
- screenshot: null,
73
- scripts: false,
74
- parallel: true,
75
- traces: []
76
- }, JSON.parse((await readFile(capabilities)).toString()))
77
- } catch (e) {
78
- throw UTRError.MISSING_OR_INVALID_BROWSER_CAPABILITIES(e.message)
79
- }
80
- return browserCapabilities
81
- }
82
-
83
- const browserCapabilities = await execute('probe')
84
- job.browserCapabilities = browserCapabilities
85
-
86
- const { modules } = browserCapabilities
87
- const resolvedModules = {}
88
- if (modules.length) {
89
- for await (const name of browserCapabilities.modules) {
90
- resolvedModules[name] = await resolvePackage(job, name)
91
- }
92
- }
93
- job.browserModules = resolvedModules
94
- if (browserCapabilities['probe-with-modules']) {
95
- job.browserCapabilities = await execute('probe/with-modules')
96
- }
97
-
98
- output.browserCapabilities(job.browserCapabilities)
99
- }
100
-
101
- async function start (job, url, scripts = []) {
102
- const output = getOutput(job)
103
- if (!job[$browsers]) {
104
- job[$browsers] = {}
105
- }
106
- output.browserStart(url)
107
- const reportDir = join(job.reportDir, filename(url))
108
- const resolvedScripts = []
109
- for await (const script of scripts) {
110
- if (script.endsWith('.js')) {
111
- const scriptFilename = join(__dirname, 'inject', script)
112
- const scriptContent = (await readFile(scriptFilename)).toString()
113
- resolvedScripts.push(scriptContent)
114
- } else {
115
- resolvedScripts.push(script)
116
- }
117
- }
118
- if (resolvedScripts.length) {
119
- resolvedScripts.unshift(`(function () {
120
- window['ui5-test-runner/base-host'] = 'http://localhost:${job.port}'
121
- }())`)
122
- }
123
- const progress = newProgress(job, url)
124
- const pageBrowser = {
125
- url,
126
- reportDir,
127
- scripts: resolvedScripts,
128
- retry: 0,
129
- progress
130
- }
131
- const { promise, resolve, reject } = allocPromise()
132
- pageBrowser.done = value => {
133
- delete job[$browsers][url]
134
- resolve(value)
135
- }
136
- pageBrowser.failed = reason => {
137
- delete job[$browsers][url]
138
- reject(reason)
139
- }
140
- job[$browsers][url] = pageBrowser
141
- await run(job, pageBrowser)
142
- try {
143
- await promise
144
- } finally {
145
- progress.done()
146
- output.browserStopped(url)
147
- }
148
- }
149
-
150
- async function run (job, pageBrowser) {
151
- const output = getOutput(job)
152
- const { url, retry, reportDir, scripts } = pageBrowser
153
- let dir = reportDir
154
- if (retry) {
155
- output.browserRetry(url, retry)
156
- dir = join(dir, retry.toString())
157
- if (pageBrowser.console.count) {
158
- try {
159
- await pageBrowser.console.flush
160
- .then(() => unlink(join(reportDir, 'console.jsonl')))
161
- } catch (e) {
162
- // ignore
163
- }
164
- }
165
- }
166
- pageBrowser.console = {
167
- count: 0,
168
- byApi: {},
169
- flush: Promise.resolve()
170
- }
171
- await recreateDir(dir)
172
- delete pageBrowser.stopped
173
- const childProcess = await instantiate(job, {
174
- url,
175
- retry,
176
- scripts,
177
- dir
178
- })
179
- pageBrowser.childProcess = childProcess
180
- const timeout = getPageTimeout(job)
181
- if (timeout) {
182
- pageBrowser.timeoutId = setTimeout(() => {
183
- output.browserTimeout(url, dir)
184
- pageTimedOut(job, url)
185
- stop(job, url)
186
- }, timeout)
187
- }
188
- childProcess.on('message', message => {
189
- if (message.command === 'screenshot') {
190
- const { id } = message
191
- screenshots[id]()
192
- delete screenshots[id]
193
- } else if (message.command === 'console') {
194
- ++pageBrowser.console.count
195
- if (!pageBrowser.console.byApi[message.api]) {
196
- pageBrowser.console.byApi[message.api] = 1
197
- } else {
198
- ++pageBrowser.console.byApi[message.api]
199
- }
200
- pageBrowser.console.flush = pageBrowser.console.flush
201
- .then(() => writeFile(join(reportDir, 'console.jsonl'), JSON.stringify({
202
- t: message.t,
203
- api: message.api,
204
- args: message.args
205
- }) + '\n', {
206
- flag: 'a+'
207
- }))
208
- }
209
- })
210
- childProcess.on('close', async code => {
211
- if (!pageBrowser.stopped) {
212
- if (code === 0) {
213
- output.browserClosed(url, code, dir)
214
- }
215
- childProcess.closed.then(() => stop(job, url, true))
216
- }
217
- })
218
- }
219
-
220
- async function screenshot (job, url, filename) {
221
- if (!job.browserCapabilities.screenshot) {
222
- throw UTRError.BROWSER_SCREENSHOT_NOT_SUPPORTED()
223
- }
224
- const output = getOutput(job)
225
- const id = ++lastScreenshotId
226
- try {
227
- const { childProcess, reportDir } = job[$browsers][url]
228
- const absoluteFilename = join(reportDir, filename + job.browserCapabilities.screenshot)
229
- if (childProcess.connected) {
230
- output.debug('screenshot', id, url, absoluteFilename)
231
- const { promise, resolve, reject } = allocPromise()
232
- screenshots[id] = resolve
233
- output.debug('screenshot', id, 'sending command')
234
- childProcess.send({
235
- id,
236
- command: 'screenshot',
237
- filename: absoluteFilename
238
- })
239
- const timeoutId = setTimeout(() => {
240
- reject(UTRError.BROWSER_SCREENSHOT_TIMEOUT())
241
- }, job.screenshotTimeout)
242
- output.debug('screenshot', id, 'command sent, waiting for answer')
243
- await promise
244
- output.debug('screenshot', id, 'answer received')
245
- clearTimeout(timeoutId)
246
- const result = await stat(absoluteFilename)
247
- output.debug('screenshot', id, 'file size :', result.size)
248
- if (!result.isFile() || result.size === 0) {
249
- throw new Error('File expected')
250
- }
251
- output.debug('screenshot', id, 'done')
252
- return absoluteFilename
253
- }
254
- } catch (e) {
255
- output.debug('screenshot', id, e.message)
256
- if (e.code === UTRError.BROWSER_SCREENSHOT_TIMEOUT_CODE) {
257
- throw e
258
- }
259
- throw UTRError.BROWSER_SCREENSHOT_FAILED(e.toString())
260
- }
261
- }
262
-
263
- async function stop (job, url, retry = false) {
264
- const pageBrowser = job[$browsers][url]
265
- if (pageBrowser) {
266
- pageBrowser.stopped = true
267
- const { childProcess, done, failed, timeoutId } = pageBrowser
268
- if (timeoutId) {
269
- clearTimeout(timeoutId)
270
- }
271
- if (childProcess.connected) {
272
- /* istanbul ignore else */
273
- if (!job.debugKeepBrowserOpen) {
274
- childProcess.send({ command: 'stop' })
275
- }
276
- const { promise: closeTimeout, resolve } = allocPromise()
277
- const timeoutId = setTimeout(resolve, job.browserCloseTimeout)
278
- await Promise.race([
279
- childProcess.closed,
280
- closeTimeout
281
- ])
282
- clearTimeout(timeoutId)
283
- }
284
- await pageBrowser.console.flush
285
- if (retry) {
286
- if (++pageBrowser.retry <= job.browserRetry) {
287
- run(job, pageBrowser)
288
- } else {
289
- failed(UTRError.BROWSER_FAILED())
290
- }
291
- } else {
292
- done()
293
- }
294
- }
295
- }
296
-
297
- module.exports = { probe, start, screenshot, stop }
1
+ 'use strict'
2
+
3
+ const { fork } = require('child_process')
4
+ const { join } = require('path')
5
+ const { writeFile, readFile, open, stat, unlink } = require('fs/promises')
6
+ const { recreateDir, filename, allocPromise } = require('./tools')
7
+ const { getPageTimeout, pageTimedOut } = require('./timeout')
8
+ const { getOutput, newProgress } = require('./output')
9
+ const { resolvePackage } = require('./npm')
10
+ const { UTRError } = require('./error')
11
+ const { $browsers } = require('./symbols')
12
+
13
+ let lastScreenshotId = 0
14
+ const screenshots = {}
15
+
16
+ async function instantiate (job, config) {
17
+ const { dir, url } = config
18
+ await recreateDir(dir)
19
+ const browserConfig = {
20
+ capabilities: job.browserCapabilities,
21
+ modules: job.browserModules,
22
+ ...config,
23
+ args: job.browserArgs
24
+ }
25
+ const browserConfigPath = join(dir, 'browser.json')
26
+ await writeFile(browserConfigPath, JSON.stringify(browserConfig, undefined, 2))
27
+ const stdoutFilename = join(dir, 'stdout.txt')
28
+ const stderrFilename = join(dir, 'stderr.txt')
29
+ const stdout = await open(stdoutFilename, 'w')
30
+ const stderr = await open(stderrFilename, 'w')
31
+ const childProcess = fork(job.browser, [browserConfigPath], {
32
+ stdio: [0, stdout, stderr, 'ipc']
33
+ })
34
+ const { promise, resolve } = allocPromise()
35
+ childProcess.on('close', async code => {
36
+ await stdout.close()
37
+ await stderr.close()
38
+ if (code !== 0) {
39
+ getOutput(job).browserFailed(url, code, dir)
40
+ }
41
+ resolve(code)
42
+ })
43
+ childProcess.closed = promise
44
+ childProcess.stdoutFilename = stdoutFilename
45
+ childProcess.stderrFilename = stderrFilename
46
+ return childProcess
47
+ }
48
+
49
+ async function probe (job) {
50
+ if (job.browserCapabilities) {
51
+ return
52
+ }
53
+ const output = getOutput(job)
54
+ job.status = 'Probing browser instantiation command'
55
+
56
+ async function execute (folder) {
57
+ const dir = join(job.reportDir, folder)
58
+ const capabilities = join(dir, 'capabilities.json')
59
+ const childProcess = await instantiate(job, {
60
+ url: 'about:blank',
61
+ capabilities,
62
+ dir
63
+ })
64
+ const code = await childProcess.closed
65
+ if (code !== 0) {
66
+ throw UTRError.BROWSER_PROBE_FAILED(code.toString())
67
+ }
68
+ let browserCapabilities
69
+ try {
70
+ browserCapabilities = Object.assign({
71
+ modules: [],
72
+ screenshot: null,
73
+ scripts: false,
74
+ parallel: true,
75
+ traces: []
76
+ }, JSON.parse((await readFile(capabilities)).toString()))
77
+ } catch (e) {
78
+ throw UTRError.MISSING_OR_INVALID_BROWSER_CAPABILITIES(e.message)
79
+ }
80
+ return browserCapabilities
81
+ }
82
+
83
+ const browserCapabilities = await execute('probe')
84
+ job.browserCapabilities = browserCapabilities
85
+
86
+ const { modules } = browserCapabilities
87
+ const resolvedModules = {}
88
+ if (modules.length) {
89
+ for await (const name of browserCapabilities.modules) {
90
+ resolvedModules[name] = await resolvePackage(job, name)
91
+ }
92
+ }
93
+ job.browserModules = resolvedModules
94
+ if (browserCapabilities['probe-with-modules']) {
95
+ job.browserCapabilities = await execute('probe/with-modules')
96
+ }
97
+
98
+ if (job.debugCapabilitiesNoScript) {
99
+ job.browserCapabilities.scripts = false
100
+ }
101
+
102
+ output.browserCapabilities(job.browserCapabilities)
103
+ }
104
+
105
+ async function start (job, url, scripts = []) {
106
+ const output = getOutput(job)
107
+ if (!job[$browsers]) {
108
+ job[$browsers] = {}
109
+ }
110
+ output.browserStart(url)
111
+ const reportDir = join(job.reportDir, filename(url))
112
+ const resolvedScripts = []
113
+ for await (const script of scripts) {
114
+ if (script.endsWith('.js')) {
115
+ const scriptFilename = join(__dirname, 'inject', script)
116
+ const scriptContent = (await readFile(scriptFilename)).toString()
117
+ resolvedScripts.push(scriptContent)
118
+ } else {
119
+ resolvedScripts.push(script)
120
+ }
121
+ }
122
+ if (resolvedScripts.length) {
123
+ resolvedScripts.unshift(`(function () {
124
+ window['ui5-test-runner/base-host'] = 'http://localhost:${job.port}'
125
+ }())`)
126
+ }
127
+ const progress = newProgress(job, url)
128
+ const pageBrowser = {
129
+ url,
130
+ reportDir,
131
+ scripts: resolvedScripts,
132
+ retry: 0,
133
+ progress
134
+ }
135
+ const { promise, resolve, reject } = allocPromise()
136
+ pageBrowser.done = value => {
137
+ delete job[$browsers][url]
138
+ resolve(value)
139
+ }
140
+ pageBrowser.failed = reason => {
141
+ delete job[$browsers][url]
142
+ reject(reason)
143
+ }
144
+ job[$browsers][url] = pageBrowser
145
+ await run(job, pageBrowser)
146
+ try {
147
+ await promise
148
+ } finally {
149
+ progress.done()
150
+ output.browserStopped(url)
151
+ }
152
+ }
153
+
154
+ async function run (job, pageBrowser) {
155
+ const output = getOutput(job)
156
+ const { url, retry, reportDir, scripts } = pageBrowser
157
+ let dir = reportDir
158
+ if (retry) {
159
+ output.browserRetry(url, retry)
160
+ dir = join(dir, retry.toString())
161
+ if (pageBrowser.console.count) {
162
+ try {
163
+ await pageBrowser.console.flush
164
+ .then(() => unlink(join(reportDir, 'console.jsonl')))
165
+ } catch (e) {
166
+ // ignore
167
+ }
168
+ }
169
+ }
170
+ pageBrowser.console = {
171
+ count: 0,
172
+ byApi: {},
173
+ flush: Promise.resolve()
174
+ }
175
+ await recreateDir(dir)
176
+ delete pageBrowser.stopped
177
+ const childProcess = await instantiate(job, {
178
+ url,
179
+ retry,
180
+ scripts,
181
+ dir
182
+ })
183
+ pageBrowser.childProcess = childProcess
184
+ const timeout = getPageTimeout(job)
185
+ if (timeout) {
186
+ pageBrowser.timeoutId = setTimeout(() => {
187
+ output.browserTimeout(url, dir)
188
+ pageTimedOut(job, url)
189
+ stop(job, url)
190
+ }, timeout)
191
+ }
192
+ childProcess.on('message', message => {
193
+ if (message.command === 'screenshot') {
194
+ const { id } = message
195
+ screenshots[id]()
196
+ delete screenshots[id]
197
+ } else if (message.command === 'console') {
198
+ ++pageBrowser.console.count
199
+ if (!pageBrowser.console.byApi[message.api]) {
200
+ pageBrowser.console.byApi[message.api] = 1
201
+ } else {
202
+ ++pageBrowser.console.byApi[message.api]
203
+ }
204
+ pageBrowser.console.flush = pageBrowser.console.flush
205
+ .then(() => writeFile(join(reportDir, 'console.jsonl'), JSON.stringify({
206
+ t: message.t,
207
+ api: message.api,
208
+ args: message.args
209
+ }) + '\n', {
210
+ flag: 'a+'
211
+ }))
212
+ }
213
+ })
214
+ childProcess.on('close', async code => {
215
+ if (!pageBrowser.stopped) {
216
+ if (code === 0) {
217
+ output.browserClosed(url, code, dir)
218
+ }
219
+ childProcess.closed.then(() => stop(job, url, true))
220
+ }
221
+ })
222
+ }
223
+
224
+ async function screenshot (job, url, filename) {
225
+ if (!job.browserCapabilities.screenshot) {
226
+ throw UTRError.BROWSER_SCREENSHOT_NOT_SUPPORTED()
227
+ }
228
+ const output = getOutput(job)
229
+ const id = ++lastScreenshotId
230
+ try {
231
+ const { childProcess, reportDir } = job[$browsers][url]
232
+ const absoluteFilename = join(reportDir, filename + job.browserCapabilities.screenshot)
233
+ if (childProcess.connected) {
234
+ output.debug('screenshot', id, url, absoluteFilename)
235
+ const { promise, resolve, reject } = allocPromise()
236
+ screenshots[id] = resolve
237
+ output.debug('screenshot', id, 'sending command')
238
+ childProcess.send({
239
+ id,
240
+ command: 'screenshot',
241
+ filename: absoluteFilename
242
+ })
243
+ const timeoutId = setTimeout(() => {
244
+ reject(UTRError.BROWSER_SCREENSHOT_TIMEOUT())
245
+ }, job.screenshotTimeout)
246
+ output.debug('screenshot', id, 'command sent, waiting for answer')
247
+ await promise
248
+ output.debug('screenshot', id, 'answer received')
249
+ clearTimeout(timeoutId)
250
+ const result = await stat(absoluteFilename)
251
+ output.debug('screenshot', id, 'file size :', result.size)
252
+ if (!result.isFile() || result.size === 0) {
253
+ throw new Error('File expected')
254
+ }
255
+ output.debug('screenshot', id, 'done')
256
+ return absoluteFilename
257
+ }
258
+ } catch (e) {
259
+ output.debug('screenshot', id, e.message)
260
+ if (e.code === UTRError.BROWSER_SCREENSHOT_TIMEOUT_CODE) {
261
+ throw e
262
+ }
263
+ throw UTRError.BROWSER_SCREENSHOT_FAILED(e.toString())
264
+ }
265
+ }
266
+
267
+ async function stop (job, url, retry = false) {
268
+ const pageBrowser = job[$browsers][url]
269
+ if (pageBrowser) {
270
+ pageBrowser.stopped = true
271
+ const { childProcess, done, failed, timeoutId } = pageBrowser
272
+ if (timeoutId) {
273
+ clearTimeout(timeoutId)
274
+ }
275
+ if (childProcess.connected) {
276
+ /* istanbul ignore else */
277
+ if (!job.debugKeepBrowserOpen) {
278
+ childProcess.send({ command: 'stop' })
279
+ }
280
+ const { promise: closeTimeout, resolve } = allocPromise()
281
+ const timeoutId = setTimeout(resolve, job.browserCloseTimeout)
282
+ await Promise.race([
283
+ childProcess.closed,
284
+ closeTimeout
285
+ ])
286
+ clearTimeout(timeoutId)
287
+ }
288
+ await pageBrowser.console.flush
289
+ if (retry) {
290
+ if (++pageBrowser.retry <= job.browserRetry) {
291
+ run(job, pageBrowser)
292
+ } else {
293
+ failed(UTRError.BROWSER_FAILED())
294
+ }
295
+ } else {
296
+ done()
297
+ }
298
+ }
299
+ }
300
+
301
+ module.exports = { probe, start, screenshot, stop }
package/src/coverage.js CHANGED
@@ -310,13 +310,27 @@ module.exports = {
310
310
  await setupNyc(job)
311
311
  // Assuming all files are coming from the same server
312
312
  const { origin } = new URL(job.url[0])
313
- const { createInstrumenter } = require(join(await nycInstallationPath, 'node_modules/istanbul-lib-instrument'))
314
- const instrumenter = createInstrumenter({
315
- produceSourceMap: true,
316
- coverageGlobalScope: 'window.top',
317
- coverageGlobalScopeFunc: false
318
- })
319
- const instrument = promisify(instrumenter.instrument.bind(instrumenter))
313
+ let instrument
314
+ try {
315
+ const { createInstrumenter } = require(join(await nycInstallationPath, 'node_modules/istanbul-lib-instrument'))
316
+ const instrumenter = createInstrumenter({
317
+ produceSourceMap: true,
318
+ coverageGlobalScope: 'window.top',
319
+ coverageGlobalScopeFunc: false
320
+ })
321
+ instrument = promisify(instrumenter.instrument.bind(instrumenter))
322
+ } catch (e) {
323
+ // Recent version of nyc offers a different interface
324
+ const createInstrumenter = require(join(await nycInstallationPath, 'lib/instrumenters/istanbul.js'))
325
+ const instrumenter = createInstrumenter({
326
+ produceSourceMap: true
327
+ })
328
+ instrument = async function (code, sourcePath) {
329
+ return instrumenter.instrumentSync(code, sourcePath, { registerMap: () => {} })
330
+ // TODO use regular expression !
331
+ .replace(globalContextSearch, globalContextReplace)
332
+ }
333
+ }
320
334
  const sources = {}
321
335
  return [{
322
336
  match: /(.*\.js)(\?.*)?$/,