|
4 | 4 | // npm install browser-ui-test
|
5 | 5 | // ```
|
6 | 6 |
|
7 |
| -const fs = require("fs"); |
8 | 7 | const path = require("path");
|
9 |
| -const os = require("os"); |
10 |
| -const {Options, runTest} = require("browser-ui-test"); |
11 |
| - |
12 |
| -function showHelp() { |
13 |
| - console.log("docs-rs-gui-js options:"); |
14 |
| - console.log(" --file [PATH] : file to run (can be repeated)"); |
15 |
| - console.log(" --debug : show extra information about script run"); |
16 |
| - console.log(" --show-text : render font in pages"); |
17 |
| - console.log(" --no-headless : disable headless mode"); |
18 |
| - console.log(" --help : show this message then quit"); |
19 |
| - console.log(" --jobs [NUMBER] : number of threads to run tests on"); |
20 |
| -} |
21 |
| - |
22 |
| -function isNumeric(s) { |
23 |
| - return /^\d+$/.test(s); |
24 |
| -} |
25 |
| - |
26 |
| -function parseOptions(args) { |
27 |
| - const opts = { |
28 |
| - "files": [], |
29 |
| - "debug": false, |
30 |
| - "show_text": false, |
31 |
| - "no_headless": false, |
32 |
| - "jobs": -1, |
33 |
| - }; |
34 |
| - const correspondences = { |
35 |
| - "--debug": "debug", |
36 |
| - "--show-text": "show_text", |
37 |
| - "--no-headless": "no_headless", |
38 |
| - }; |
39 |
| - |
40 |
| - for (let i = 0; i < args.length; ++i) { |
41 |
| - if (args[i] === "--file" |
42 |
| - || args[i] === "--jobs") { |
43 |
| - i += 1; |
44 |
| - if (i >= args.length) { |
45 |
| - console.log("Missing argument after `" + args[i - 1] + "` option."); |
46 |
| - return null; |
47 |
| - } |
48 |
| - if (args[i - 1] === "--jobs") { |
49 |
| - if (!isNumeric(args[i])) { |
50 |
| - console.log( |
51 |
| - "`--jobs` option expects a positive number, found `" + args[i] + "`"); |
52 |
| - return null; |
53 |
| - } |
54 |
| - opts["jobs"] = parseInt(args[i]); |
55 |
| - } else if (args[i - 1] !== "--file") { |
56 |
| - opts[correspondences[args[i - 1]]] = args[i]; |
57 |
| - } else { |
58 |
| - opts["files"].push(args[i]); |
59 |
| - } |
60 |
| - } else if (args[i] === "--help") { |
61 |
| - showHelp(); |
62 |
| - process.exit(0); |
63 |
| - } else if (correspondences[args[i]]) { |
64 |
| - opts[correspondences[args[i]]] = true; |
65 |
| - } else { |
66 |
| - console.log("Unknown option `" + args[i] + "`."); |
67 |
| - console.log("Use `--help` to see the list of options"); |
68 |
| - return null; |
69 |
| - } |
70 |
| - } |
71 |
| - return opts; |
72 |
| -} |
73 |
| - |
74 |
| -/// Print single char status information without \n |
75 |
| -function char_printer(n_tests) { |
76 |
| - const max_per_line = 10; |
77 |
| - let current = 0; |
78 |
| - return { |
79 |
| - successful: function() { |
80 |
| - current += 1; |
81 |
| - if (current % max_per_line === 0) { |
82 |
| - process.stdout.write(`. (${current}/${n_tests})${os.EOL}`); |
83 |
| - } else { |
84 |
| - process.stdout.write("."); |
85 |
| - } |
86 |
| - }, |
87 |
| - erroneous: function() { |
88 |
| - current += 1; |
89 |
| - if (current % max_per_line === 0) { |
90 |
| - process.stderr.write(`F (${current}/${n_tests})${os.EOL}`); |
91 |
| - } else { |
92 |
| - process.stderr.write("F"); |
93 |
| - } |
94 |
| - }, |
95 |
| - finish: function() { |
96 |
| - if (current % max_per_line === 0) { |
97 |
| - // Don't output if we are already at a matching line end |
98 |
| - console.log(""); |
99 |
| - } else { |
100 |
| - const spaces = " ".repeat(max_per_line - (current % max_per_line)); |
101 |
| - process.stdout.write(`${spaces} (${current}/${n_tests})${os.EOL}${os.EOL}`); |
102 |
| - } |
103 |
| - }, |
104 |
| - }; |
105 |
| -} |
106 |
| - |
107 |
| -/// Sort array by .file_name property |
108 |
| -function by_filename(a, b) { |
109 |
| - return a.file_name - b.file_name; |
110 |
| -} |
| 8 | +const spawn = require("child_process").spawn; |
111 | 9 |
|
112 | 10 | async function main(argv) {
|
113 |
| - const opts = parseOptions(argv.slice(2)); |
114 |
| - if (opts === null) { |
115 |
| - process.exit(1); |
116 |
| - } |
117 |
| - |
118 |
| - // Print successful tests too |
119 |
| - let debug = false; |
120 |
| - // Run tests in sequentially |
121 |
| - let headless = true; |
122 |
| - const options = new Options(); |
123 |
| - try { |
124 |
| - // This is more convenient that setting fields one by one. |
125 |
| - const args = []; |
126 |
| - if (typeof process.env.SERVER_URL !== "undefined") { |
127 |
| - args.push("--variable", "DOC_PATH", process.env.SERVER_URL); |
128 |
| - } else { |
129 |
| - args.push("--variable", "DOC_PATH", "http://127.0.0.1:3000"); |
| 11 | + let server = "http://127.0.0.1:3000"; |
| 12 | + if (typeof process.env.SERVER_URL !== "undefined") { |
| 13 | + server = process.env.SERVER_URL; |
| 14 | + } |
| 15 | + let nodeModulePath = "./node_modules"; |
| 16 | + if (typeof process.env.NODE_MODULE_PATH !== "undefined") { |
| 17 | + nodeModulePath = process.env.NODE_MODULE_PATH; |
| 18 | + } |
| 19 | + await spawn("node", [ |
| 20 | + path.join(nodeModulePath, "browser-ui-test/src/index.js"), |
| 21 | + "--display-format", |
| 22 | + "compact", |
| 23 | + "--variable", |
| 24 | + "DOC_PATH", |
| 25 | + server, |
| 26 | + "--test-folder", |
| 27 | + __dirname, |
| 28 | + ...argv.slice(2), |
| 29 | + ], {stdio: "inherit", stderr: "inherit"}).on("exit", code => { |
| 30 | + if (code !== 0) { |
| 31 | + process.exit(1); |
130 | 32 | }
|
131 |
| - if (opts["debug"]) { |
132 |
| - debug = true; |
133 |
| - args.push("--debug"); |
134 |
| - } |
135 |
| - if (opts["show_text"]) { |
136 |
| - args.push("--show-text"); |
137 |
| - } |
138 |
| - if (opts["no_headless"]) { |
139 |
| - args.push("--no-headless"); |
140 |
| - headless = false; |
141 |
| - } |
142 |
| - options.parseArguments(args); |
143 |
| - } catch (error) { |
144 |
| - console.error(`invalid argument: ${error}`); |
145 |
| - process.exit(1); |
146 |
| - } |
147 |
| - |
148 |
| - let failed = false; |
149 |
| - let files; |
150 |
| - if (opts["files"].length === 0) { |
151 |
| - files = fs.readdirSync(__dirname); |
152 |
| - } else { |
153 |
| - files = opts["files"]; |
154 |
| - } |
155 |
| - files = files.filter(file => path.extname(file) === ".goml"); |
156 |
| - if (files.length === 0) { |
157 |
| - console.error("No test selected"); |
158 |
| - process.exit(2); |
159 |
| - } |
160 |
| - files.sort(); |
161 |
| - |
162 |
| - if (!headless) { |
163 |
| - opts["jobs"] = 1; |
164 |
| - console.log("`--no-headless` option is active, disabling concurrency for running tests."); |
165 |
| - } |
166 |
| - let jobs = opts["jobs"]; |
167 |
| - |
168 |
| - if (opts["jobs"] < 1) { |
169 |
| - jobs = files.length; |
170 |
| - process.setMaxListeners(files.length + 1); |
171 |
| - } else if (headless) { |
172 |
| - process.setMaxListeners(opts["jobs"] + 1); |
173 |
| - } |
174 |
| - console.log(`Running ${files.length} docs.rs GUI (${jobs} concurrently) ...`); |
175 |
| - |
176 |
| - const tests_queue = []; |
177 |
| - const results = { |
178 |
| - successful: [], |
179 |
| - failed: [], |
180 |
| - errored: [], |
181 |
| - }; |
182 |
| - const status_bar = char_printer(files.length); |
183 |
| - for (let i = 0; i < files.length; ++i) { |
184 |
| - const file_name = files[i]; |
185 |
| - const testPath = path.join(__dirname, file_name); |
186 |
| - const callback = runTest(testPath, {"options": options}) |
187 |
| - .then(out => { |
188 |
| - const [output, nb_failures] = out; |
189 |
| - results[nb_failures === 0 ? "successful" : "failed"].push({ |
190 |
| - file_name: testPath, |
191 |
| - output: output, |
192 |
| - }); |
193 |
| - if (nb_failures > 0) { |
194 |
| - status_bar.erroneous(); |
195 |
| - failed = true; |
196 |
| - } else { |
197 |
| - status_bar.successful(); |
198 |
| - } |
199 |
| - }) |
200 |
| - .catch(err => { |
201 |
| - results.errored.push({ |
202 |
| - file_name: testPath + file_name, |
203 |
| - output: err, |
204 |
| - }); |
205 |
| - status_bar.erroneous(); |
206 |
| - failed = true; |
207 |
| - }) |
208 |
| - .finally(() => { |
209 |
| - // We now remove the promise from the tests_queue. |
210 |
| - tests_queue.splice(tests_queue.indexOf(callback), 1); |
211 |
| - }); |
212 |
| - tests_queue.push(callback); |
213 |
| - if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) { |
214 |
| - await Promise.race(tests_queue); |
215 |
| - } |
216 |
| - } |
217 |
| - if (tests_queue.length > 0) { |
218 |
| - await Promise.all(tests_queue); |
219 |
| - } |
220 |
| - status_bar.finish(); |
221 |
| - |
222 |
| - if (debug) { |
223 |
| - results.successful.sort(by_filename); |
224 |
| - results.successful.forEach(r => { |
225 |
| - console.log(r.output); |
226 |
| - }); |
227 |
| - } |
228 |
| - |
229 |
| - if (results.failed.length > 0) { |
230 |
| - console.log(""); |
231 |
| - results.failed.sort(by_filename); |
232 |
| - results.failed.forEach(r => { |
233 |
| - console.log(r.file_name, r.output); |
234 |
| - }); |
235 |
| - } |
236 |
| - if (results.errored.length > 0) { |
237 |
| - console.log(os.EOL); |
238 |
| - // print run errors on the bottom so developers see them better |
239 |
| - results.errored.sort(by_filename); |
240 |
| - results.errored.forEach(r => { |
241 |
| - console.error(r.file_name, r.output); |
242 |
| - }); |
243 |
| - } |
244 |
| - |
245 |
| - if (failed) { |
246 |
| - process.exit(1); |
247 |
| - } |
| 33 | + }); |
248 | 34 | }
|
249 | 35 |
|
250 | 36 | main(process.argv);
|
0 commit comments