Index: test/runners/chromium_process.js |
=================================================================== |
rename from chromium_process.js |
rename to test/runners/chromium_process.js |
--- a/chromium_process.js |
+++ b/test/runners/chromium_process.js |
@@ -10,316 +10,51 @@ |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
-/* eslint-env node */ |
-/* eslint no-console: "off" */ |
- |
"use strict"; |
-const childProcess = require("child_process"); |
-const fs = require("fs"); |
-const https = require("https"); |
-const os = require("os"); |
-const path = require("path"); |
- |
-const remoteInterface = require("chrome-remote-interface"); |
-const extractZip = require("extract-zip"); |
- |
-const CHROMIUM_REVISION = 467222; |
+const {Builder} = require("selenium-webdriver"); |
+const chrome = require("selenium-webdriver/chrome"); |
+require("chromedriver"); |
-function rmdir(dirPath) |
-{ |
- for (let file of fs.readdirSync(dirPath)) |
- { |
- let filePath = path.join(dirPath, file); |
- try |
- { |
- if (fs.statSync(filePath).isDirectory()) |
- rmdir(filePath); |
- else |
- fs.unlinkSync(filePath); |
- } |
- catch (error) |
- { |
- console.error(error); |
- } |
- } |
- |
- try |
- { |
- fs.rmdirSync(dirPath); |
- } |
- catch (error) |
- { |
- console.error(error); |
- } |
-} |
- |
-function getChromiumExecutable(chromiumDir) |
-{ |
- switch (process.platform) |
- { |
- case "win32": |
- return path.join(chromiumDir, "chrome-win32", "chrome.exe"); |
- case "linux": |
- return path.join(chromiumDir, "chrome-linux", "chrome"); |
- case "darwin": |
- return path.join(chromiumDir, "chrome-mac", "Chromium.app", "Contents", |
- "MacOS", "Chromium"); |
- default: |
- throw new Error("Unexpected platform"); |
- } |
-} |
+const {executeScript} = require("./webdriver"); |
+const {ensureChromium} = require("./chromium_download"); |
-function ensureChromium() |
-{ |
- let {platform} = process; |
- if (platform == "win32") |
- platform += "-" + process.arch; |
- let buildTypes = { |
- "win32-ia32": ["Win", "chrome-win32.zip"], |
- "win32-x64": ["Win_x64", "chrome-win32.zip"], |
- "linux": ["Linux_x64", "chrome-linux.zip"], |
- "darwin": ["Mac", "chrome-mac.zip"] |
- }; |
- |
- if (!buildTypes.hasOwnProperty(platform)) |
- { |
- let err = new Error(`Cannot run browser tests, ${platform} is unsupported`); |
- return Promise.reject(err); |
- } |
- |
- |
- return Promise.resolve().then(() => |
- { |
- let snapshotsDir = path.join(__dirname, "chromium-snapshots"); |
- let chromiumDir = path.join(snapshotsDir, |
- `chromium-${platform}-${CHROMIUM_REVISION}`); |
- if (fs.existsSync(chromiumDir)) |
- return chromiumDir; |
- |
- if (!fs.existsSync(path.dirname(chromiumDir))) |
- fs.mkdirSync(path.dirname(chromiumDir)); |
- |
- let [dir, fileName] = buildTypes[platform]; |
- let archive = path.join(snapshotsDir, "download-cache", |
- `${CHROMIUM_REVISION}-${fileName}`); |
- |
- return Promise.resolve() |
- .then(() => |
- { |
- if (!fs.existsSync(archive)) |
- { |
- let url = `https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${dir}%2F${CHROMIUM_REVISION}%2F${fileName}?alt=media`; |
- console.info("Downloading Chromium..."); |
- return download(url, archive); |
- } |
- console.info(`Reusing cached archive ${archive}`); |
- }) |
- .then(() => unzipArchive(archive, chromiumDir)) |
- .then(() => chromiumDir); |
- }).then(dir => getChromiumExecutable(dir)); |
-} |
- |
-function download(url, destFile) |
-{ |
- return new Promise((resolve, reject) => |
- { |
- let cacheDir = path.dirname(destFile); |
- if (!fs.existsSync(cacheDir)) |
- fs.mkdirSync(cacheDir); |
- let tempDest = destFile + "-" + process.pid; |
- let writable = fs.createWriteStream(tempDest); |
- |
- https.get(url, response => |
- { |
- if (response.statusCode != 200) |
- { |
- reject( |
- new Error(`Unexpected server response: ${response.statusCode}`)); |
- response.resume(); |
- return; |
- } |
+// The Chromium version is a build number, quite obscure. |
+// Chromium 63.0.3239.x is 508578 |
+// Chromium 65.0.3325.0 is 530368 |
+// We currently want Chromiun 63, as we still support it and that's the |
+// loweset version that supports WebDriver. |
+const CHROMIUM_REVISION = 508578; |
- response.pipe(writable) |
- .on("error", error => |
- { |
- writable.close(); |
- fs.unlinkSync(tempDest); |
- reject(error); |
- }) |
- .on("close", () => |
- { |
- writable.close(); |
- fs.renameSync(tempDest, destFile); |
- resolve(); |
- }); |
- }).on("error", reject); |
- }); |
-} |
- |
-function unzipArchive(archive, destDir) |
-{ |
- return new Promise((resolve, reject) => |
- { |
- extractZip(archive, {dir: destDir}, err => |
- { |
- if (err) |
- reject(err); |
- else |
- resolve(); |
- }); |
- }); |
-} |
- |
-function startChromium(chromiumPath) |
-{ |
- fs.chmodSync(chromiumPath, fs.constants.S_IRWXU); |
- |
- let dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "chromium-data")); |
- let child = null; |
- return { |
- kill: () => child && child.kill(), |
- done: new Promise((resolve, reject) => |
- { |
- child = childProcess.execFile(chromiumPath, [ |
- "--headless", "--single-process", "--disable-gpu", "--no-sandbox", |
- "--allow-file-access-from-files", "--remote-debugging-port=9222", |
- "--user-data-dir=" + dataDir |
- ], error => |
- { |
- rmdir(dataDir); |
- if (error) |
- reject(error); |
- else |
- resolve(); |
- }); |
- }) |
- }; |
-} |
- |
-function throwException(details, url) |
-{ |
- let text = details.exception ? details.exception.description : details.text; |
- if (!details.stackTrace) |
- { |
- // ExceptionDetails uses zero-based line and column numbers. |
- text += `\n at ${details.url || url}:` + |
- (details.lineNumber + 1) + ":" + |
- (details.columnNumber + 1); |
- } |
- throw text; |
-} |
- |
-function reportMessage(text, level) |
+function runScript(chromiumPath, script, scriptName, scriptArgs) |
{ |
- let method = { |
- log: "log", |
- warning: "warn", |
- error: "error", |
- debug: "log", |
- info: "info" |
- }[level] || "log"; |
- console[method](text); |
-} |
- |
-function connectRemoteInterface(attempt) |
-{ |
- return remoteInterface().catch(error => |
- { |
- attempt = attempt || 1; |
- if (attempt > 50) |
- { |
- // Stop trying to connect after 10 seconds |
- throw error; |
- } |
- |
- return new Promise((resolve, reject) => |
- { |
- setTimeout(() => |
- { |
- connectRemoteInterface(attempt + 1).then(resolve).catch(reject); |
- }, 200); |
- }); |
- }); |
-} |
- |
-function runScript(script, scriptName, scriptArgs) |
-{ |
- return connectRemoteInterface().then(async client => |
- { |
- try |
- { |
- let {Runtime, Log, Console} = client; |
+ const options = new chrome.Options() |
+ .headless() |
+ .setChromeBinaryPath(chromiumPath); |
- await Log.enable(); |
- Log.entryAdded(({entry}) => |
- { |
- reportMessage(entry.text, entry.level); |
- }); |
- |
- await Console.enable(); |
- Console.messageAdded(({message}) => |
- { |
- reportMessage(message.text, message.level); |
- }); |
- |
- await Runtime.enable(); |
- let compileResult = await Runtime.compileScript({ |
- expression: script, |
- sourceURL: scriptName, |
- persistScript: true |
- }); |
- if (compileResult.exceptionDetails) |
- throwException(compileResult.exceptionDetails, scriptName); |
+ const driver = new Builder() |
+ .forBrowser("chrome") |
+ .setChromeOptions(options) |
+ .build(); |
- let runResult = await Runtime.runScript({ |
- scriptId: compileResult.scriptId |
- }); |
- if (runResult.exceptionDetails) |
- throwException(runResult.exceptionDetails, scriptName); |
- |
- let callResult = await Runtime.callFunctionOn({ |
- objectId: runResult.result.objectId, |
- functionDeclaration: "function(...args) { return this(...args); }", |
- arguments: scriptArgs.map(arg => ({value: arg})) |
- }); |
- if (callResult.exceptionDetails) |
- throwException(callResult.exceptionDetails, scriptName); |
- |
- let promiseResult = await Runtime.awaitPromise({ |
- promiseObjectId: callResult.result.objectId |
- }); |
- if (promiseResult.exceptionDetails) |
- throwException(promiseResult.exceptionDetails, scriptName); |
- } |
- finally |
- { |
- client.close(); |
- } |
- }); |
+ return executeScript(driver, "Chromium (WebDriver)", |
+ script, scriptName, scriptArgs); |
} |
module.exports = function(script, scriptName, ...scriptArgs) |
{ |
- return ensureChromium().then(chromiumPath => |
+ return ensureChromium(CHROMIUM_REVISION).then(chromiumPath => |
{ |
- let child = startChromium(chromiumPath); |
- return Promise.race([ |
- child.done, |
- runScript(script, scriptName, scriptArgs) |
- ]).then(result => |
- { |
- child.kill(); |
- return result; |
- }).catch(error => |
- { |
- child.kill(); |
- throw error; |
- }); |
+ return runScript(chromiumPath, script, scriptName, scriptArgs) |
+ .then(result => result) |
+ .catch(error => |
+ { |
+ throw error; |
+ }); |
}); |
}; |