UNPKG

5.96 kBJavaScriptView Raw
1'use strict'
2
3const { join } = require('path')
4const { body } = require('reserve')
5const { extractPageUrl } = require('./tools')
6const { Request, Response } = require('reserve')
7const { getOutput } = require('./output')
8const { begin, testStart, log, testDone, done } = require('./qunit-hooks')
9const { addTestPages } = require('./add-test-pages')
10const { getJobProgress } = require('./get-job-progress')
11const { readFile } = require('fs/promises')
12const { TextEncoder } = require('util')
13const { resolveDependencyPath } = require('./npm.js')
14
15const punyexprBinPath = join(resolveDependencyPath('punyexpr'), 'dist/punyexpr.js')
16const punybindBinPath = join(resolveDependencyPath('punybind'), 'dist/punybind.js')
17
18module.exports = job => {
19 async function endpointImpl (api, implementation, request) {
20 const url = extractPageUrl(request.headers)
21 const data = JSON.parse(await body(request))
22 try {
23 await implementation.call(this, url, data)
24 } catch (error) {
25 getOutput(job).endpointError({ api, url, data, error })
26 }
27 }
28
29 function synchronousEndpoint (api, implementation) {
30 return async function (request, response) {
31 await endpointImpl(api, implementation, request)
32 response.writeHead(200)
33 response.end()
34 }
35 }
36
37 function endpoint (api, implementation) {
38 return async function (request, response) {
39 response.writeHead(200)
40 response.end()
41 await endpointImpl(api, implementation, request)
42 }
43 }
44
45 async function getInjects (...names) {
46 return '\n;\n' + (await Promise.all(names.map(name => readFile(join(__dirname, 'inject', `${name}.js`)))))
47 .map(buffer => buffer.toString())
48 .join('\n;\n')
49 }
50
51 function contentLength (content) {
52 return new TextEncoder().encode(content).length
53 }
54
55 function sendScript (response, content) {
56 response.writeHead(200, {
57 'content-type': 'text/javascript',
58 'content-length': contentLength(content),
59 'cache-control': 'no-store'
60 })
61 response.end(content)
62 }
63
64 return job.parallel
65 ? [{
66 // Substitute qunit-redirect to extract test pages
67 match: '/resources/sap/ui/qunit/qunit-redirect.js',
68 custom: async (request, response) => {
69 sendScript(response, await getInjects('post', 'qunit-redirect'))
70 }
71 }, {
72 // Endpoint to receive test pages
73 match: '^/_/addTestPages',
74 custom: endpoint('addTestPages', (url, pages) => addTestPages(job, url, pages))
75 }, {
76 // QUnit hooks
77 match: '^/_/qunit-hooks.js',
78 file: join(__dirname, './inject/qunit-hooks.js')
79 }, {
80 // Concatenate qunit.js source with hooks
81 match: /\/thirdparty\/(qunit(?:-2)?(?:-dbg)?\.js)/,
82 custom: async function (request, response, scriptName) {
83 if (request.internal) {
84 return // ignore to avoid infinite loop
85 }
86 const ui5Request = new Request('GET', request.url)
87 ui5Request.internal = true
88 const ui5Response = new Response()
89 const [inject] = await Promise.all([
90 getInjects('post', 'qunit-hooks'),
91 this.configuration.dispatch(ui5Request, ui5Response)
92 ])
93 const hooksLength = contentLength(inject)
94 const ui5Length = parseInt(ui5Response.headers['content-length'], 10)
95 response.writeHead(ui5Response.statusCode, {
96 ...ui5Response.headers,
97 'content-length': ui5Length + hooksLength,
98 'cache-control': 'no-store' // for debugging purpose
99 })
100 response.write(ui5Response.toString())
101 response.end(inject)
102 }
103 }, {
104 // Endpoint to receive QUnit.begin
105 match: '^/_/QUnit/begin',
106 custom: endpoint('QUnit/begin', (url, details) => begin(job, url, details))
107 }, {
108 // Endpoint to receive QUnit.testStart
109 match: '^/_/QUnit/testStart',
110 custom: endpoint('QUnit/testStart', (url, details) => testStart(job, url, details))
111 }, {
112 // Endpoint to receive QUnit.log
113 match: '^/_/QUnit/log',
114 custom: synchronousEndpoint('QUnit/log', async (url, report) => log(job, url, report))
115 }, {
116 // Endpoint to receive QUnit.testDone
117 match: '^/_/QUnit/testDone',
118 custom: synchronousEndpoint('QUnit/testDone', async (url, report) => testDone(job, url, report))
119 }, {
120 // Endpoint to receive QUnit.done
121 match: '^/_/QUnit/done',
122 custom: endpoint('QUnit/done', async (url, report) => done(job, url, report))
123 }, {
124 // UI to follow progress
125 match: '^/_/progress.html',
126 file: job.progressPage
127 }, {
128 // Report 'main' substituted for progress
129 match: '^/_/report/main.js',
130 file: join(__dirname, 'defaults/report/progress.js')
131 }, {
132 // Other report resources
133 match: '^/_/report/(.*)',
134 file: join(__dirname, 'defaults/report/$1')
135 }, {
136 // punybind
137 match: '^/_/punybind.js',
138 file: punybindBinPath
139 }, {
140 // punyexpr
141 match: '^/_/punyexpr.js',
142 file: punyexprBinPath
143 }, {
144 // Endpoint to retry on progress
145 method: 'INFO',
146 match: '^/_/progress',
147 custom: (request, response) => {
148 response.writeHead(204)
149 response.end()
150 }
151 }, {
152 // Endpoint to follow progress
153 match: '^/_/progress(?:\\?page=([^&]*)(?:&test=([^&]*))?)?',
154 custom: (request, response, pageId, testId) => getJobProgress(job, request, response, pageId, testId)
155 }, {
156 // Endpoint to coverage files
157 match: '^/_/coverage/(.*)',
158 file: join(job.coverageReportDir, '$1')
159 }, {
160 // Endpoint to report
161 match: '^/_/report.html',
162 file: join(__dirname, 'report.html')
163 }, {
164 // Endpoint to report files
165 match: '^/_/(.*)',
166 file: join(job.reportDir, '$1')
167 }]
168 : []
169}