ui5-test-runner 3.3.1 → 3.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui5-test-runner",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Standalone test runner for UI5",
5
5
  "main": "index.js",
6
6
  "files": [
package/src/browsers.js CHANGED
@@ -4,7 +4,7 @@ const { fork } = require('child_process')
4
4
  const { join } = require('path')
5
5
  const { writeFile, readFile, open, stat, unlink } = require('fs/promises')
6
6
  const { recreateDir, filename, allocPromise } = require('./tools')
7
- const { getPageTimeout } = require('./timeout')
7
+ const { getPageTimeout, pageTimedOut } = require('./timeout')
8
8
  const { getOutput } = require('./output')
9
9
  const { resolvePackage } = require('./npm')
10
10
  const { UTRError } = require('./error')
@@ -174,6 +174,7 @@ async function run (job, pageBrowser) {
174
174
  if (timeout) {
175
175
  pageBrowser.timeoutId = setTimeout(() => {
176
176
  output.browserTimeout(url, dir)
177
+ pageTimedOut(job, url)
177
178
  stop(job, url)
178
179
  }, timeout)
179
180
  }
package/src/coverage.js CHANGED
@@ -110,7 +110,20 @@ async function generateCoverageReport (job) {
110
110
  await writeFile(coverageFilename, JSON.stringify(coverageData))
111
111
  }
112
112
  const reporters = job.coverageReporters.map(reporter => `--reporter=${reporter}`)
113
- await nyc(job, 'report', ...reporters, '--temp-dir', coverageMergedDir, '--report-dir', job.coverageReportDir, '--nycrc-path', job[$nycSettingsPath])
113
+ if (!job.coverageReporters.includes('text')) {
114
+ reporters.push('--reporter=text')
115
+ }
116
+ const checks = []
117
+ if (job.coverageCheckBranches || job.coverageCheckFunctions || job.coverageCheckLines || job.coverageCheckStatements) {
118
+ checks.push(
119
+ `--branches=${job.coverageCheckBranches}`,
120
+ `--functions=${job.coverageCheckFunctions}`,
121
+ `--lines=${job.coverageCheckLines}`,
122
+ `--statements=${job.coverageCheckStatements}`,
123
+ '--check-coverage'
124
+ )
125
+ }
126
+ await nyc(job, 'report', ...reporters, ...checks, '--temp-dir', coverageMergedDir, '--report-dir', job.coverageReportDir, '--nycrc-path', job[$nycSettingsPath])
114
127
  }
115
128
 
116
129
  module.exports = {
@@ -12,6 +12,9 @@
12
12
  <h1>{{ status || 'Test report' }}</h1>
13
13
  <div {{if}}="end === undefined" class="elapsed">In progress since {{ elapsed(start) }}</div>
14
14
  <div {{else}} class="elapsed">Duration : {{ elapsed(start, end) }} <a href="#" id="download">&#128230;</a></div>
15
+ <div {{if}}="timedOut">
16
+ &#9202;&#65039; Timed out
17
+ </div>
15
18
  <table style="visibility: {{ testPageUrls.length > 0 ? 'visible' : 'hidden' }};">
16
19
  <tr>
17
20
  <th>&nbsp;</th>
@@ -30,7 +33,7 @@
30
33
  <td>
31
34
  <span {{if}}="!qunitPages[url]">-</span>
32
35
  <span {{elseif}}="qunitPages[url].isOpa" title="OPA test">&#129404;</span>
33
- <span {{else}} title="Unit test">&#129514;</span>
36
+ <span {{elseif}}="qunitPages[url].start" title="Unit test">&#129514;</span>
34
37
  </td>
35
38
  <td>
36
39
  <span {{if}}="!qunitPages[url]">-</span>
@@ -56,6 +59,9 @@
56
59
  <a href="#">&#9204; back to report</a>
57
60
  <div {{if}}="qunitPage.end === undefined" class="elapsed">In progress since {{ elapsed(qunitPage.start) }}</div>
58
61
  <div {{else}} class="elapsed">Duration : {{ elapsed(qunitPage.start, qunitPage.end) }}</div>
62
+ <div {{if}}="timedOut">
63
+ &#9202;&#65039; Timed out
64
+ </div>
59
65
  <div {{for}}="module of qunitPage.modules">
60
66
  <h2>{{ module.name }}</h2>
61
67
  <div {{for}}="test of module.tests">
@@ -1,19 +1,29 @@
1
1
  'use strict'
2
2
 
3
3
  const { join, isAbsolute } = require('path')
4
- const [, , reportDir] = process.argv
4
+ const [, , reportDir, expectedWidth] = process.argv
5
5
  const { pad } = require('../tools')
6
6
 
7
- const p = pad(process.stdout.columns || 80)
7
+ const p = pad(process.stdout.columns || parseInt(expectedWidth || '80', 10))
8
8
  const log = console.log.bind(console)
9
9
 
10
10
  function collectErrors (page) {
11
11
  const errors = []
12
12
  page.modules.forEach(module => {
13
- module.tests.forEach(test => {
14
- if (test.report.failed) {
13
+ module.tests.every(test => {
14
+ if (!test.report) {
15
+ if (!test.skip) {
16
+ test.logs ??= []
17
+ test.logs.push({
18
+ message: '(no report found)'
19
+ })
20
+ errors.push({ module: module.name, ...test })
21
+ return false
22
+ }
23
+ } else if (test.report.failed) {
15
24
  errors.push({ module: module.name, ...test })
16
25
  }
26
+ return true
17
27
  })
18
28
  })
19
29
  return errors
@@ -28,8 +38,11 @@ async function main () {
28
38
  }
29
39
  const job = require(jobPath)
30
40
  const failedUrls = []
31
- log(p`┌─${pad.x('─')}───────────────────┐`)
41
+ let rendered = 0
32
42
  function render (url) {
43
+ if (++rendered === 1) {
44
+ log(p`┌─${pad.x('─')}───────────────────┐`)
45
+ }
33
46
  const page = job.qunitPages && job.qunitPages[url]
34
47
  if (!page || !page.report) {
35
48
  log(p`│${pad.lt(url)} 🧨 │`)
@@ -49,7 +62,9 @@ async function main () {
49
62
  render(url)
50
63
  }
51
64
  })
52
- log(p`└─${pad.x('─')}────────────────────┘`)
65
+ if (rendered > 0) {
66
+ log(p`└─${pad.x('─')}────────────────────┘`)
67
+ }
53
68
  failedUrls.forEach(url => {
54
69
  log()
55
70
  log(p`[${pad.lt(url)}]`)
package/src/job.js CHANGED
@@ -7,7 +7,7 @@ const { name, description, version } = require(join(__dirname, '../package.json'
7
7
  const { getOutput } = require('./output')
8
8
  const { $valueSources } = require('./symbols')
9
9
  const { buildAndCheckMode } = require('./job-mode')
10
- const { boolean, integer, timeout, url, arrayOf, regex } = require('./options')
10
+ const { boolean, integer, timeout, url, arrayOf, regex, percent } = require('./options')
11
11
 
12
12
  const $status = Symbol('status')
13
13
 
@@ -119,9 +119,13 @@ function getCommand (cwd) {
119
119
  .option('--coverage [flag]', '[💻🔗] Enable or disable code coverage', boolean)
120
120
  .option('--no-coverage', '[💻🔗] Disable code coverage')
121
121
  .option('-cs, --coverage-settings <path>', '[💻🔗] Path to a custom nyc.json file providing settings for instrumentation (relative to cwd or use $/ for provided ones)', '$/nyc.json')
122
- .option('-ct, --coverage-temp-dir <path>', '[💻🔗] Directory to output raw coverage information to (relative to cwd)', '.nyc_output')
123
- .option('-cr, --coverage-report-dir <path>', '[💻🔗] Directory to store the coverage report files (relative to cwd)', 'coverage')
124
- .option('-cr, --coverage-reporters <reporter...>', '[💻🔗] List of nyc reporters to use', ['lcov', 'cobertura'])
122
+ .option('-ctd, --coverage-temp-dir <path>', '[💻🔗] Directory to output raw coverage information to (relative to cwd)', '.nyc_output')
123
+ .option('-crd, --coverage-report-dir <path>', '[💻🔗] Directory to store the coverage report files (relative to cwd)', 'coverage')
124
+ .option('-cr, --coverage-reporters <reporter...>', '[💻🔗] List of nyc reporters to use (text is always used)', ['lcov', 'cobertura'])
125
+ .option('-ccb, --coverage-check-branches <percent>', '[💻🔗] What % of branches must be covered', percent, 0)
126
+ .option('-ccf, --coverage-check-functions <percent>', '[💻🔗] What % of functions must be covered', percent, 0)
127
+ .option('-ccl, --coverage-check-lines <percent>', '[💻🔗] What % of lines must be covered', percent, 0)
128
+ .option('-ccs, --coverage-check-statements <percent>', '[💻🔗] What % of statements must be covered', percent, 0)
125
129
  .option('-s, --serve-only [flag]', '[💻🔗] Serve only', boolean, false)
126
130
 
127
131
  // Specific to legacy (and might be used with url if pointing to local project)
package/src/options.js CHANGED
@@ -77,5 +77,13 @@ module.exports = {
77
77
  result.push(typeValidator(value))
78
78
  return result
79
79
  }
80
+ },
81
+
82
+ percent (value) {
83
+ const int = integer(value)
84
+ if (int > 100) {
85
+ throw new InvalidArgumentError('Invalid percent')
86
+ }
87
+ return int
80
88
  }
81
89
  }
@@ -1,4 +1,4 @@
1
- const { any, boolean, integer, timeout, url, arrayOf } = require('./options')
1
+ const { any, boolean, integer, timeout, url, arrayOf, percent } = require('./options')
2
2
  const { InvalidArgumentError } = require('commander')
3
3
 
4
4
  function checkType ({ method, validValues, invalidValues }) {
@@ -115,6 +115,22 @@ describe('src/options', () => {
115
115
  ]
116
116
  })
117
117
 
118
+ checkType({
119
+ method: percent,
120
+ validValues: {
121
+ 0: 0,
122
+ 1: 1,
123
+ 10: 10,
124
+ 100: 100
125
+ },
126
+ invalidValues: [
127
+ '',
128
+ '-1',
129
+ 'abc',
130
+ '101'
131
+ ]
132
+ })
133
+
118
134
  describe('arrayOf', () => {
119
135
  it('builds a type validator that aggregates validated values in an array', () => {
120
136
  const validator = arrayOf(integer)
package/src/report.js CHANGED
@@ -22,7 +22,7 @@ async function save (job) {
22
22
 
23
23
  function generateTextReport (job) {
24
24
  const { promise, resolve } = allocPromise()
25
- const childProcess = fork(join(__dirname, 'defaults/text-report.js'), [job.reportDir], { stdio: 'pipe' })
25
+ const childProcess = fork(join(__dirname, 'defaults/text-report.js'), [job.reportDir, process.stdout.columns || ''], { stdio: 'pipe' })
26
26
  getOutput(job).monitor(childProcess, true)
27
27
  childProcess.on('close', resolve)
28
28
  return promise
@@ -301,7 +301,7 @@ describe('simulate', () => {
301
301
 
302
302
  describe('global timeout', () => {
303
303
  beforeAll(async () => {
304
- await setup('timeout', {
304
+ await setup('global-timeout', {
305
305
  parallel: 1,
306
306
  globalTimeout: 10000
307
307
  })
@@ -325,6 +325,62 @@ describe('simulate', () => {
325
325
 
326
326
  it('failed', () => {
327
327
  expect(job.failed).toStrictEqual(true)
328
+ expect(job.timedOut).toStrictEqual(true)
329
+ })
330
+ })
331
+
332
+ describe('page timeout', () => {
333
+ beforeAll(async () => {
334
+ await setup('page-timeout', {
335
+ parallel: 1,
336
+ pageTimeout: 250
337
+ })
338
+ pages = {
339
+ 'testsuite.qunit.html': async referer => {
340
+ await post('/_/addTestPages', referer, [
341
+ '/page1.html'
342
+ ])
343
+ },
344
+ 'page1.html': async headers => {
345
+ await post('/_/QUnit/begin', headers, {
346
+ totalTests: 3,
347
+ modules: [{
348
+ name: '0',
349
+ tests: [{
350
+ name: '1',
351
+ testId: '1'
352
+ }, {
353
+ name: '2',
354
+ testId: '2'
355
+ }, {
356
+ name: '3',
357
+ testId: '3'
358
+ }]
359
+ }]
360
+ })
361
+ await post('/_/QUnit/testStart', headers, { module: '0', name: '1', testId: '1' })
362
+ await post('/_/QUnit/testDone', headers, { testId: '1', failed: 0, passed: 1 })
363
+ await post('/_/QUnit/testStart', headers, { module: '0', name: '2', testId: '2' })
364
+ }
365
+ }
366
+ await safeExecute()
367
+ })
368
+
369
+ it('failed', () => {
370
+ expect(job.failed).toStrictEqual(true)
371
+ expect(job.timedOut).toStrictEqual(true)
372
+ const page = job.qunitPages['http://localhost:0/page1.html']
373
+ expect(page.failed).toStrictEqual(2)
374
+ expect(page.end).not.toBeUndefined()
375
+ expect(page.timedOut).toStrictEqual(true)
376
+ const { tests } = page.modules[0]
377
+ expect(tests[1].report.failed).toStrictEqual(1)
378
+ expect(tests[1].report.passed).toStrictEqual(0)
379
+ expect(tests[1].end).not.toBeUndefined()
380
+ expect(tests[2].report.failed).toStrictEqual(1)
381
+ expect(tests[2].report.passed).toStrictEqual(0)
382
+ expect(tests[2].start).toBeUndefined()
383
+ expect(tests[2].end).toBeUndefined()
328
384
  })
329
385
  })
330
386
 
package/src/tests.js CHANGED
@@ -35,6 +35,7 @@ async function run (task, job) {
35
35
  if (globallyTimedOut(job)) {
36
36
  output.globalTimeout(url)
37
37
  job.failed = true
38
+ job.timedOut = true
38
39
  } else if (job.failFast && job.failed) {
39
40
  output.failFast(url)
40
41
  } else {
package/src/timeout.js CHANGED
@@ -16,5 +16,38 @@ module.exports = {
16
16
  return new Date() - job.start > job.globalTimeout
17
17
  }
18
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
+ job.failed = true
50
+ job.timedOut = true
51
+ }
19
52
  }
20
53
  }