diff --git a/lib/tasks/qunit.rake b/lib/tasks/qunit.rake index a80e443ed4a..813084da5e2 100644 --- a/lib/tasks/qunit.rake +++ b/lib/tasks/qunit.rake @@ -1,11 +1,11 @@ desc "Runs the qunit test suite" -task "qunit:test", [:timeout, :qunit_path] => :environment do |_, args| +task "qunit:test", [:timeout, :qunit_path, :use_chrome] => :environment do |_, args| require "rack" require "socket" - unless %x{which phantomjs > /dev/null 2>&1} + unless %x{which phantomjs > /dev/null 2>&1} || args[:use_chrome] abort "PhantomJS is not installed. Download from http://phantomjs.org" end @@ -36,7 +36,12 @@ task "qunit:test", [:timeout, :qunit_path] => :environment do |_, args| success = true test_path = "#{Rails.root}/vendor/assets/javascripts" qunit_path = args[:qunit_path] || "/qunit" - cmd = "phantomjs #{test_path}/run-qunit.js http://localhost:#{port}#{qunit_path}" + + if args[:use_chrome] + cmd = "node #{test_path}/run-qunit-chrome.js http://localhost:#{port}#{qunit_path}" + else + cmd = "phantomjs #{test_path}/run-qunit.js http://localhost:#{port}#{qunit_path}" + end options = {} diff --git a/vendor/assets/javascripts/run-qunit-chrome.js b/vendor/assets/javascripts/run-qunit-chrome.js new file mode 100644 index 00000000000..bbe194a91e4 --- /dev/null +++ b/vendor/assets/javascripts/run-qunit-chrome.js @@ -0,0 +1,164 @@ +// Chrome QUnit Test Runner +// Author: David Taylor +// Requires chrome-launcher and chrome-remote-interface from npm +// An up-to-date version of chrome is also required + +var args = process.argv.slice(2); + +if (args.length < 1 || args.length > 2) { + console.log("Usage: node run-qunit-chrome.js "); + process.exit(1); +} + +const chromeLauncher = require('chrome-launcher'); +const CDP = require('chrome-remote-interface'); + +(async function() { + + async function launchChrome() { + return await chromeLauncher.launch({ + chromeFlags: [ + '--disable-gpu', + '--headless' + ] + }); + } + const chrome = await launchChrome(); + const protocol = await CDP({ + port: chrome.port + }); + + const { + Page, + Runtime + } = protocol; + await Page.enable(); + await Runtime.enable(); + + Runtime.consoleAPICalled((response) => { + const message = response['args'][0].value; + + // If it's a simple test result, write without newline + if(message === "." || message === "F"){ + process.stdout.write(message); + }else{ + console.log(message); + } + }); + + Page.navigate({ + url: args[0] + }); + + Page.loadEventFired(async() => { + + await Runtime.evaluate({ + expression: `(${qunit_script})()` + }); + + const timeout = parseInt(args[1] || 300000, 10); + var start = Date.now(); + + var interval = setInterval(async() => { + if (Date.now() > start + timeout) { + console.error("Tests timed out"); + + protocol.close(); + chrome.kill(); + process.exit(124); + } else { + + const numFails = await Runtime.evaluate({ + expression: `(${check_script})()` + }); + + if (numFails.result.type !== 'undefined') { + clearInterval(interval); + protocol.close(); + chrome.kill(); + + if (numFails.value > 0) { + process.exit(1); + } else { + process.exit(); + } + } + } + }, 250); + + }); + +})(); + +// The following functions are converted to strings +// And then sent to chrome to be evalaluated +function logQUnit() { + var moduleErrors = []; + var testErrors = []; + var assertionErrors = []; + + console.log("\nRunning: " + JSON.stringify(QUnit.urlParams) + "\n"); + + QUnit.config.testTimeout = 10000; + + QUnit.moduleDone(function(context) { + if (context.failed) { + var msg = "Module Failed: " + context.name + "\n" + testErrors.join("\n"); + moduleErrors.push(msg); + testErrors = []; + } + }); + + QUnit.testDone(function(context) { + if (context.failed) { + var msg = " Test Failed: " + context.name + assertionErrors.join(" "); + testErrors.push(msg); + assertionErrors = []; + console.log("F"); + } else { + console.log("."); + } + }); + + QUnit.log(function(context) { + if (context.result) { return; } + + var msg = "\n Assertion Failed:"; + if (context.message) { + msg += " " + context.message; + } + + if (context.expected) { + msg += "\n Expected: " + context.expected + ", Actual: " + context.actual; + } + + assertionErrors.push(msg); + }); + + QUnit.done(function(context) { + console.log("\n"); + + if (moduleErrors.length > 0) { + for (var idx=0; idx