Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: chromium_process.js

Issue 29517687: Issue 5079, 5516 - Use webpack for browser tests, modules for content scripts (Closed)
Left Patch Set: Created Aug. 16, 2017, 3:40 p.m.
Right Patch Set: Addressed nits Created Aug. 17, 2017, 1:25 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « chrome/content/elemHideEmulation.js ('k') | lib/common.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
(...skipping 10 matching lines...) Expand all
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 extractZip = require("extract-zip");
30 const remoteInterface = require("chrome-remote-interface"); 30 const remoteInterface = require("chrome-remote-interface");
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.
33 31
34 const CHROMIUM_REVISION = 467222; 32 const CHROMIUM_REVISION = 467222;
35 33
36 function rmdir(dirPath) 34 function rmdir(dirPath)
37 { 35 {
38 for (let file of fs.readdirSync(dirPath)) 36 for (let file of fs.readdirSync(dirPath))
39 { 37 {
40 let filePath = path.join(dirPath, file); 38 let filePath = path.join(dirPath, file);
41 try 39 try
42 { 40 {
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 return new Promise((resolve, reject) => 241 return new Promise((resolve, reject) =>
244 { 242 {
245 setTimeout(() => 243 setTimeout(() =>
246 { 244 {
247 connectRemoteInterface(attempt + 1).then(resolve).catch(reject); 245 connectRemoteInterface(attempt + 1).then(resolve).catch(reject);
248 }, 200); 246 }, 200);
249 }); 247 });
250 }); 248 });
251 } 249 }
252 250
253 function webpackInMemory(bundleFilename, options) 251 function runScript(script, scriptName, scriptArgs)
254 { 252 {
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
299 return connectRemoteInterface().then(async client => 253 return connectRemoteInterface().then(async client =>
300 { 254 {
301 try 255 try
302 { 256 {
303 let {Runtime, Log, Console, Page} = client; 257 let {Runtime, Log, Console} = client;
304 258
305 await Log.enable(); 259 await Log.enable();
306 Log.entryAdded(({entry}) => 260 Log.entryAdded(({entry}) =>
307 { 261 {
308 reportMessage(entry.text, entry.level); 262 reportMessage(entry.text, entry.level);
309 }); 263 });
310 264
311 await Console.enable(); 265 await Console.enable();
312 Console.messageAdded(({message}) => 266 Console.messageAdded(({message}) =>
313 { 267 {
314 reportMessage(message.text, message.level); 268 reportMessage(message.text, message.level);
315 }); 269 });
316 270
317 await Page.navigate({url: initialPage});
318
319 await Runtime.enable(); 271 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
343 let compileResult = await Runtime.compileScript({ 272 let compileResult = await Runtime.compileScript({
344 expression: bundle, 273 expression: script,
345 sourceURL: bundleFilename, 274 sourceURL: scriptName,
346 persistScript: true 275 persistScript: true
347 }); 276 });
348 if (compileResult.exceptionDetails) 277 if (compileResult.exceptionDetails)
349 throwException(compileResult.exceptionDetails, bootstrapPath); 278 throwException(compileResult.exceptionDetails, scriptName);
350 279
351 let runResult = await Runtime.runScript({ 280 let runResult = await Runtime.runScript({
352 scriptId: compileResult.scriptId 281 scriptId: compileResult.scriptId
353 }); 282 });
354 if (runResult.exceptionDetails) 283 if (runResult.exceptionDetails)
355 throwException(runResult.exceptionDetails, bootstrapPath); 284 throwException(runResult.exceptionDetails, scriptName);
356 285
357 let callResult = await Runtime.callFunctionOn({ 286 let callResult = await Runtime.callFunctionOn({
358 objectId: runResult.result.objectId, 287 objectId: runResult.result.objectId,
359 functionDeclaration: "function(...modules) {return this(modules);}", 288 functionDeclaration: "function(...args) { return this(...args); }",
360 arguments: browserTestModules.map(module => ({value: module})) 289 arguments: scriptArgs.map(arg => ({value: arg}))
361 }); 290 });
362 if (callResult.exceptionDetails) 291 if (callResult.exceptionDetails)
363 throwException(callResult.exceptionDetails, bootstrapPath); 292 throwException(callResult.exceptionDetails, scriptName);
364 293
365 let promiseResult = await Runtime.awaitPromise({ 294 let promiseResult = await Runtime.awaitPromise({
366 promiseObjectId: callResult.result.objectId 295 promiseObjectId: callResult.result.objectId
367 }); 296 });
368 if (promiseResult.exceptionDetails) 297 if (promiseResult.exceptionDetails)
369 throwException(promiseResult.exceptionDetails, bootstrapPath); 298 throwException(promiseResult.exceptionDetails, scriptName);
370 } 299 }
371 finally 300 finally
372 { 301 {
373 client.close(); 302 client.close();
374 } 303 }
375 }); 304 });
376 } 305 }
377 306
378 module.exports = function(browserTestFiles) 307 module.exports = function(script, scriptName, ...scriptArgs)
379 { 308 {
380 return ensureChromium().then(chromiumPath => 309 return ensureChromium().then(chromiumPath =>
381 { 310 {
382 let child = startChromium(chromiumPath); 311 let child = startChromium(chromiumPath);
383 return Promise.race([ 312 return Promise.race([
384 child.done, 313 child.done,
385 runBrowserTests( 314 runScript(script, scriptName, scriptArgs)
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 )
390 ]).then(result => 315 ]).then(result =>
391 { 316 {
392 child.kill(); 317 child.kill();
393 return result; 318 return result;
394 }).catch(error => 319 }).catch(error =>
395 { 320 {
396 child.kill(); 321 child.kill();
397 throw error; 322 throw error;
398 }); 323 });
399 }); 324 });
400 }; 325 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld