Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2017 eyeo GmbH | 3 * Copyright (C) 2006-2017 eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 /* eslint-env node */ | 18 /* eslint-env node */ |
19 /* eslint no-console: "off" */ | 19 /* eslint no-console: "off" */ |
20 | 20 |
21 "use strict"; | 21 "use strict"; |
22 | 22 |
23 const childProcess = require("child_process"); | 23 const childProcess = require("child_process"); |
24 const fs = require("fs"); | 24 const fs = require("fs"); |
25 const https = require("https"); | 25 const https = require("https"); |
26 const os = require("os"); | 26 const os = require("os"); |
27 const path = require("path"); | 27 const path = require("path"); |
28 | 28 |
29 const extractZip = require("extract-zip"); | |
29 const remoteInterface = require("chrome-remote-interface"); | 30 const remoteInterface = require("chrome-remote-interface"); |
30 const extractZip = require("extract-zip"); | 31 const webpack = require("webpack"); |
32 const MemoryFS = require("memory-fs"); | |
Wladimir Palant
2017/08/17 10:05:38
I assume that this module exists because WebPack i
kzar
2017/08/17 12:40:21
Done.
| |
31 | 33 |
32 const CHROMIUM_REVISION = 467222; | 34 const CHROMIUM_REVISION = 467222; |
33 | 35 |
34 function rmdir(dirPath) | 36 function rmdir(dirPath) |
35 { | 37 { |
36 for (let file of fs.readdirSync(dirPath)) | 38 for (let file of fs.readdirSync(dirPath)) |
37 { | 39 { |
38 let filePath = path.join(dirPath, file); | 40 let filePath = path.join(dirPath, file); |
39 try | 41 try |
40 { | 42 { |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 return new Promise((resolve, reject) => | 243 return new Promise((resolve, reject) => |
242 { | 244 { |
243 setTimeout(() => | 245 setTimeout(() => |
244 { | 246 { |
245 connectRemoteInterface(attempt + 1).then(resolve).catch(reject); | 247 connectRemoteInterface(attempt + 1).then(resolve).catch(reject); |
246 }, 200); | 248 }, 200); |
247 }); | 249 }); |
248 }); | 250 }); |
249 } | 251 } |
250 | 252 |
251 function runBootstrap(initialPage, bootstrapPath, bootstrapArgs) | 253 function webpackInMemory(bundleFilename, options) |
252 { | 254 { |
255 // Based on this example https://webpack.js.org/api/node/#custom-file-systems | |
256 let memoryFS = new MemoryFS(); | |
257 | |
258 options.output = {filename: bundleFilename, path: "/"}; | |
259 let webpackCompiler = webpack(options); | |
260 webpackCompiler.outputFileSystem = memoryFS; | |
Wladimir Palant
2017/08/17 10:05:37
Nit: It's better to put all the statements above i
kzar
2017/08/17 12:40:21
Done.
| |
261 return new Promise((resolve, reject) => | |
262 { | |
263 webpackCompiler.run((err, stats) => | |
264 { | |
265 // Error handling is based on this example | |
266 // https://webpack.js.org/api/node/#error-handling | |
267 if (err) | |
268 { | |
269 let reason = err.stack || err; | |
270 if (err.details) | |
271 reason += "\n" + err.details; | |
272 reject(reason); | |
273 } | |
274 else if (stats.hasErrors()) | |
275 reject(stats.toJson().errors); | |
276 else | |
277 { | |
278 let bundle = memoryFS.readFileSync("/" + bundleFilename, "utf-8"); | |
279 memoryFS.unlink("/" + bundleFilename, () => { resolve(bundle); }); | |
Wladimir Palant
2017/08/17 10:05:38
Nit: Use memoryFS.unlinkSync() here to make this m
kzar
2017/08/17 12:40:21
Done.
| |
280 } | |
281 }); | |
282 }); | |
283 } | |
284 | |
285 function runBrowserTests(browserTestModules) | |
286 { | |
287 // We need to navigate to this directory because about:blank won't be allowed | |
288 // to load file:/// URLs. | |
289 let initialPage = require("url").format({ | |
290 protocol: "file", | |
291 slashes: "true", | |
292 pathname: path.resolve(process.cwd(), __dirname).split(path.sep).join("/") | |
293 }); | |
Wladimir Palant
2017/08/17 10:07:30
Actually, this shouldn't be necessary any more. Ru
kzar
2017/08/17 12:40:21
Done.
| |
294 | |
295 let bootstrapPath = path.join(__dirname, "test", "browser", "_bootstrap.js"); | |
296 let nodeunitPath = path.join(__dirname, "node_modules", "nodeunit", | |
297 "examples", "browser", "nodeunit.js"); | |
298 | |
253 return connectRemoteInterface().then(async client => | 299 return connectRemoteInterface().then(async client => |
254 { | 300 { |
255 try | 301 try |
256 { | 302 { |
257 let {Runtime, Log, Console, Page} = client; | 303 let {Runtime, Log, Console, Page} = client; |
258 | 304 |
259 await Log.enable(); | 305 await Log.enable(); |
260 Log.entryAdded(({entry}) => | 306 Log.entryAdded(({entry}) => |
261 { | 307 { |
262 reportMessage(entry.text, entry.level); | 308 reportMessage(entry.text, entry.level); |
263 }); | 309 }); |
264 | 310 |
265 await Console.enable(); | 311 await Console.enable(); |
266 Console.messageAdded(({message}) => | 312 Console.messageAdded(({message}) => |
267 { | 313 { |
268 reportMessage(message.text, message.level); | 314 reportMessage(message.text, message.level); |
269 }); | 315 }); |
270 | 316 |
271 await Page.navigate({url: initialPage}); | 317 await Page.navigate({url: initialPage}); |
272 | 318 |
273 await Runtime.enable(); | 319 await Runtime.enable(); |
320 | |
321 let bundleFilename = "bundle.js"; | |
322 let bundle = await webpackInMemory(bundleFilename, { | |
323 entry: bootstrapPath, | |
324 module: { | |
325 rules: [{ | |
326 resource: nodeunitPath, | |
327 // I would have rathered use exports-loader here, to avoid treating | |
Wladimir Palant
2017/08/17 10:05:37
"rather used"?
kzar
2017/08/17 12:40:21
Done.
| |
328 // nodeunit as a global. Unfortunately the nodeunit browser example | |
329 // script is quite slopily put together, if exports isn't falsey it | |
330 // breaks! As a workaround we need to use script-loader, which means | |
331 // that exports is falsey for that script as a side-effect. | |
332 use: ["script-loader"] | |
333 }] | |
334 }, | |
335 resolve: { | |
336 alias: { | |
337 nodeunit$: nodeunitPath | |
338 }, | |
339 modules: [path.resolve(__dirname, "lib")] | |
340 } | |
341 }); | |
342 | |
274 let compileResult = await Runtime.compileScript({ | 343 let compileResult = await Runtime.compileScript({ |
275 expression: fs.readFileSync(bootstrapPath, "utf-8"), | 344 expression: bundle, |
276 sourceURL: bootstrapPath, | 345 sourceURL: bundleFilename, |
277 persistScript: true | 346 persistScript: true |
278 }); | 347 }); |
279 if (compileResult.exceptionDetails) | 348 if (compileResult.exceptionDetails) |
280 throwException(compileResult.exceptionDetails, bootstrapPath); | 349 throwException(compileResult.exceptionDetails, bootstrapPath); |
281 | 350 |
282 let runResult = await Runtime.runScript({ | 351 let runResult = await Runtime.runScript({ |
283 scriptId: compileResult.scriptId | 352 scriptId: compileResult.scriptId |
284 }); | 353 }); |
285 if (runResult.exceptionDetails) | 354 if (runResult.exceptionDetails) |
286 throwException(runResult.exceptionDetails, bootstrapPath); | 355 throwException(runResult.exceptionDetails, bootstrapPath); |
287 | 356 |
288 let callResult = await Runtime.callFunctionOn({ | 357 let callResult = await Runtime.callFunctionOn({ |
289 objectId: runResult.result.objectId, | 358 objectId: runResult.result.objectId, |
290 functionDeclaration: "function(...args) {return this(...args);}", | 359 functionDeclaration: "function(...modules) {return this(modules);}", |
291 arguments: bootstrapArgs.map(url => ({value: url})) | 360 arguments: browserTestModules.map(module => ({value: module})) |
292 }); | 361 }); |
293 if (callResult.exceptionDetails) | 362 if (callResult.exceptionDetails) |
294 throwException(callResult.exceptionDetails, bootstrapPath); | 363 throwException(callResult.exceptionDetails, bootstrapPath); |
295 | 364 |
296 let promiseResult = await Runtime.awaitPromise({ | 365 let promiseResult = await Runtime.awaitPromise({ |
297 promiseObjectId: callResult.result.objectId | 366 promiseObjectId: callResult.result.objectId |
298 }); | 367 }); |
299 if (promiseResult.exceptionDetails) | 368 if (promiseResult.exceptionDetails) |
300 throwException(promiseResult.exceptionDetails, bootstrapPath); | 369 throwException(promiseResult.exceptionDetails, bootstrapPath); |
301 } | 370 } |
302 finally | 371 finally |
303 { | 372 { |
304 client.close(); | 373 client.close(); |
305 } | 374 } |
306 }); | 375 }); |
307 } | 376 } |
308 | 377 |
309 module.exports = function(initialPage, bootstrapPath, bootstrapArgs) | 378 module.exports = function(browserTestFiles) |
310 { | 379 { |
311 return ensureChromium().then(chromiumPath => | 380 return ensureChromium().then(chromiumPath => |
312 { | 381 { |
313 let child = startChromium(chromiumPath); | 382 let child = startChromium(chromiumPath); |
314 return Promise.race([ | 383 return Promise.race([ |
315 child.done, | 384 child.done, |
316 runBootstrap(initialPage, bootstrapPath, bootstrapArgs) | 385 runBrowserTests( |
386 browserTestFiles.map( | |
387 m => "." + path.sep + path.relative(path.join("test", "browser"), m) | |
Wladimir Palant
2017/08/17 10:05:37
The point here is generating a list of module name
kzar
2017/08/17 12:40:21
Done.
| |
388 ) | |
389 ) | |
317 ]).then(result => | 390 ]).then(result => |
318 { | 391 { |
319 child.kill(); | 392 child.kill(); |
320 return result; | 393 return result; |
321 }).catch(error => | 394 }).catch(error => |
322 { | 395 { |
323 child.kill(); | 396 child.kill(); |
324 throw error; | 397 throw error; |
325 }); | 398 }); |
326 }); | 399 }); |
327 }; | 400 }; |
OLD | NEW |