ui5-test-runner 3.3.3 → 3.3.5
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 +30 -5
- package/src/coverage.js +38 -18
- package/src/coverage.spec.js +3 -1
- package/src/defaults/playwright.js +3 -1
- package/src/error.js +2 -0
- package/src/job.js +11 -1
- package/src/output.js +4 -0
- package/src/qunit-hooks.js +44 -9
- package/src/qunit-hooks.spec.js +22 -3
- package/src/report.js +4 -1
- package/src/simulate.spec.js +25 -0
- package/src/symbols.js +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui5-test-runner",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.5",
|
|
4
4
|
"description": "Standalone test runner for UI5",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"lint": "standard --fix",
|
|
19
|
-
"test": "npm run test:unit && npm run test:
|
|
19
|
+
"test": "npm run test:unit && npm run test:browsers && npm run test:samples",
|
|
20
|
+
"test:browsers": "npm run test:integration:jsdom && npm run test:integration:puppeteer && npm run test:integration:selenium-webdriver-chrome && npm run test:integration:playwright",
|
|
21
|
+
"test:samples": "npm run test:samples:js && npm run test:samples:ts",
|
|
22
|
+
"test:samples:js": "npm run test:sample:js:legacy && npm run test:sample:js:coverage:legacy && npm run test:sample:js:legacy-remote && npm run test:sample:js:coverage:legacy-remote && npm run test:sample:js:remote && npm run test:sample:js:coverage:remote",
|
|
23
|
+
"test:samples:ts": "npm run test:sample:ts:remote && npm run test:sample:ts:coverage:remote",
|
|
20
24
|
"test:coverall": "rimraf .nyc_output && jest --coverageDirectory .nyc_output --coverageReporters json && nyc --silent --no-clean npm run test:integration:jsdom && nyc --silent --no-clean npm run test:integration:puppeteer && nyc --silent --no-clean npm run test:integration:selenium-webdriver-chrome && nyc --silent --no-clean npm run test:integration:playwright && nyc merge .nyc_output .nyc_output/final/coverage.json && nyc report --temp-dir .nyc_output/final/ --report-dir coverage --branches 80 --functions 80 --lines 80 --statements 80",
|
|
21
25
|
"test:unit": "jest",
|
|
22
26
|
"test:unit:debug": "jest --runInBand",
|
|
@@ -26,6 +30,17 @@
|
|
|
26
30
|
"test:integration:playwright": "node . --capabilities --browser $/playwright.js",
|
|
27
31
|
"test:report": "node ./src/defaults/report.js ./test/report && reserve --config ./test/report/reserve.json",
|
|
28
32
|
"test:text-report": "node ./src/defaults/text-report.js ./test/report",
|
|
33
|
+
"test:sample:js:legacy": "node . --cwd ./test/sample.js",
|
|
34
|
+
"test:sample:js:coverage:legacy": "node . --cwd ./test/sample.js --coverage --coverage-settings nyc.json --coverage-check-statements 67",
|
|
35
|
+
"test:sample:js:legacy-remote": "node . --port 8081 --cwd ./test/sample.js --url http://localhost:8081/test/testsuite.qunit.html",
|
|
36
|
+
"test:sample:js:coverage:legacy-remote": "node . --port 8081 --cwd ./test/sample.js --url http://localhost:8081/test/testsuite.qunit.html --coverage --coverage-settings nyc.json --coverage-check-statements 67",
|
|
37
|
+
"test:sample:js:remote": "start-server-and-test 'npm run serve:sample:js' http://localhost:8080 'node . --url http://localhost:8080/test/testsuite.qunit.html'",
|
|
38
|
+
"test:sample:js:coverage:remote": "start-server-and-test 'npm run serve:sample:js' http://localhost:8080 'node . --url http://localhost:8080/test/testsuite.qunit.html --coverage --coverage-check-statements 67'",
|
|
39
|
+
"serve:sample:js": "ui5 serve --config ./test/sample.js/ui5.yaml",
|
|
40
|
+
"test:sample:ts:remote": "start-server-and-test 'npm run serve:sample:ts' http://localhost:8080 'node . --url http://localhost:8080/test/testsuite.qunit.html'",
|
|
41
|
+
"serve:sample:ts": "cd ./test/sample.ts && node ui5.cjs serve",
|
|
42
|
+
"test:sample:ts:coverage:remote": "start-server-and-test 'npm run serve:sample:ts:coverage' http://localhost:8080 'node . --url http://localhost:8080/test/testsuite.qunit.html --coverage --coverage-check-statements 67'",
|
|
43
|
+
"serve:sample:ts:coverage": "cd ./test/sample.ts && node ui5.cjs serve --config ui5-coverage.yaml",
|
|
29
44
|
"build:doc": "node build/doc"
|
|
30
45
|
},
|
|
31
46
|
"repository": {
|
|
@@ -52,13 +67,19 @@
|
|
|
52
67
|
"mime": "^3.0.0",
|
|
53
68
|
"punybind": "^1.2.1",
|
|
54
69
|
"punyexpr": "^1.0.4",
|
|
55
|
-
"reserve": "^1.15.
|
|
70
|
+
"reserve": "^1.15.4"
|
|
56
71
|
},
|
|
57
72
|
"devDependencies": {
|
|
73
|
+
"@openui5/types": "^1.119.0",
|
|
74
|
+
"@ui5/cli": "^3.6.1",
|
|
75
|
+
"@ui5/middleware-code-coverage": "^1.1.0",
|
|
58
76
|
"jest": "^29.7.0",
|
|
59
77
|
"nock": "^13.3.3",
|
|
60
78
|
"nyc": "^15.1.0",
|
|
61
|
-
"standard": "^17.1.0"
|
|
79
|
+
"standard": "^17.1.0",
|
|
80
|
+
"start-server-and-test": "^2.0.1",
|
|
81
|
+
"typescript": "^5.2.2",
|
|
82
|
+
"ui5-tooling-transpile": "^3.2.6"
|
|
62
83
|
},
|
|
63
84
|
"optionalDependencies": {
|
|
64
85
|
"fsevents": "^2.3.3"
|
|
@@ -69,6 +90,10 @@
|
|
|
69
90
|
"qunit",
|
|
70
91
|
"node",
|
|
71
92
|
"jest"
|
|
93
|
+
],
|
|
94
|
+
"globals": [
|
|
95
|
+
"sap",
|
|
96
|
+
"opaTest"
|
|
72
97
|
]
|
|
73
98
|
},
|
|
74
99
|
"jest": {
|
|
@@ -98,4 +123,4 @@
|
|
|
98
123
|
}
|
|
99
124
|
}
|
|
100
125
|
}
|
|
101
|
-
}
|
|
126
|
+
}
|
package/src/coverage.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { join, dirname } = require('path')
|
|
3
|
+
const { join, dirname, isAbsolute } = require('path')
|
|
4
4
|
const { fork } = require('child_process')
|
|
5
|
-
const { cleanDir, createDir, filename, download } = require('./tools')
|
|
5
|
+
const { cleanDir, createDir, filename, download, allocPromise } = require('./tools')
|
|
6
6
|
const { readdir, readFile, stat, writeFile, access, constants } = require('fs').promises
|
|
7
7
|
const { Readable } = require('stream')
|
|
8
8
|
const { getOutput } = require('./output')
|
|
9
9
|
const { resolvePackage } = require('./npm')
|
|
10
10
|
const { promisify } = require('util')
|
|
11
|
+
const { UTRError } = require('./error')
|
|
12
|
+
const { $remoteOnLegacy } = require('./symbols')
|
|
11
13
|
|
|
12
14
|
const $nycSettingsPath = Symbol('nycSettingsPath')
|
|
13
15
|
const $coverageFileIndex = Symbol('coverageFileIndex')
|
|
@@ -28,9 +30,13 @@ async function nyc (job, ...args) {
|
|
|
28
30
|
output.nyc(...args)
|
|
29
31
|
const childProcess = fork(nycScript, args, { stdio: 'pipe' })
|
|
30
32
|
output.monitor(childProcess)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const { promise, resolve, reject } = allocPromise()
|
|
34
|
+
childProcess.on('close', async code => {
|
|
35
|
+
if (code !== 0) {
|
|
36
|
+
reject(UTRError.NYC_FAILED(`Return code ${code}`))
|
|
37
|
+
}
|
|
38
|
+
resolve()
|
|
39
|
+
})
|
|
34
40
|
return promise
|
|
35
41
|
}
|
|
36
42
|
|
|
@@ -70,15 +76,9 @@ async function instrument (job) {
|
|
|
70
76
|
settings.exclude.push(join(job.coverageReportDir, '**'))
|
|
71
77
|
await writeFile(job[$nycSettingsPath], JSON.stringify(settings))
|
|
72
78
|
if (job.mode === 'url') {
|
|
73
|
-
|
|
74
|
-
const useLocal = job.url.some(url => {
|
|
75
|
-
// ignore host name since the machine might be exposed with any name
|
|
76
|
-
const parsedUrl = new URL(url)
|
|
77
|
-
return parsedUrl.port === port
|
|
78
|
-
})
|
|
79
|
-
if (!useLocal) {
|
|
80
|
-
getOutput(job).instrumentationSkipped()
|
|
79
|
+
if (!job[$remoteOnLegacy]) {
|
|
81
80
|
job[$coverageRemote] = true
|
|
81
|
+
getOutput(job).instrumentationSkipped()
|
|
82
82
|
return
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -94,20 +94,30 @@ async function generateCoverageReport (job) {
|
|
|
94
94
|
const coverageFilename = join(coverageMergedDir, 'coverage.json')
|
|
95
95
|
await nyc(job, 'merge', job.coverageTempDir, coverageFilename)
|
|
96
96
|
if (job[$coverageRemote] && !job.coverageProxy) {
|
|
97
|
-
job.status = '
|
|
97
|
+
job.status = 'Checking remote source files'
|
|
98
98
|
// Assuming all files are coming from the same server
|
|
99
99
|
const { origin } = new URL(job.testPageUrls[0])
|
|
100
100
|
const sourcesBasePath = join(job.coverageTempDir, 'sources')
|
|
101
101
|
const coverageData = require(coverageFilename)
|
|
102
102
|
const filenames = Object.keys(coverageData)
|
|
103
|
+
let changes = 0
|
|
103
104
|
for (const filename of filenames) {
|
|
104
105
|
const fileData = coverageData[filename]
|
|
105
106
|
const { path } = fileData
|
|
107
|
+
if (isAbsolute(path)) {
|
|
108
|
+
try {
|
|
109
|
+
await access(path, constants.R_OK)
|
|
110
|
+
continue
|
|
111
|
+
} catch (e) {}
|
|
112
|
+
}
|
|
106
113
|
const filePath = join(sourcesBasePath, path)
|
|
107
114
|
fileData.path = filePath
|
|
108
115
|
await download(origin + path, filePath)
|
|
116
|
+
++changes
|
|
117
|
+
}
|
|
118
|
+
if (changes > 0) {
|
|
119
|
+
await writeFile(coverageFilename, JSON.stringify(coverageData))
|
|
109
120
|
}
|
|
110
|
-
await writeFile(coverageFilename, JSON.stringify(coverageData))
|
|
111
121
|
}
|
|
112
122
|
const reporters = job.coverageReporters.map(reporter => `--reporter=${reporter}`)
|
|
113
123
|
if (!job.coverageReporters.includes('text')) {
|
|
@@ -115,6 +125,9 @@ async function generateCoverageReport (job) {
|
|
|
115
125
|
}
|
|
116
126
|
const checks = []
|
|
117
127
|
if (job.coverageCheckBranches || job.coverageCheckFunctions || job.coverageCheckLines || job.coverageCheckStatements) {
|
|
128
|
+
if (!job.coverageReporters.includes('lcov')) {
|
|
129
|
+
reporters.push('--reporter=lcov')
|
|
130
|
+
}
|
|
118
131
|
checks.push(
|
|
119
132
|
`--branches=${job.coverageCheckBranches}`,
|
|
120
133
|
`--functions=${job.coverageCheckFunctions}`,
|
|
@@ -124,6 +137,13 @@ async function generateCoverageReport (job) {
|
|
|
124
137
|
)
|
|
125
138
|
}
|
|
126
139
|
await nyc(job, 'report', ...reporters, ...checks, '--temp-dir', coverageMergedDir, '--report-dir', job.coverageReportDir, '--nycrc-path', job[$nycSettingsPath])
|
|
140
|
+
if (checks.length) {
|
|
141
|
+
// The checks are not triggered if the coverage is empty
|
|
142
|
+
const lcov = await stat(join(job.coverageReportDir, 'lcov.info'))
|
|
143
|
+
if (lcov.size === 0) {
|
|
144
|
+
throw UTRError.NYC_FAILED('No coverage information extracted')
|
|
145
|
+
}
|
|
146
|
+
}
|
|
127
147
|
}
|
|
128
148
|
|
|
129
149
|
module.exports = {
|
|
@@ -136,18 +156,18 @@ module.exports = {
|
|
|
136
156
|
}
|
|
137
157
|
await writeFile(coverageFileName, JSON.stringify(coverageData))
|
|
138
158
|
},
|
|
139
|
-
generateCoverageReport: job => job.coverage
|
|
159
|
+
generateCoverageReport: job => job.coverage ? generateCoverageReport(job) : Promise.resolve(),
|
|
140
160
|
mappings: async job => {
|
|
141
161
|
if (!job.coverage) {
|
|
142
162
|
return []
|
|
143
163
|
}
|
|
144
164
|
const instrumentedBasePath = join(job.coverageTempDir, 'instrumented')
|
|
145
165
|
const instrumentedMapping = {
|
|
146
|
-
match:
|
|
166
|
+
match: /(.*\.js)(\?.*)?$/,
|
|
147
167
|
file: join(instrumentedBasePath, '$1'),
|
|
148
168
|
'ignore-if-not-found': true
|
|
149
169
|
}
|
|
150
|
-
if (job.mode === 'legacy') {
|
|
170
|
+
if (job.mode === 'legacy' || job[$remoteOnLegacy]) {
|
|
151
171
|
return [{
|
|
152
172
|
...instrumentedMapping,
|
|
153
173
|
'custom-file-system': job.debugCoverageNoCustomFs ? undefined : customFileSystem
|
package/src/coverage.spec.js
CHANGED
|
@@ -4,6 +4,7 @@ const { instrument, generateCoverageReport, mappings } = require('./coverage')
|
|
|
4
4
|
const { stat } = require('fs/promises')
|
|
5
5
|
const { cleanDir, createDir } = require('./tools')
|
|
6
6
|
const { getOutput } = require('./output')
|
|
7
|
+
const { $remoteOnLegacy } = require('./symbols')
|
|
7
8
|
|
|
8
9
|
describe('src/coverage', () => {
|
|
9
10
|
const cwd = join(__dirname, '../test/project')
|
|
@@ -108,7 +109,8 @@ describe('src/coverage', () => {
|
|
|
108
109
|
Object.assign(job, {
|
|
109
110
|
mode: 'url',
|
|
110
111
|
port: 8080,
|
|
111
|
-
url: ['http://localhost:8080/whatever/test.html']
|
|
112
|
+
url: ['http://localhost:8080/whatever/test.html'],
|
|
113
|
+
[$remoteOnLegacy]: true // added on job finalization
|
|
112
114
|
})
|
|
113
115
|
await instrument(job)
|
|
114
116
|
expect(instrumentationSkipped).not.toHaveBeenCalled()
|
|
@@ -88,7 +88,9 @@ require('./browser')({
|
|
|
88
88
|
networkWriter
|
|
89
89
|
}) {
|
|
90
90
|
const browsers = require(modules.playwright)
|
|
91
|
-
browser = await browsers[options.browser].launch(
|
|
91
|
+
browser = await browsers[options.browser].launch({
|
|
92
|
+
headless: !options.visible
|
|
93
|
+
})
|
|
92
94
|
|
|
93
95
|
let recordVideo
|
|
94
96
|
if (options.video) {
|
package/src/error.js
CHANGED
package/src/job.js
CHANGED
|
@@ -5,7 +5,7 @@ const { statSync, accessSync, constants } = require('fs')
|
|
|
5
5
|
const { dirname, join, isAbsolute } = require('path')
|
|
6
6
|
const { name, description, version } = require(join(__dirname, '../package.json'))
|
|
7
7
|
const { getOutput } = require('./output')
|
|
8
|
-
const { $valueSources } = require('./symbols')
|
|
8
|
+
const { $valueSources, $remoteOnLegacy } = require('./symbols')
|
|
9
9
|
const { buildAndCheckMode } = require('./job-mode')
|
|
10
10
|
const { boolean, integer, timeout, url, arrayOf, regex, percent } = require('./options')
|
|
11
11
|
|
|
@@ -107,6 +107,7 @@ function getCommand (cwd) {
|
|
|
107
107
|
.option('-br, --browser-retry <count>', '[💻🔗🧪] Browser instantiation retries : if the command fails unexpectedly, it is re-executed (0 means no retry)', 1)
|
|
108
108
|
|
|
109
109
|
// Common to legacy and url
|
|
110
|
+
.option('-qs, --qunit-strict', '[💻🔗] Strict mode on qunit execution (fails if no modules declared)', boolean, false)
|
|
110
111
|
.option('-pf, --page-filter <regexp>', '[💻🔗] Filter out pages not matching the regexp')
|
|
111
112
|
.option('-pp, --page-params <params>', '[💻🔗] Add parameters to page URL')
|
|
112
113
|
.option('-t, --global-timeout <timeout>', '[💻🔗] Limit the pages execution time, fail the page if it takes longer than the timeout (0 means no timeout)', timeout, 0)
|
|
@@ -287,6 +288,15 @@ function finalize (job) {
|
|
|
287
288
|
overrideIfNotSet('coverageReporters', settings.reporter)
|
|
288
289
|
}
|
|
289
290
|
|
|
291
|
+
if (job.mode === 'url') {
|
|
292
|
+
const port = job.port.toString()
|
|
293
|
+
job[$remoteOnLegacy] = job.url.every(url => {
|
|
294
|
+
// ignore host name since the machine might be exposed with any name
|
|
295
|
+
const parsedUrl = new URL(url)
|
|
296
|
+
return parsedUrl.port === port
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
|
|
290
300
|
job[$status] = 'Starting'
|
|
291
301
|
Object.defineProperty(job, 'status', {
|
|
292
302
|
get () {
|
package/src/output.js
CHANGED
|
@@ -412,6 +412,10 @@ function build (job) {
|
|
|
412
412
|
log(job, p80()`Skipping nyc instrumentation (--url)`)
|
|
413
413
|
}),
|
|
414
414
|
|
|
415
|
+
qunitEarlyStart: wrap(url => {
|
|
416
|
+
log(job, p80()`QUnit start without tests in ${pad.lt(url)}`)
|
|
417
|
+
}),
|
|
418
|
+
|
|
415
419
|
endpointError: wrap(({ api, url, data, error }) => {
|
|
416
420
|
const p = p80()
|
|
417
421
|
log(job, p`┌──────────${pad.x('─')}┐`)
|
package/src/qunit-hooks.js
CHANGED
|
@@ -13,27 +13,40 @@ function error (job, url, details = '') {
|
|
|
13
13
|
throw UTRError.QUNIT_ERROR(details)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function invalidTestId (job, url, testId) {
|
|
17
|
+
error(job, url, `No QUnit unit test found with id ${testId}`)
|
|
18
|
+
}
|
|
19
|
+
|
|
16
20
|
function get (job, urlWithHash, testId) {
|
|
17
21
|
const url = stripUrlHash(urlWithHash)
|
|
18
22
|
const page = job.qunitPages && job.qunitPages[url]
|
|
19
23
|
if (!page) {
|
|
20
24
|
error(job, url, `No QUnit page found for ${urlWithHash}`)
|
|
21
25
|
}
|
|
26
|
+
let testModule
|
|
22
27
|
let test
|
|
23
28
|
if (testId !== undefined) {
|
|
24
29
|
page.modules.every(module => {
|
|
25
30
|
test = module.tests.find(test => test.testId === testId)
|
|
26
|
-
|
|
31
|
+
if (test === undefined) {
|
|
32
|
+
return true
|
|
33
|
+
} else {
|
|
34
|
+
testModule = module
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
27
37
|
})
|
|
28
|
-
if (!test) {
|
|
29
|
-
|
|
38
|
+
if (!test && job.qunitStrict) {
|
|
39
|
+
invalidTestId(job, url, testId)
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
|
-
return { url, page, test }
|
|
42
|
+
return { url, page, testModule, test }
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
async function done (job, urlWithHash, report) {
|
|
36
46
|
const { url, page } = get(job, urlWithHash)
|
|
47
|
+
if (page.earlyStart && page.count === 0) {
|
|
48
|
+
return // wait
|
|
49
|
+
}
|
|
37
50
|
if (job.browserCapabilities.screenshot) {
|
|
38
51
|
try {
|
|
39
52
|
await screenshot(job, url, 'done')
|
|
@@ -41,11 +54,11 @@ async function done (job, urlWithHash, report) {
|
|
|
41
54
|
getOutput(job).genericError(error, url)
|
|
42
55
|
}
|
|
43
56
|
}
|
|
57
|
+
page.end = new Date()
|
|
44
58
|
if (report.__coverage__) {
|
|
45
|
-
collect(job, url, report.__coverage__)
|
|
59
|
+
await collect(job, url, report.__coverage__)
|
|
46
60
|
delete report.__coverage__
|
|
47
61
|
}
|
|
48
|
-
page.end = new Date()
|
|
49
62
|
page.report = report
|
|
50
63
|
stop(job, url)
|
|
51
64
|
}
|
|
@@ -55,8 +68,12 @@ module.exports = {
|
|
|
55
68
|
|
|
56
69
|
async begin (job, urlWithHash, { isOpa, totalTests, modules }) {
|
|
57
70
|
const url = stripUrlHash(urlWithHash)
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
const earlyStart = !totalTests || !modules
|
|
72
|
+
if (earlyStart) {
|
|
73
|
+
getOutput(job).qunitEarlyStart(url)
|
|
74
|
+
if (job.qunitStrict) {
|
|
75
|
+
error(job, url, 'Invalid begin hook details')
|
|
76
|
+
}
|
|
60
77
|
}
|
|
61
78
|
if (!job.qunitPages) {
|
|
62
79
|
job.qunitPages = {}
|
|
@@ -70,16 +87,31 @@ module.exports = {
|
|
|
70
87
|
count: totalTests,
|
|
71
88
|
modules
|
|
72
89
|
}
|
|
90
|
+
if (earlyStart) {
|
|
91
|
+
qunitPage.earlyStart = true
|
|
92
|
+
}
|
|
73
93
|
job.qunitPages[url] = qunitPage
|
|
74
94
|
},
|
|
75
95
|
|
|
76
96
|
async testStart (job, urlWithHash, { module, name, testId }) {
|
|
77
|
-
|
|
97
|
+
let { page, testModule, test } = get(job, urlWithHash, testId)
|
|
98
|
+
if (!testModule) {
|
|
99
|
+
testModule = { name: module, tests: [] }
|
|
100
|
+
page.modules.push(testModule)
|
|
101
|
+
}
|
|
102
|
+
if (!test) {
|
|
103
|
+
test = { name, testId }
|
|
104
|
+
testModule.tests.push(test)
|
|
105
|
+
++page.count
|
|
106
|
+
}
|
|
78
107
|
test.start = new Date()
|
|
79
108
|
},
|
|
80
109
|
|
|
81
110
|
async log (job, urlWithHash, { module, name, testId, ...log }) {
|
|
82
111
|
const { url, page, test } = get(job, urlWithHash, testId)
|
|
112
|
+
if (!test) {
|
|
113
|
+
invalidTestId(job, url, testId)
|
|
114
|
+
}
|
|
83
115
|
if (!test.logs) {
|
|
84
116
|
test.logs = []
|
|
85
117
|
}
|
|
@@ -97,6 +129,9 @@ module.exports = {
|
|
|
97
129
|
async testDone (job, urlWithHash, { name, module, testId, assertions, ...report }) {
|
|
98
130
|
const { failed } = report
|
|
99
131
|
const { url, page, test } = get(job, urlWithHash, testId)
|
|
132
|
+
if (!test) {
|
|
133
|
+
invalidTestId(job, url, testId)
|
|
134
|
+
}
|
|
100
135
|
if (failed) {
|
|
101
136
|
if (job.browserCapabilities.screenshot) {
|
|
102
137
|
try {
|
package/src/qunit-hooks.spec.js
CHANGED
|
@@ -10,10 +10,12 @@ jest.mock('./coverage.js', () => ({
|
|
|
10
10
|
const { collect } = require('./coverage')
|
|
11
11
|
|
|
12
12
|
const mockGenericError = jest.fn()
|
|
13
|
+
const mockQunitEarlyStart = jest.fn()
|
|
13
14
|
|
|
14
15
|
jest.mock('./output.js', () => ({
|
|
15
16
|
getOutput: () => ({
|
|
16
|
-
genericError: mockGenericError
|
|
17
|
+
genericError: mockGenericError,
|
|
18
|
+
qunitEarlyStart: mockQunitEarlyStart
|
|
17
19
|
})
|
|
18
20
|
}))
|
|
19
21
|
|
|
@@ -174,7 +176,11 @@ describe('src/qunit-hooks', () => {
|
|
|
174
176
|
})
|
|
175
177
|
})
|
|
176
178
|
|
|
177
|
-
describe('validation', () => {
|
|
179
|
+
describe('validation (--qunit-strict)', () => {
|
|
180
|
+
beforeEach(() => {
|
|
181
|
+
job.qunitStrict = true
|
|
182
|
+
})
|
|
183
|
+
|
|
178
184
|
afterEach(() => {
|
|
179
185
|
expect(stop).toHaveBeenCalledWith(job, url)
|
|
180
186
|
expect(job.failed).toStrictEqual(true)
|
|
@@ -185,6 +191,7 @@ describe('src/qunit-hooks', () => {
|
|
|
185
191
|
isOpa: false,
|
|
186
192
|
modules: getModules()
|
|
187
193
|
})).rejects.toThrow(UTRError.QUNIT_ERROR('Invalid begin hook details'))
|
|
194
|
+
expect(mockQunitEarlyStart).toHaveBeenCalled()
|
|
188
195
|
})
|
|
189
196
|
|
|
190
197
|
it('requires modules', async () => {
|
|
@@ -192,6 +199,7 @@ describe('src/qunit-hooks', () => {
|
|
|
192
199
|
isOpa: false,
|
|
193
200
|
totalTests: 1
|
|
194
201
|
})).rejects.toThrow(UTRError.QUNIT_ERROR('Invalid begin hook details'))
|
|
202
|
+
expect(mockQunitEarlyStart).toHaveBeenCalled()
|
|
195
203
|
})
|
|
196
204
|
})
|
|
197
205
|
})
|
|
@@ -594,7 +602,18 @@ describe('src/qunit-hooks', () => {
|
|
|
594
602
|
expect(job.failed).toStrictEqual(true)
|
|
595
603
|
})
|
|
596
604
|
|
|
597
|
-
it('fails on invalid test id', async () => {
|
|
605
|
+
it('fails on invalid test id (--qunit-strict)', async () => {
|
|
606
|
+
job.qunitStrict = true
|
|
607
|
+
await expect(testDone(job, url, {
|
|
608
|
+
...getTestDoneFor1a(),
|
|
609
|
+
testId: '1c'
|
|
610
|
+
}))
|
|
611
|
+
.rejects.toThrow(UTRError.QUNIT_ERROR('No QUnit unit test found with id 1c'))
|
|
612
|
+
expect(stop).toHaveBeenCalledWith(job, url)
|
|
613
|
+
expect(job.failed).toStrictEqual(true)
|
|
614
|
+
})
|
|
615
|
+
|
|
616
|
+
it('fails on invalid test id (--no-qunit-strict)', async () => {
|
|
598
617
|
await expect(testDone(job, url, {
|
|
599
618
|
...getTestDoneFor1a(),
|
|
600
619
|
testId: '1c'
|
package/src/report.js
CHANGED
|
@@ -51,7 +51,10 @@ module.exports = {
|
|
|
51
51
|
})
|
|
52
52
|
return promise
|
|
53
53
|
})
|
|
54
|
-
promises.push(generateCoverageReport(job)
|
|
54
|
+
promises.push(generateCoverageReport(job).catch(e => {
|
|
55
|
+
output.genericError(e)
|
|
56
|
+
job.failed = true
|
|
57
|
+
}))
|
|
55
58
|
await Promise.all(promises)
|
|
56
59
|
job.status = 'Done'
|
|
57
60
|
}
|
package/src/simulate.spec.js
CHANGED
|
@@ -213,6 +213,31 @@ describe('simulate', () => {
|
|
|
213
213
|
})
|
|
214
214
|
})
|
|
215
215
|
|
|
216
|
+
describe('simple test execution (--no-qunit-strict)', () => {
|
|
217
|
+
beforeAll(async () => {
|
|
218
|
+
await setup('simple-early')
|
|
219
|
+
pages = {
|
|
220
|
+
'testsuite.qunit.html': async referer => {
|
|
221
|
+
await post('/_/addTestPages', referer, [
|
|
222
|
+
referer.replace('testsuite.qunit.html', 'page1.html')
|
|
223
|
+
])
|
|
224
|
+
},
|
|
225
|
+
'page1.html': async referer => {
|
|
226
|
+
await post('/_/QUnit/begin', referer, { totalTests: 0, modules: [] })
|
|
227
|
+
await post('/_/QUnit/done', referer, { failed: 0 })
|
|
228
|
+
await post('/_/QUnit/testStart', referer, { module: 'module', name: 'test', testId: '1' })
|
|
229
|
+
await post('/_/QUnit/testDone', referer, { testId: '1', failed: 0, passed: 1 })
|
|
230
|
+
await post('/_/QUnit/done', referer, { failed: 0 })
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
await safeExecute()
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('succeeded', () => {
|
|
237
|
+
expect(job.failed).toStrictEqual(false)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
216
241
|
describe('error', () => {
|
|
217
242
|
describe('one test fail', () => {
|
|
218
243
|
beforeAll(async () => {
|
package/src/symbols.js
CHANGED
|
@@ -4,5 +4,6 @@ module.exports = {
|
|
|
4
4
|
$probeUrlsCompleted: Symbol('probeUrlsCompleted'),
|
|
5
5
|
$testPagesStarted: Symbol('testPagesStarted'),
|
|
6
6
|
$testPagesCompleted: Symbol('testPagesCompleted'),
|
|
7
|
-
$valueSources: Symbol('valueSources')
|
|
7
|
+
$valueSources: Symbol('valueSources'),
|
|
8
|
+
$remoteOnLegacy: Symbol('remoteOnLegacy')
|
|
8
9
|
}
|