Index: chromium_process.js |
diff --git a/chromium_process.js b/chromium_process.js |
index d6f9b82e93e85217e11b76da9cc07b13fc71552e..1a60fe2ca814437d5582b4e853ea10e1ebfacf09 100644 |
--- a/chromium_process.js |
+++ b/chromium_process.js |
@@ -26,8 +26,10 @@ const https = require("https"); |
const os = require("os"); |
const path = require("path"); |
-const remoteInterface = require("chrome-remote-interface"); |
const extractZip = require("extract-zip"); |
+const remoteInterface = require("chrome-remote-interface"); |
+const webpack = require("webpack"); |
+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.
|
const CHROMIUM_REVISION = 467222; |
@@ -248,8 +250,52 @@ function connectRemoteInterface(attempt) |
}); |
} |
-function runBootstrap(initialPage, bootstrapPath, bootstrapArgs) |
+function webpackInMemory(bundleFilename, options) |
+{ |
+ // Based on this example https://webpack.js.org/api/node/#custom-file-systems |
+ let memoryFS = new MemoryFS(); |
+ |
+ options.output = {filename: bundleFilename, path: "/"}; |
+ let webpackCompiler = webpack(options); |
+ 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.
|
+ return new Promise((resolve, reject) => |
+ { |
+ webpackCompiler.run((err, stats) => |
+ { |
+ // Error handling is based on this example |
+ // https://webpack.js.org/api/node/#error-handling |
+ if (err) |
+ { |
+ let reason = err.stack || err; |
+ if (err.details) |
+ reason += "\n" + err.details; |
+ reject(reason); |
+ } |
+ else if (stats.hasErrors()) |
+ reject(stats.toJson().errors); |
+ else |
+ { |
+ let bundle = memoryFS.readFileSync("/" + bundleFilename, "utf-8"); |
+ 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.
|
+ } |
+ }); |
+ }); |
+} |
+ |
+function runBrowserTests(browserTestModules) |
{ |
+ // We need to navigate to this directory because about:blank won't be allowed |
+ // to load file:/// URLs. |
+ let initialPage = require("url").format({ |
+ protocol: "file", |
+ slashes: "true", |
+ pathname: path.resolve(process.cwd(), __dirname).split(path.sep).join("/") |
+ }); |
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.
|
+ |
+ let bootstrapPath = path.join(__dirname, "test", "browser", "_bootstrap.js"); |
+ let nodeunitPath = path.join(__dirname, "node_modules", "nodeunit", |
+ "examples", "browser", "nodeunit.js"); |
+ |
return connectRemoteInterface().then(async client => |
{ |
try |
@@ -271,9 +317,32 @@ function runBootstrap(initialPage, bootstrapPath, bootstrapArgs) |
await Page.navigate({url: initialPage}); |
await Runtime.enable(); |
+ |
+ let bundleFilename = "bundle.js"; |
+ let bundle = await webpackInMemory(bundleFilename, { |
+ entry: bootstrapPath, |
+ module: { |
+ rules: [{ |
+ resource: nodeunitPath, |
+ // 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.
|
+ // nodeunit as a global. Unfortunately the nodeunit browser example |
+ // script is quite slopily put together, if exports isn't falsey it |
+ // breaks! As a workaround we need to use script-loader, which means |
+ // that exports is falsey for that script as a side-effect. |
+ use: ["script-loader"] |
+ }] |
+ }, |
+ resolve: { |
+ alias: { |
+ nodeunit$: nodeunitPath |
+ }, |
+ modules: [path.resolve(__dirname, "lib")] |
+ } |
+ }); |
+ |
let compileResult = await Runtime.compileScript({ |
- expression: fs.readFileSync(bootstrapPath, "utf-8"), |
- sourceURL: bootstrapPath, |
+ expression: bundle, |
+ sourceURL: bundleFilename, |
persistScript: true |
}); |
if (compileResult.exceptionDetails) |
@@ -287,8 +356,8 @@ function runBootstrap(initialPage, bootstrapPath, bootstrapArgs) |
let callResult = await Runtime.callFunctionOn({ |
objectId: runResult.result.objectId, |
- functionDeclaration: "function(...args) {return this(...args);}", |
- arguments: bootstrapArgs.map(url => ({value: url})) |
+ functionDeclaration: "function(...modules) {return this(modules);}", |
+ arguments: browserTestModules.map(module => ({value: module})) |
}); |
if (callResult.exceptionDetails) |
throwException(callResult.exceptionDetails, bootstrapPath); |
@@ -306,14 +375,18 @@ function runBootstrap(initialPage, bootstrapPath, bootstrapArgs) |
}); |
} |
-module.exports = function(initialPage, bootstrapPath, bootstrapArgs) |
+module.exports = function(browserTestFiles) |
{ |
return ensureChromium().then(chromiumPath => |
{ |
let child = startChromium(chromiumPath); |
return Promise.race([ |
child.done, |
- runBootstrap(initialPage, bootstrapPath, bootstrapArgs) |
+ runBrowserTests( |
+ browserTestFiles.map( |
+ 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.
|
+ ) |
+ ) |
]).then(result => |
{ |
child.kill(); |