ui5-test-runner 1.1.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +32 -188
  2. package/index.js +47 -16
  3. package/package.json +28 -10
  4. package/src/add-test-pages.js +35 -0
  5. package/src/add-test-pages.spec.js +95 -0
  6. package/src/browser.spec.js +724 -0
  7. package/src/browsers.js +220 -59
  8. package/src/capabilities/index.js +194 -0
  9. package/src/capabilities/tests/basic/iframe.html +8 -0
  10. package/src/capabilities/tests/basic/index.html +12 -0
  11. package/src/capabilities/tests/basic/index.js +20 -0
  12. package/src/capabilities/tests/basic/ui5.html +24 -0
  13. package/src/capabilities/tests/dynamic-include/index.js +21 -0
  14. package/src/capabilities/tests/dynamic-include/mix.html +11 -0
  15. package/src/capabilities/tests/dynamic-include/one.html +11 -0
  16. package/src/capabilities/tests/dynamic-include/post.js +3 -0
  17. package/src/capabilities/tests/dynamic-include/test.js +1 -0
  18. package/src/capabilities/tests/dynamic-include/two.html +11 -0
  19. package/src/capabilities/tests/index.js +16 -0
  20. package/src/capabilities/tests/local-storage/index.html +16 -0
  21. package/src/capabilities/tests/local-storage/index.js +21 -0
  22. package/src/capabilities/tests/screenshot/index.html +13 -0
  23. package/src/capabilities/tests/screenshot/index.js +18 -0
  24. package/src/capabilities/tests/scripts/index.js +50 -0
  25. package/src/capabilities/tests/scripts/qunit.html +22 -0
  26. package/src/capabilities/tests/scripts/testsuite.html +10 -0
  27. package/src/capabilities/tests/scripts/testsuite.js +8 -0
  28. package/src/capabilities/tests/timeout/index.html +21 -0
  29. package/src/capabilities/tests/timeout/index.js +19 -0
  30. package/src/capabilities/tests/traces/index.html +18 -0
  31. package/src/capabilities/tests/traces/index.js +81 -0
  32. package/src/cors.js +1 -1
  33. package/src/cors.spec.js +41 -0
  34. package/src/coverage.js +30 -18
  35. package/src/coverage.spec.js +79 -0
  36. package/src/csv-reader.js +36 -0
  37. package/src/csv-reader.spec.js +42 -0
  38. package/src/csv-writer.js +52 -0
  39. package/src/csv-writer.spec.js +77 -0
  40. package/src/defaults/browser.js +144 -0
  41. package/src/defaults/jsdom/compatibility.js +95 -0
  42. package/src/defaults/jsdom/debug.js +23 -0
  43. package/src/defaults/jsdom/resource-loader.js +43 -0
  44. package/src/defaults/jsdom/sap.ui.test.matchers.visible.js +39 -0
  45. package/src/defaults/jsdom.js +64 -0
  46. package/src/defaults/junit-xml-report.js +64 -0
  47. package/src/defaults/puppeteer.js +111 -0
  48. package/src/defaults/report/common.js +38 -0
  49. package/src/defaults/report/default.html +84 -0
  50. package/src/defaults/report/main.js +44 -0
  51. package/src/defaults/report/progress.js +49 -0
  52. package/src/defaults/report/styles.css +66 -0
  53. package/src/defaults/report.js +69 -0
  54. package/src/defaults/selenium-webdriver/chrome.js +38 -0
  55. package/src/defaults/selenium-webdriver/edge.js +25 -0
  56. package/src/defaults/selenium-webdriver/firefox.js +31 -0
  57. package/src/defaults/selenium-webdriver.js +138 -0
  58. package/src/endpoints.js +70 -124
  59. package/src/error.js +52 -0
  60. package/src/error.spec.js +17 -0
  61. package/src/get-job-progress.js +69 -0
  62. package/src/get-job-progress.spec.js +175 -0
  63. package/src/inject/post.js +96 -0
  64. package/src/inject/post.spec.js +147 -0
  65. package/src/inject/qunit-hooks.js +6 -21
  66. package/src/inject/qunit-intercept.js +30 -0
  67. package/src/inject/qunit-redirect.js +15 -7
  68. package/src/job-mode.js +45 -0
  69. package/src/job.js +254 -108
  70. package/src/job.spec.js +413 -0
  71. package/src/npm.js +73 -0
  72. package/src/npm.spec.js +98 -0
  73. package/src/options.js +73 -0
  74. package/src/options.spec.js +125 -0
  75. package/src/output.js +450 -131
  76. package/src/qunit-hooks.js +116 -0
  77. package/src/qunit-hooks.spec.js +687 -0
  78. package/src/report.js +47 -0
  79. package/src/reserve.js +3 -4
  80. package/src/simulate.spec.js +466 -0
  81. package/src/symbols.js +8 -0
  82. package/src/tests.js +127 -84
  83. package/src/timeout.spec.js +39 -0
  84. package/src/tools.js +111 -4
  85. package/src/tools.spec.js +90 -0
  86. package/src/ui5.js +3 -3
  87. package/src/unhandled.js +6 -6
  88. package/src/unhandled.spec.js +63 -0
  89. package/defaults/chromium.js +0 -62
  90. package/src/progress.html +0 -71
  91. package/src/proxies.js +0 -8
  92. package/src/report.html +0 -202
  93. /package/{defaults → src/defaults}/nyc.json +0 -0
