1 | 'use strict'
|
2 |
|
3 | const { join } = require('path')
|
4 | const { body } = require('reserve')
|
5 | const { extractPageUrl } = require('./tools')
|
6 | const { Request, Response } = require('reserve')
|
7 | const { getOutput } = require('./output')
|
8 | const { begin, testStart, log, testDone, done } = require('./qunit-hooks')
|
9 | const { addTestPages } = require('./add-test-pages')
|
10 | const { getJobProgress } = require('./get-job-progress')
|
11 | const { readFile } = require('fs/promises')
|
12 | const { TextEncoder } = require('util')
|
13 | const { resolveDependencyPath } = require('./npm.js')
|
14 |
|
15 | const punyexprBinPath = join(resolveDependencyPath('punyexpr'), 'dist/punyexpr.js')
|
16 | const punybindBinPath = join(resolveDependencyPath('punybind'), 'dist/punybind.js')
|
17 |
|
18 | module.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 |
|
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 |
|
73 | match: '^/_/addTestPages',
|
74 | custom: endpoint('addTestPages', (url, pages) => addTestPages(job, url, pages))
|
75 | }, {
|
76 |
|
77 | match: '^/_/qunit-hooks.js',
|
78 | file: join(__dirname, './inject/qunit-hooks.js')
|
79 | }, {
|
80 |
|
81 | match: /\/thirdparty\/(qunit(?:-2)?(?:-dbg)?\.js)/,
|
82 | custom: async function (request, response, scriptName) {
|
83 | if (request.internal) {
|
84 | return
|
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'
|
99 | })
|
100 | response.write(ui5Response.toString())
|
101 | response.end(inject)
|
102 | }
|
103 | }, {
|
104 |
|
105 | match: '^/_/QUnit/begin',
|
106 | custom: endpoint('QUnit/begin', (url, details) => begin(job, url, details))
|
107 | }, {
|
108 |
|
109 | match: '^/_/QUnit/testStart',
|
110 | custom: endpoint('QUnit/testStart', (url, details) => testStart(job, url, details))
|
111 | }, {
|
112 |
|
113 | match: '^/_/QUnit/log',
|
114 | custom: synchronousEndpoint('QUnit/log', async (url, report) => log(job, url, report))
|
115 | }, {
|
116 |
|
117 | match: '^/_/QUnit/testDone',
|
118 | custom: synchronousEndpoint('QUnit/testDone', async (url, report) => testDone(job, url, report))
|
119 | }, {
|
120 |
|
121 | match: '^/_/QUnit/done',
|
122 | custom: endpoint('QUnit/done', async (url, report) => done(job, url, report))
|
123 | }, {
|
124 |
|
125 | match: '^/_/progress.html',
|
126 | file: job.progressPage
|
127 | }, {
|
128 |
|
129 | match: '^/_/report/main.js',
|
130 | file: join(__dirname, 'defaults/report/progress.js')
|
131 | }, {
|
132 |
|
133 | match: '^/_/report/(.*)',
|
134 | file: join(__dirname, 'defaults/report/$1')
|
135 | }, {
|
136 |
|
137 | match: '^/_/punybind.js',
|
138 | file: punybindBinPath
|
139 | }, {
|
140 |
|
141 | match: '^/_/punyexpr.js',
|
142 | file: punyexprBinPath
|
143 | }, {
|
144 |
|
145 | method: 'INFO',
|
146 | match: '^/_/progress',
|
147 | custom: (request, response) => {
|
148 | response.writeHead(204)
|
149 | response.end()
|
150 | }
|
151 | }, {
|
152 |
|
153 | match: '^/_/progress(?:\\?page=([^&]*)(?:&test=([^&]*))?)?',
|
154 | custom: (request, response, pageId, testId) => getJobProgress(job, request, response, pageId, testId)
|
155 | }, {
|
156 |
|
157 | match: '^/_/coverage/(.*)',
|
158 | file: join(job.coverageReportDir, '$1')
|
159 | }, {
|
160 |
|
161 | match: '^/_/report.html',
|
162 | file: join(__dirname, 'report.html')
|
163 | }, {
|
164 |
|
165 | match: '^/_/(.*)',
|
166 | file: join(job.reportDir, '$1')
|
167 | }]
|
168 | : []
|
169 | }
|