| 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 |