package/src/browsers.js CHANGED
@@ -2,55 +2,179 @@
2
2
 
3
3
  const { fork } = require('child_process')
4
4
  const { join } = require('path')
5
- const { recreateDir, filename } = require('./tools')
5
+ const { writeFile, readFile, open, stat, unlink } = require('fs/promises')
6
+ const { recreateDir, filename, allocPromise } = require('./tools')
6
7
  const { getPageTimeout } = require('./timeout')
7
- const output = require('./output')
8
+ const { getOutput } = require('./output')
9
+ const { resolvePackage } = require('./npm')
10
+ const { UTRError } = require('./error')
11
+ const { $browsers } = require('./symbols')
8
12
 
9
13
  let lastScreenshotId = 0
10
14
  const screenshots = {}
11
15
 
12
- function start (job, relativeUrl) {
13
- if (!job.browsers) {
14
- job.browsers = {}
15
- }
16
- output.browserStart(relativeUrl)
17
- const reportDir = join(job.tstReportDir, filename(relativeUrl))
18
- const args = job.args.split(' ')
19
- .map(arg => arg
20
- .replace('__URL__', `http://localhost:${job.port}${relativeUrl}`)
21
- .replace('__REPORT__', reportDir)
22
- )
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(`window['ui5-test-runner/base-host'] = 'http://localhost:${job.port}'
120
+ `)
121
+ }
23
122
  const pageBrowser = {
24
- relativeUrl,
123
+ url,
25
124
  reportDir,
26
- args,
125
+ scripts: resolvedScripts,
27
126
  retry: 0
28
127
  }
29
- const promise = new Promise(resolve => {
30
- pageBrowser.done = resolve
31
- })
32
- job.browsers[relativeUrl] = pageBrowser
33
- run(job, pageBrowser)
34
- return promise.then(() => {
35
- output.browserStopped(relativeUrl)
36
- })
128
+ const { promise, resolve, reject } = allocPromise()
129
+ pageBrowser.done = value => {
130
+ delete job[$browsers][url]
131
+ resolve(value)
132
+ }
133
+ pageBrowser.failed = reason => {
134
+ delete job[$browsers][url]
135
+ reject(reason)
136
+ }
137
+ job[$browsers][url] = pageBrowser
138
+ await run(job, pageBrowser)
139
+ await promise
140
+ output.browserStopped(url)
37
141
  }
38
142
 
39
143
  async function run (job, pageBrowser) {
40
- const { relativeUrl } = pageBrowser
41
- if (pageBrowser.retry) {
42
- output.browserRetry(relativeUrl, pageBrowser.retry)
144
+ const output = getOutput(job)
145
+ const { url, retry, reportDir, scripts } = pageBrowser
146
+ let dir = reportDir
147
+ if (retry) {
148
+ output.browserRetry(url, retry)
149
+ dir = join(dir, retry.toString())
150
+ if (pageBrowser.console.count) {
151
+ try {
152
+ await pageBrowser.console.flush
153
+ .then(() => unlink(join(reportDir, 'console.jsonl')))
154
+ } catch (e) {
155
+ // ignore
156
+ }
157
+ }
43
158
  }
44
- await recreateDir(pageBrowser.reportDir)
159
+ pageBrowser.console = {
160
+ count: 0,
161
+ byApi: {},
162
+ flush: Promise.resolve()
163
+ }
164
+ await recreateDir(dir)
45
165
  delete pageBrowser.stopped
46
- const childProcess = fork(job.browser, pageBrowser.args.map(arg => arg.replace('__RETRY__', pageBrowser.retry)), { stdio: 'pipe' })
47
- output.monitor(childProcess)
166
+ const childProcess = await instantiate(job, {
167
+ url,
168
+ retry,
169
+ scripts,
170
+ dir
171
+ })
48
172
  pageBrowser.childProcess = childProcess
49
173
  const timeout = getPageTimeout(job)
50
174
  if (timeout) {
51
175
  pageBrowser.timeoutId = setTimeout(() => {
52
- output.browserTimeout(relativeUrl)
53
- stop(job, relativeUrl)
176
+ output.browserTimeout(url, dir)
177
+ stop(job, url)
54
178
  }, timeout)
55
179
  }
56
180
  childProcess.on('message', message => {
@@ -58,63 +182,100 @@ async function run (job, pageBrowser) {
58
182
  const { id } = message
59
183
  screenshots[id]()
60
184
  delete screenshots[id]
61
- } else /* istanbul ignore else */ if (message.command === 'capabilities') {
62
- job.browserCapabilities = { ...message }
63
- delete job.browserCapabilities.command
64
- output.browserCapabilities(job.browserCapabilities)
185
+ } else if (message.command === 'console') {
186
+ ++pageBrowser.console.count
187
+ if (!pageBrowser.console.byApi[message.api]) {
188
+ pageBrowser.console.byApi[message.api] = 1
189
+ } else {
190
+ ++pageBrowser.console.byApi[message.api]
191
+ }
192
+ pageBrowser.console.flush = pageBrowser.console.flush
193
+ .then(() => writeFile(join(reportDir, 'console.jsonl'), JSON.stringify({
194
+ t: message.t,
195
+ api: message.api,
196
+ args: message.args
197
+ }) + '\n', {
198
+ flag: 'a+'
199
+ }))
65
200
  }
66
201
  })
67
- childProcess.on('close', () => {
202
+ childProcess.on('close', async code => {
68
203
  if (!pageBrowser.stopped) {
69
- output.browserClosed(relativeUrl)
70
- stop(job, relativeUrl, true)
204
+ if (code === 0) {
205
+ output.browserClosed(url, code, dir)
206
+ }
207
+ childProcess.closed.then(() => stop(job, url, true))
71
208
  }
72
209
  })
73
- if (!job.browserCapabilities) {
74
- childProcess.send({ command: 'capabilities' })
75
- }
76
210
  }
77
211
 
78
- async function screenshot (job, relativeUrl, filename) {
79
- if (job.noScreenshot || !job.browserCapabilities || !job.browserCapabilities.screenshot) {
80
- return
212
+ async function screenshot (job, url, filename) {
213
+ if (!job.browserCapabilities.screenshot) {
214
+ throw UTRError.BROWSER_SCREENSHOT_NOT_SUPPORTED()
81
215
  }
82
- const pageBrowser = job.browsers[relativeUrl]
83
- if (pageBrowser) {
84
- const { childProcess } = pageBrowser
216
+ try {
217
+ const { childProcess, reportDir } = job[$browsers][url]
218
+ const absoluteFilename = join(reportDir, filename + job.browserCapabilities.screenshot)
85
219
  if (childProcess.connected) {
86
220
  const id = ++lastScreenshotId
87
- const promise = new Promise(resolve => {
88
- screenshots[id] = resolve
89
- })
221
+ const { promise, resolve, reject } = allocPromise()
222
+ screenshots[id] = resolve
90
223
  childProcess.send({
91
224
  id,
92
225
  command: 'screenshot',
93
- filename
226
+ filename: absoluteFilename
94
227
  })
228
+ const timeoutId = setTimeout(() => {
229
+ reject(UTRError.BROWSER_SCREENSHOT_TIMEOUT())
230
+ }, job.screenshotTimeout)
95
231
  await promise
232
+ clearTimeout(timeoutId)
233
+ const result = await stat(absoluteFilename)
234
+ if (!result.isFile() || result.size === 0) {
235
+ throw new Error('File expected')
236
+ }
237
+ return absoluteFilename
96
238
  }
239
+ } catch (e) {
240
+ if (e.code === UTRError.BROWSER_SCREENSHOT_TIMEOUT_CODE) {
241
+ throw e
242
+ }
243
+ throw UTRError.BROWSER_SCREENSHOT_FAILED(e.toString())
97
244
  }
98
245
  }
99
246
 
100
- async function stop (job, relativeUrl, retry = false) {
101
- const pageBrowser = job.browsers[relativeUrl]
247
+ async function stop (job, url, retry = false) {
248
+ const pageBrowser = job[$browsers][url]
102
249
  if (pageBrowser) {
103
250
  pageBrowser.stopped = true
104
- const { childProcess, done, timeoutId } = pageBrowser
251
+ const { childProcess, done, failed, timeoutId } = pageBrowser
105
252
  if (timeoutId) {
106
253
  clearTimeout(timeoutId)
107
254
  }
108
255
  if (childProcess.connected) {
109
- childProcess.send({ command: 'stop' })
256
+ /* istanbul ignore else */
257
+ if (!job.debugKeepBrowserOpen) {
258
+ childProcess.send({ command: 'stop' })
259
+ }
260
+ const { promise: closeTimeout, resolve } = allocPromise()
261
+ const timeoutId = setTimeout(resolve, job.browserCloseTimeout)
262
+ await Promise.race([
263
+ childProcess.closed,
264
+ closeTimeout
265
+ ])
266
+ clearTimeout(timeoutId)
110
267
  }
111
- if (retry && ++pageBrowser.retry <= job.browserRetry) {
112
- run(job, pageBrowser)
268
+ await pageBrowser.console.flush
269
+ if (retry) {
270
+ if (++pageBrowser.retry <= job.browserRetry) {
271
+ run(job, pageBrowser)
272
+ } else {
273
+ failed(UTRError.BROWSER_FAILED())
274
+ }
113
275
  } else {
114
- delete job.browsers[relativeUrl]
115
276
  done()
116
277
  }
117
278
  }
118
279
  }
119
280
 
120
- module.exports = { start, screenshot, stop }
281
+ module.exports = { probe, start, screenshot, stop }
@@ -0,0 +1,194 @@
1
+ 'use strict'
2
+
3
+ const { check, serve, body } = require('reserve')
4
+ const { probe, start, stop } = require('../browsers')
5
+ const { join } = require('path')
6
+ const { getOutput } = require('../output')
7
+ const EventEmitter = require('events')
8
+ const { performance } = require('perf_hooks')
9
+ const { cleanDir, allocPromise, filename } = require('../tools')
10
+ const { $browsers } = require('../symbols')
11
+ const tests = require('./tests')
12
+
13
+ async function capabilities (job) {
14
+ const output = getOutput(job)
15
+
16
+ async function exit (code) {
17
+ if (job.keepAlive) {
18
+ job.status = 'Serving'
19
+ } else {
20
+ if (job.debugKeepReport) {
21
+ output.wrap(() => console.log('Report folder', job.reportDir, 'not cleaned because of --debug-keep-report.'))
22
+ } else if (code !== 0) {
23
+ output.wrap(() => console.error('Report folder', job.reportDir, 'not cleaned because of errors.'))
24
+ } else {
25
+ await cleanDir(job.reportDir)
26
+ }
27
+ output.stop()
28
+ process.exit(code)
29
+ }
30
+ }
31
+
32
+ try {
33
+ output.reportOnJobProgress()
34
+ try {
35
+ await probe(job)
36
+ } catch (e) {
37
+ output.wrap(() => console.error('Unable to probe'))
38
+ exit(-1)
39
+ }
40
+
41
+ const listeners = []
42
+
43
+ const configuration = await check({
44
+ port: job.port,
45
+ mappings: [
46
+ require('../cors'), {
47
+ custom: async (request, response) => {
48
+ response.setHeader('x-ui5-test-runner', 'capabilities')
49
+ }
50
+ }, {
51
+ match: /x-wait-time=(\d+)/,
52
+ custom: async (request, response, waitTime) => {
53
+ response.setHeader('x-wait-time', waitTime)
54
+ await new Promise(resolve => setTimeout(resolve, parseInt(waitTime)))
55
+ }
56
+ }, {
57
+ method: 'POST',
58
+ match: '^/_/(.*)',
59
+ custom: async (request, response, endpoint) => {
60
+ const { referer, 'x-page-url': xPageUrl } = request.headers
61
+ const listenerIndex = (xPageUrl || referer).match(/\blistener=(\d+)/)[1]
62
+ const listener = listeners[listenerIndex]
63
+ listener.emit('endpoint', {
64
+ endpoint,
65
+ body: JSON.parse(await body(request))
66
+ })
67
+ response.writeHead(200)
68
+ response.end()
69
+ }
70
+ }, {
71
+ match: '^/(.*)',
72
+ file: join(__dirname, '$1')
73
+ }]
74
+ })
75
+ const server = serve(configuration)
76
+ if (job.logServer) {
77
+ server.on('redirected', output.redirected)
78
+ }
79
+ await new Promise(resolve => server
80
+ .on('ready', ({ port }) => {
81
+ job.port = port
82
+ resolve()
83
+ })
84
+ )
85
+
86
+ job.status = 'Running tests'
87
+
88
+ const filteredTests = tests
89
+ .filter((test) => !test.for || test.for(job.browserCapabilities))
90
+ .filter(({ name }) => !job.debugCapabilitiesTest || name.startsWith(job.debugCapabilitiesTest))
91
+ output.wrap(() => console.log('Number of tests :', filteredTests.length))
92
+
93
+ let errors = 0
94
+
95
+ const { promise: forEver } = allocPromise()
96
+
97
+ const next = async () => {
98
+ if (filteredTests.length === 0) {
99
+ if (!job[$browsers] || Object.keys(job[$browsers]).length === 0) {
100
+ output.wrap(() => console.log('Done.'))
101
+ exit(errors)
102
+ }
103
+ return
104
+ }
105
+ const { label, url, scripts, endpoint = () => { } } = filteredTests.shift()
106
+
107
+ const listenerIndex = listeners.length
108
+ const listener = new EventEmitter()
109
+ listeners.push(listener)
110
+ let pageUrl
111
+ if (url.startsWith('http')) {
112
+ pageUrl = url
113
+ } else {
114
+ pageUrl = `http://localhost:${job.port}/tests/${url}`
115
+ }
116
+ if (url.includes('?')) {
117
+ pageUrl += `&listener=${listenerIndex}`
118
+ } else {
119
+ pageUrl += `?listener=${listenerIndex}`
120
+ }
121
+
122
+ const now = performance.now()
123
+ let timeoutId
124
+ if (!job.debugCapabilitiesNoTimeout) {
125
+ const timeout = job.pageTimeout || 120000
126
+ timeoutId = setTimeout(() => done(`Timeout (${timeout})`), timeout)
127
+ }
128
+
129
+ async function done (error) {
130
+ if (done.called) {
131
+ return
132
+ }
133
+ done.called = true
134
+ if (timeoutId) {
135
+ clearTimeout(timeoutId)
136
+ }
137
+ await stop(job, pageUrl)
138
+ const timeSpent = Math.floor(performance.now() - now)
139
+ if (error) {
140
+ output.wrap(() => console.log('❌', label, `[${filename(pageUrl)}]`, error))
141
+ if (job.failFast) {
142
+ exit(1)
143
+ }
144
+ ++errors
145
+ } else {
146
+ output.wrap(() => console.log('✔️', label, timeSpent, 'ms'))
147
+ }
148
+ await next()
149
+ }
150
+
151
+ const context = {
152
+ job
153
+ }
154
+ listener.on('endpoint', async data => {
155
+ try {
156
+ if (await endpoint.call(context, data, pageUrl) !== false) {
157
+ done()
158
+ }
159
+ } catch (e) {
160
+ done(e)
161
+ }
162
+ })
163
+
164
+ start(job, pageUrl, scripts)
165
+ .catch(reason => done(reason))
166
+ .then(() => {
167
+ if (!context.stopExpected) {
168
+ done('Failed')
169
+ }
170
+ })
171
+ }
172
+
173
+ let parallel
174
+ if (!job.browserCapabilities.parallel) {
175
+ parallel = 1
176
+ } else {
177
+ parallel = job.parallel
178
+ }
179
+
180
+ const testsCount = filteredTests.length
181
+ for (let i = 0; i < Math.max(Math.min(parallel, testsCount), 1); ++i) {
182
+ next()
183
+ }
184
+
185
+ await forEver
186
+ } catch (error) {
187
+ output.wrap(() => console.error(error))
188
+ exit(-1)
189
+ }
190
+ }
191
+
192
+ module.exports = {
193
+ capabilities
194
+ }
@@ -0,0 +1,8 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>iframe</H1>
5
+ <p>Checks if the browser can load UI5 in an iframe</p>
6
+ <iframe src="ui5.html"></iframe>
7
+ </body>
8
+ </html>
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>basic</H1>
5
+ <p>Checks if the browser can load a page</p>
6
+ <script>
7
+ const xhr = new XMLHttpRequest()
8
+ xhr.open('POST', '/_/log')
9
+ xhr.send('{}')
10
+ </script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ const assert = require('assert')
4
+
5
+ module.exports = [{
6
+ label: 'Loads a page',
7
+ url: 'basic/index.html'
8
+ }, {
9
+ label: 'Loads a UI5 example',
10
+ url: 'basic/ui5.html',
11
+ endpoint: ({ body }) => {
12
+ assert.strictEqual(body['sap.m.Button'], true)
13
+ }
14
+ }, {
15
+ label: 'Loads a UI5 inside an iframe',
16
+ url: 'basic/iframe.html',
17
+ endpoint: ({ body }) => {
18
+ assert.strictEqual(body['sap.m.Button'], true)
19
+ }
20
+ }]
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>UI5 example</H1>
5
+ <p>Checks if the browser can load a page</p>
6
+ <script
7
+ src="https://ui5.sap.com/resources/sap-ui-core.js"
8
+ id="sap-ui-bootstrap"
9
+ data-sap-ui-libs="sap.m"
10
+ data-sap-ui-theme="sap_fiori_3"
11
+ data-sap-ui-compatVersion="edge">
12
+ </script>
13
+ <script>
14
+ sap.ui.getCore().attachInit(function() {
15
+ const xhr = new XMLHttpRequest()
16
+ xhr.open('POST', '/_/log')
17
+ if (parent !== window) {
18
+ xhr.setRequestHeader('x-page-url', parent.document.location.toString())
19
+ }
20
+ xhr.send('{"sap.m.Button":' + !!sap.m.Button + '}')
21
+ });
22
+ </script>
23
+ </body>
24
+ </html>
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const assert = require('assert')
4
+
5
+ const endpoint = ({ body }) => {
6
+ assert.strictEqual(body.test, true)
7
+ }
8
+
9
+ module.exports = [{
10
+ label: 'Dynamic include',
11
+ url: 'dynamic-include/one.html',
12
+ endpoint
13
+ }, {
14
+ label: 'Dynamic includes',
15
+ url: 'dynamic-include/two.html',
16
+ endpoint
17
+ }, {
18
+ label: 'Dynamic include mixed with a static one',
19
+ url: 'dynamic-include/mix.html',
20
+ endpoint
21
+ }]
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>basic</H1>
5
+ <p>Checks if the browser can mix static script with a dynamic script inserted with document.write</p>
6
+ <script>
7
+ document.write('<script src="test.js?x-wait-time=1000"><' + '/script>'); // wait 1s before delivering
8
+ </script>
9
+ <script src="post.js"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>basic</H1>
5
+ <p>Checks if the browser can load a script inserted with document.write</p>
6
+ <script>
7
+ window.test = true
8
+ document.write('<script src="post.js"><' + '/script>');
9
+ </script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,3 @@
1
+ const xhr = new XMLHttpRequest()
2
+ xhr.open('POST', '/_/log')
3
+ xhr.send('{"test":' + window.test + '}')
@@ -0,0 +1 @@
1
+ window.test = true
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <H1>basic</H1>
5
+ <p>Checks if the browser can load sequentially scripts inserted with document.write</p>
6
+ <script>
7
+ document.write('<script src="test.js?x-wait-time=1000"><' + '/script>'); // wait 1s before delivering
8
+ document.write('<script src="post.js"><' + '/script>');
9
+ </script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,16 @@
1
+ const { readdirSync } = require('fs')
2
+
3
+ module.exports = readdirSync(__dirname)
4
+ .filter(name => !name.endsWith('.js'))
5
+ .map(name => {
6
+ const tests = require(`./${name}`)
7
+ if (Array.isArray(tests)) {
8
+ tests.forEach((test, index) => {
9
+ test.name = `${name}:${index}`
10
+ })
11
+ } else {
12
+ tests.name = name
13
+ }
14
+ return tests
15
+ })
16
+ .flat()