Switch to chrome headless mode instead of phantomjs.
This commit is contained in:
parent
30ddc1f222
commit
6a4f391e38
3
Brewfile
3
Brewfile
|
@ -14,6 +14,3 @@ brew 'postgresql'
|
||||||
|
|
||||||
# install the Redis datastore
|
# install the Redis datastore
|
||||||
brew 'redis'
|
brew 'redis'
|
||||||
|
|
||||||
# install headless Javascript testing library
|
|
||||||
brew 'phantomjs'
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ To get your Ubuntu 16.04 LTS install up and running to develop Discourse and Dis
|
||||||
|
|
||||||
nvm install node
|
nvm install node
|
||||||
nvm alias default node
|
nvm alias default node
|
||||||
npm install -g svgo phantomjs-prebuilt
|
npm install -g svgo
|
||||||
|
|
||||||
|
|
||||||
If everything goes alright, let's clone Discourse and start hacking:
|
If everything goes alright, let's clone Discourse and start hacking:
|
||||||
|
|
|
@ -183,11 +183,11 @@ You should not need to alter `/usr/local/var/postgres/pg_hba.conf`
|
||||||
|
|
||||||
That's about it.
|
That's about it.
|
||||||
|
|
||||||
## PhantomJS
|
## Google Chrome 59+
|
||||||
|
|
||||||
Homebrew loves you.
|
Chrome is used for running QUnit tests in headless mode.
|
||||||
|
|
||||||
brew install phantomjs
|
Download from https://www.google.com/chrome/index.html
|
||||||
|
|
||||||
## ImageMagick
|
## ImageMagick
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,10 @@ module Autospec
|
||||||
|
|
||||||
require "socket"
|
require "socket"
|
||||||
|
|
||||||
class PhantomJsNotInstalled < StandardError; end
|
class ChromeNotInstalled < StandardError; end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
ensure_phantomjs_is_installed
|
ensure_chrome_is_installed
|
||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def start
|
||||||
|
@ -66,7 +66,7 @@ module Autospec
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cmd = "phantomjs #{Rails.root}/lib/autospec/run-qunit.js \"#{qunit_url}\""
|
cmd = "node #{Rails.root}/lib/autospec/run-qunit.js \"#{qunit_url}\""
|
||||||
|
|
||||||
@pid = Process.spawn(cmd)
|
@pid = Process.spawn(cmd)
|
||||||
_, status = Process.wait2(@pid)
|
_, status = Process.wait2(@pid)
|
||||||
|
@ -96,7 +96,6 @@ module Autospec
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop
|
def stop
|
||||||
# kill phantomjs first
|
|
||||||
abort
|
abort
|
||||||
stop_rails_server
|
stop_rails_server
|
||||||
@running = false
|
@running = false
|
||||||
|
@ -104,8 +103,12 @@ module Autospec
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ensure_phantomjs_is_installed
|
def ensure_chrome_is_installed
|
||||||
raise PhantomJsNotInstalled.new unless system("command -v phantomjs >/dev/null;")
|
raise ChromeNotInstalled.new unless system("command -v google-chrome >/dev/null;")
|
||||||
|
|
||||||
|
if Gem::Version.new(`$(command -v google-chrome) --version`.match(/[\d\.]+/)[0]) < Gem::Version.new("59")
|
||||||
|
raise "Chrome 59 or higher is required"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def port_available?(port)
|
def port_available?(port)
|
||||||
|
|
|
@ -1,182 +1,182 @@
|
||||||
/*jshint devel:true, phantom:true */
|
// Chrome QUnit Test Runner
|
||||||
/*globals QUnit ANSI */
|
// Author: David Taylor
|
||||||
|
// Requires chrome-launcher and chrome-remote-interface from npm
|
||||||
|
// An up-to-date version of chrome is also required
|
||||||
|
|
||||||
// THIS FILE IS CALLED BY "qunit_runner.rb" IN AUTOSPEC
|
/* globals Promise */
|
||||||
|
|
||||||
var system = require("system"),
|
var args = process.argv.slice(2);
|
||||||
args = phantom.args;
|
|
||||||
|
|
||||||
if (args === undefined) {
|
if (args.length < 1 || args.length > 2) {
|
||||||
args = system.args;
|
console.log("Usage: node run-qunit.js <URL> <timeout>");
|
||||||
args.shift();
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length !== 1) {
|
const chromeLauncher = require('chrome-launcher');
|
||||||
console.log("Usage: " + phantom.scriptName + " <URL>");
|
const CDP = require('chrome-remote-interface');
|
||||||
phantom.exit(1);
|
const fs = require('fs');
|
||||||
}
|
const QUNIT_RESULT = "./tmp/qunit_result";
|
||||||
|
|
||||||
var fs = require('fs'),
|
(async () => {
|
||||||
page = require('webpage').create(),
|
await fs.stat(QUNIT_RESULT, (err, stats) => {
|
||||||
QUNIT_RESULT = "./tmp/qunit_result";
|
if (stats && stats.isFile()) fs.unlink(QUNIT_RESULT);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
if (fs.exists(QUNIT_RESULT) && fs.isFile(QUNIT_RESULT)) { fs.remove(QUNIT_RESULT); }
|
(function() {
|
||||||
|
|
||||||
page.onConsoleMessage = function (message) {
|
function launchChrome() {
|
||||||
// filter out Ember's debug messages
|
return chromeLauncher.launch({
|
||||||
if (message.slice(0, 8) === "WARNING:") { return; }
|
chromeFlags: [
|
||||||
if (message.slice(0, 6) === "DEBUG:") { return; }
|
'--disable-gpu',
|
||||||
|
'--headless',
|
||||||
console.log(message);
|
'--no-sandbox'
|
||||||
};
|
]
|
||||||
|
});
|
||||||
page.onCallback = function (message) {
|
|
||||||
// write to the result file
|
|
||||||
if (message.slice(0, 5) === "FAIL:") {
|
|
||||||
fs.write(QUNIT_RESULT, message.slice(6) + "\n", "a");
|
|
||||||
}
|
}
|
||||||
// forward the message to the standard output
|
|
||||||
if (message.slice(0, 6) === "PRINT:") { system.stdout.write(message.slice(7)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
page.start = new Date();
|
launchChrome().then(chrome => {
|
||||||
|
CDP({
|
||||||
|
port: chrome.port
|
||||||
|
}).then(protocol => {
|
||||||
|
const {Page, Runtime} = protocol;
|
||||||
|
Promise.all([Page.enable(), Runtime.enable()]).then(()=>{
|
||||||
|
|
||||||
// -----------------------------------WARNING --------------------------------------
|
Runtime.consoleAPICalled((response) => {
|
||||||
// calling "console.log" BELOW this line will go through the "page.onConsoleMessage"
|
const message = response['args'][0].value;
|
||||||
// -----------------------------------WARNING --------------------------------------
|
|
||||||
page.open(args[0], function (status) {
|
|
||||||
if (status !== "success") {
|
|
||||||
console.log("\nNO NETWORK :(\n");
|
|
||||||
phantom.exit(1);
|
|
||||||
} else {
|
|
||||||
console.log("QUnit loaded in " + (new Date() - page.start) + " ms");
|
|
||||||
|
|
||||||
page.evaluate(colorizer);
|
// If it's a simple test result, write without newline
|
||||||
page.evaluate(logQUnit);
|
if (message === "." || message === "F") {
|
||||||
|
process.stdout.write(message);
|
||||||
// wait up to 600 seconds for QUnit to finish
|
} else if (message.startsWith("AUTOSPEC:")) {
|
||||||
var timeout = 600 * 1000,
|
fs.appendFileSync(QUNIT_RESULT, `${message.slice(10)}\n`);
|
||||||
start = Date.now();
|
|
||||||
|
|
||||||
var interval = setInterval(function() {
|
|
||||||
if (Date.now() - start > timeout) {
|
|
||||||
console.error("\nTIME OUT :(\n");
|
|
||||||
phantom.exit(1);
|
|
||||||
} else {
|
|
||||||
var qunitResult = page.evaluate(function() { return window.qunitResult; });
|
|
||||||
if (qunitResult) {
|
|
||||||
clearInterval(interval);
|
|
||||||
if (qunitResult.failed > 0) {
|
|
||||||
phantom.exit(1);
|
|
||||||
} else {
|
} else {
|
||||||
phantom.exit(0);
|
console.log(message);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// https://github.com/jquery/qunit/pull/470
|
Page.navigate({
|
||||||
function colorizer() {
|
url: args[0]
|
||||||
window.ANSI = {
|
});
|
||||||
colorMap: {
|
|
||||||
"red": "\u001b[31m",
|
|
||||||
"green": "\u001b[32m",
|
|
||||||
"blue": "\u001b[34m",
|
|
||||||
"end": "\u001b[0m"
|
|
||||||
},
|
|
||||||
highlightMap: {
|
|
||||||
"red": "\u001b[41m\u001b[37m", // change 37 to 30 for black text
|
|
||||||
"green": "\u001b[42m\u001b[30m",
|
|
||||||
"blue": "\u001b[44m\u001b[37m",
|
|
||||||
"end": "\u001b[0m"
|
|
||||||
},
|
|
||||||
|
|
||||||
highlight: function (text, color) {
|
Page.loadEventFired(() => {
|
||||||
var colorCode = this.highlightMap[color],
|
|
||||||
colorEnd = this.highlightMap.end;
|
|
||||||
|
|
||||||
return colorCode + text + colorEnd;
|
Runtime.evaluate({
|
||||||
},
|
expression: `(${qunit_script})()`
|
||||||
|
}).then(() => {
|
||||||
|
const timeout = parseInt(args[1] || 300000, 10);
|
||||||
|
var start = Date.now();
|
||||||
|
|
||||||
colorize: function (text, color) {
|
var interval = setInterval(() => {
|
||||||
var colorCode = this.colorMap[color],
|
if (Date.now() > start + timeout) {
|
||||||
colorEnd = this.colorMap.end;
|
console.error("Tests timed out");
|
||||||
|
|
||||||
return colorCode + text + colorEnd;
|
protocol.close();
|
||||||
}
|
chrome.kill();
|
||||||
|
process.exit(124);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Runtime.evaluate({
|
||||||
|
expression: `(${check_script})()`
|
||||||
|
}).then(numFails => {
|
||||||
|
if (numFails.result.type !== 'undefined') {
|
||||||
|
clearInterval(interval);
|
||||||
|
protocol.close();
|
||||||
|
chrome.kill();
|
||||||
|
|
||||||
|
if (numFails.result.value > 0) {
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(error);
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
}).catch(error(1));
|
||||||
|
});
|
||||||
|
}).catch(error(3));
|
||||||
|
}).catch(error(4));
|
||||||
|
}).catch(error(5));
|
||||||
|
})();
|
||||||
|
|
||||||
|
function error(code){
|
||||||
|
return function(){
|
||||||
|
console.log("A promise failed to resolve code:"+code);
|
||||||
|
process.exit(1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following functions are converted to strings
|
||||||
|
// And then sent to chrome to be evalaluated
|
||||||
function logQUnit() {
|
function logQUnit() {
|
||||||
// keep track of error messages
|
var moduleErrors = [];
|
||||||
var errors = {};
|
var testErrors = [];
|
||||||
|
var assertionErrors = [];
|
||||||
|
|
||||||
QUnit.begin(function () {
|
console.log("\nRunning: " + JSON.stringify(QUnit.urlParams) + "\n");
|
||||||
console.log("BEGIN");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.log(function (context) {
|
QUnit.config.testTimeout = 10000;
|
||||||
if (!context.result) {
|
|
||||||
var module = context.module,
|
|
||||||
test = context.name;
|
|
||||||
|
|
||||||
var assertion = {
|
QUnit.moduleDone(function(context) {
|
||||||
message: context.message,
|
if (context.failed) {
|
||||||
expected: context.expected,
|
var msg = "Module Failed: " + context.name + "\n" + testErrors.join("\n");
|
||||||
actual: context.actual
|
moduleErrors.push(msg);
|
||||||
};
|
testErrors = [];
|
||||||
|
|
||||||
if (!errors[module]) { errors[module] = {}; }
|
|
||||||
if (!errors[module][test]) { errors[module][test] = []; }
|
|
||||||
errors[module][test].push(assertion);
|
|
||||||
|
|
||||||
window.callPhantom("FAIL: " + context.module + ":::" + context.testId + ":::" + context.name);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.testDone(function (context) {
|
QUnit.testDone(function(context) {
|
||||||
if (context.failed > 0) {
|
if (context.failed) {
|
||||||
window.callPhantom("PRINT: " + ANSI.colorize("F", "red"));
|
var msg = " Test Failed: " + context.name + assertionErrors.join(" ");
|
||||||
|
console.log(`AUTOSPEC: ${context.module}:::${context.testId}:::${context.name}`);
|
||||||
|
testErrors.push(msg);
|
||||||
|
assertionErrors = [];
|
||||||
|
console.log("F");
|
||||||
} else {
|
} else {
|
||||||
window.callPhantom("PRINT: " + ANSI.colorize(".", "green"));
|
console.log(".");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.done(function (context) {
|
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");
|
console.log("\n");
|
||||||
|
|
||||||
// display failures
|
if (moduleErrors.length > 0) {
|
||||||
if (Object.keys(errors).length > 0) {
|
for (var idx=0; idx<moduleErrors.length; idx++) {
|
||||||
console.log("Failures:\n");
|
console.error(moduleErrors[idx]+"\n");
|
||||||
for (var m in errors) {
|
|
||||||
var module = errors[m];
|
|
||||||
console.log("Module Failed: " + ANSI.highlight(m, "red"));
|
|
||||||
for (var t in module) {
|
|
||||||
var test = module[t];
|
|
||||||
console.log(" Test Failed: " + t);
|
|
||||||
for (var a = 0; a < test.length; a++) {
|
|
||||||
var assertion = test[a];
|
|
||||||
console.log(" Assertion Failed: " + (assertion.message || ""));
|
|
||||||
if (assertion.expected) {
|
|
||||||
console.log(" Expected: " + assertion.expected);
|
|
||||||
console.log(" Actual: " + assertion.actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// display summary
|
var stats = [
|
||||||
console.log("\n");
|
"Time: " + context.runtime + "ms",
|
||||||
console.log("Finished in " + (context.runtime / 1000) + " seconds");
|
"Total: " + context.total,
|
||||||
var color = context.failed > 0 ? "red" : "green";
|
"Passed: " + context.passed,
|
||||||
console.log(ANSI.colorize(context.total + " examples, " + context.failed + " failures", color));
|
"Failed: " + context.failed
|
||||||
|
];
|
||||||
// we're done
|
console.log(stats.join(", "));
|
||||||
window.qunitResult = context;
|
window.qunitDone = context;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const qunit_script = logQUnit.toString();
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
if(window.qunitDone){
|
||||||
|
return window.qunitDone.failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const check_script = check.toString();
|
||||||
|
|
|
@ -5,10 +5,20 @@ task "qunit:test", [:timeout, :qunit_path] => :environment do |_, args|
|
||||||
require "rack"
|
require "rack"
|
||||||
require "socket"
|
require "socket"
|
||||||
|
|
||||||
unless %x{which phantomjs > /dev/null 2>&1} || ENV["USE_CHROME"]
|
unless system("command -v google-chrome >/dev/null;")
|
||||||
abort "PhantomJS is not installed. Download from http://phantomjs.org"
|
abort "Chrome is not installed. Download from https://www.google.com/chrome/browser/desktop/index.html"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Gem::Version.new(`$(command -v google-chrome) --version`.match(/[\d\.]+/)[0]) < Gem::Version.new("59")
|
||||||
|
abort "Chrome 59 or higher is required to run tests in headless mode."
|
||||||
|
end
|
||||||
|
|
||||||
|
unless system("command -v yarn >/dev/null;")
|
||||||
|
abort "Yarn is not installed. Download from https://yarnpkg.com/lang/en/docs/install/"
|
||||||
|
end
|
||||||
|
|
||||||
|
system("yarn install --dev")
|
||||||
|
|
||||||
# ensure we have this port available
|
# ensure we have this port available
|
||||||
def port_available?(port)
|
def port_available?(port)
|
||||||
server = TCPServer.open port
|
server = TCPServer.open port
|
||||||
|
@ -36,13 +46,7 @@ task "qunit:test", [:timeout, :qunit_path] => :environment do |_, args|
|
||||||
success = true
|
success = true
|
||||||
test_path = "#{Rails.root}/vendor/assets/javascripts"
|
test_path = "#{Rails.root}/vendor/assets/javascripts"
|
||||||
qunit_path = args[:qunit_path] || "/qunit"
|
qunit_path = args[:qunit_path] || "/qunit"
|
||||||
|
cmd = "node #{test_path}/run-qunit.js http://localhost:#{port}#{qunit_path}"
|
||||||
if ENV["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 = {}
|
options = {}
|
||||||
|
|
||||||
%w{module filter qunit_skip_core qunit_single_plugin}.each do |arg|
|
%w{module filter qunit_skip_core qunit_single_plugin}.each do |arg|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
desc "run phantomjs based smoke tests on current build"
|
desc "run chrome headless smoke tests on current build"
|
||||||
task "smoke:test" do
|
task "smoke:test" do
|
||||||
phantom_path = File.expand_path('~/phantomjs/bin/phantomjs')
|
unless system("command -v google-chrome >/dev/null;")
|
||||||
phantom_path = nil unless File.exists?(phantom_path)
|
abort "Chrome is not installed. Download from https://www.google.com/chrome/browser/desktop/index.html"
|
||||||
phantom_path = phantom_path || 'phantomjs'
|
end
|
||||||
|
|
||||||
|
if Gem::Version.new(`$(command -v google-chrome) --version`.match(/[\d\.]+/)[0]) < Gem::Version.new("59")
|
||||||
|
abort "Chrome 59 or higher is required to run smoke tests in headless mode."
|
||||||
|
end
|
||||||
|
|
||||||
url = ENV["URL"]
|
url = ENV["URL"]
|
||||||
if !url
|
if !url
|
||||||
|
@ -32,12 +36,7 @@ task "smoke:test" do
|
||||||
|
|
||||||
results = ""
|
results = ""
|
||||||
|
|
||||||
command =
|
"node #{Rails.root}/test/smoke_test.js #{url}"
|
||||||
if ENV["USE_CHROME"]
|
|
||||||
"node #{Rails.root}/test/smoke_test.js #{url}"
|
|
||||||
else
|
|
||||||
"#{phantom_path} #{Rails.root}/spec/phantom_js/smoke_test.js #{url}"
|
|
||||||
end
|
|
||||||
|
|
||||||
IO.popen(command).each do |line|
|
IO.popen(command).each do |line|
|
||||||
puts line
|
puts line
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
/*global phantom:true */
|
|
||||||
|
|
||||||
console.log("Starting Discourse Smoke Test");
|
|
||||||
|
|
||||||
var system = require("system");
|
|
||||||
|
|
||||||
if (system.args.length !== 2) {
|
|
||||||
console.log("Expecting: phantomjs {smoke_test.js} {url}");
|
|
||||||
phantom.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
var TIMEOUT = 25000;
|
|
||||||
var page = require("webpage").create();
|
|
||||||
|
|
||||||
if (system.env["AUTH_USER"] && system.env["AUTH_PASSWORD"]) {
|
|
||||||
page.settings.userName = system.env["AUTH_USER"];
|
|
||||||
page.settings.password = system.env["AUTH_PASSWORD"];
|
|
||||||
}
|
|
||||||
|
|
||||||
page.viewportSize = {
|
|
||||||
width: 1366,
|
|
||||||
height: 768
|
|
||||||
};
|
|
||||||
|
|
||||||
// In the browser, when the cookies are disabled, it also disables the localStorage
|
|
||||||
// Here, we're mocking that behavior and making sure the application doesn't blow up
|
|
||||||
page.onInitialized = function() {
|
|
||||||
page.evaluate(function() {
|
|
||||||
localStorage["disableLocalStorage"] = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
page.onConsoleMessage = function(msg) {
|
|
||||||
console.log(msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
page.waitFor = function(desc, fn, cb) {
|
|
||||||
var start = +new Date();
|
|
||||||
|
|
||||||
var check = function() {
|
|
||||||
var r;
|
|
||||||
|
|
||||||
try { r = page.evaluate(fn); } catch (err) { }
|
|
||||||
|
|
||||||
var diff = (+new Date()) - start;
|
|
||||||
|
|
||||||
if (r) {
|
|
||||||
console.log("PASSED: " + desc + " - " + diff + "ms");
|
|
||||||
cb(true);
|
|
||||||
} else {
|
|
||||||
if (diff > TIMEOUT) {
|
|
||||||
console.log("FAILED: " + desc + " - " + diff + "ms");
|
|
||||||
page.render('/tmp/failed.png');
|
|
||||||
console.log('Content:' + page.content);
|
|
||||||
cb(false);
|
|
||||||
} else {
|
|
||||||
setTimeout(check, 25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
check();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var actions = [];
|
|
||||||
|
|
||||||
function test(desc, fn) {
|
|
||||||
actions.push({ test: fn, desc: desc });
|
|
||||||
};
|
|
||||||
|
|
||||||
// function wait(delay) {
|
|
||||||
// actions.push({ wait: delay });
|
|
||||||
// }
|
|
||||||
|
|
||||||
function exec(desc, fn) {
|
|
||||||
actions.push({ exec: fn, desc: desc });
|
|
||||||
};
|
|
||||||
|
|
||||||
function execAsync(desc, delay, fn) {
|
|
||||||
actions.push({ execAsync: fn, delay: delay, desc: desc });
|
|
||||||
};
|
|
||||||
|
|
||||||
// function upload(input, path) {
|
|
||||||
// actions.push({ upload: path, input: input });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// function screenshot(filename) {
|
|
||||||
// actions.push({ screenshot: filename });
|
|
||||||
// }
|
|
||||||
|
|
||||||
function run() {
|
|
||||||
var allPassed = true;
|
|
||||||
|
|
||||||
var done = function() {
|
|
||||||
console.log(allPassed ? "ALL PASSED" : "SMOKE TEST FAILED");
|
|
||||||
phantom.exit();
|
|
||||||
};
|
|
||||||
|
|
||||||
var performNextAction = function() {
|
|
||||||
if (!allPassed || actions.length === 0) {
|
|
||||||
done();
|
|
||||||
} else {
|
|
||||||
var action = actions[0];
|
|
||||||
actions = actions.splice(1);
|
|
||||||
if (action.test) {
|
|
||||||
page.waitFor(action.desc, action.test, function(success) {
|
|
||||||
allPassed = allPassed && success;
|
|
||||||
performNextAction();
|
|
||||||
});
|
|
||||||
} else if (action.exec) {
|
|
||||||
console.log("EXEC: " + action.desc);
|
|
||||||
page.evaluate(action.exec, system);
|
|
||||||
performNextAction();
|
|
||||||
} else if (action.execAsync) {
|
|
||||||
console.log("EXEC ASYNC: " + action.desc + " - " + action.delay + "ms");
|
|
||||||
setTimeout(function() {
|
|
||||||
page.evaluate(action.execAsync);
|
|
||||||
performNextAction();
|
|
||||||
}, action.delay);
|
|
||||||
} else if (action.upload) {
|
|
||||||
console.log("UPLOAD: " + action.upload);
|
|
||||||
page.uploadFile(action.input, action.upload);
|
|
||||||
performNextAction();
|
|
||||||
} else if (action.screenshot) {
|
|
||||||
console.log("SCREENSHOT: " + action.screenshot);
|
|
||||||
page.render(action.screenshot);
|
|
||||||
performNextAction();
|
|
||||||
} else if (action.wait) {
|
|
||||||
console.log("WAIT: " + action.wait + "ms");
|
|
||||||
setTimeout(function() {
|
|
||||||
performNextAction();
|
|
||||||
}, action.wait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
performNextAction();
|
|
||||||
};
|
|
||||||
|
|
||||||
var runTests = function() {
|
|
||||||
|
|
||||||
test("expect a log in button in the header", function() {
|
|
||||||
return $("header .login-button").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
execAsync("go to latest page", 500, function(){
|
|
||||||
window.location = "/latest";
|
|
||||||
});
|
|
||||||
|
|
||||||
test("at least one topic shows up", function() {
|
|
||||||
return $(".topic-list tbody tr").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
execAsync("go to categories page", 500, function(){
|
|
||||||
window.location = "/categories";
|
|
||||||
});
|
|
||||||
|
|
||||||
test("can see categories on the page", function() {
|
|
||||||
return $('.category-list').length;
|
|
||||||
});
|
|
||||||
|
|
||||||
execAsync("navigate to 1st topic", 500, function() {
|
|
||||||
$(".main-link a.title:first").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("at least one post body", function() {
|
|
||||||
return $(".topic-post").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
execAsync("click on the 1st user", 500, function() {
|
|
||||||
// remove the popup action for testing
|
|
||||||
$(".topic-meta-data a:first").data("ember-action", "");
|
|
||||||
$(".topic-meta-data a:first").focus().click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("user has details", function() {
|
|
||||||
return $("#user-card .names").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!system.env["READONLY_TESTS"]) {
|
|
||||||
exec("open login modal", function() {
|
|
||||||
$(".login-button").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("login modal is open", function() {
|
|
||||||
return $(".login-modal").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("type in credentials & log in", function(system) {
|
|
||||||
$("#login-account-name").val(system.env['DISCOURSE_USERNAME'] || 'smoke_user').trigger("change");
|
|
||||||
$("#login-account-password").val(system.env["DISCOURSE_PASSWORD"] || 'P4ssw0rd').trigger("change");
|
|
||||||
$(".login-modal .btn-primary").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("is logged in", function() {
|
|
||||||
return $(".current-user").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("go home", function() {
|
|
||||||
if ($('#site-logo').length) $('#site-logo').click();
|
|
||||||
if ($('#site-text-logo').length) $('#site-text-logo').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("it shows a topic list", function() {
|
|
||||||
return $(".topic-list").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
test('we have a create topic button', function() {
|
|
||||||
return $("#create-topic").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("open composer", function() {
|
|
||||||
$("#create-topic").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('the editor is visible', function() {
|
|
||||||
return $(".d-editor").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("compose new topic", function() {
|
|
||||||
var date = " (" + (+new Date()) + ")",
|
|
||||||
title = "This is a new topic" + date,
|
|
||||||
post = "I can write a new topic inside the smoke test!" + date + "\n\n";
|
|
||||||
|
|
||||||
$("#reply-title").val(title).trigger("change");
|
|
||||||
$("#reply-control .d-editor-input").val(post).trigger("change");
|
|
||||||
$("#reply-control .d-editor-input").focus()[0].setSelectionRange(post.length, post.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("updates preview", function() {
|
|
||||||
return $(".d-editor-preview p").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("open upload modal", function() {
|
|
||||||
$(".d-editor-button-bar .upload").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("upload modal is open", function() {
|
|
||||||
return $("#filename-input").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Looks like PhantomJS 2.0.0 has a bug with `uploadFile`
|
|
||||||
// which breaks this code.
|
|
||||||
|
|
||||||
// upload("#filename-input", "spec/fixtures/images/large & unoptimized.png");
|
|
||||||
// test("the file is inserted into the input", function() {
|
|
||||||
// return document.getElementById('filename-input').files.length
|
|
||||||
// });
|
|
||||||
// screenshot('/tmp/upload-modal.png');
|
|
||||||
//
|
|
||||||
// test("upload modal is open", function() {
|
|
||||||
// return document.querySelector("#filename-input");
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// exec("click upload button", function() {
|
|
||||||
// $(".modal .btn-primary").click();
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// test("image is uploaded", function() {
|
|
||||||
// return document.querySelector(".cooked img");
|
|
||||||
// });
|
|
||||||
|
|
||||||
exec("submit the topic", function() {
|
|
||||||
$("#reply-control .create").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("topic is created", function() {
|
|
||||||
return $(".fancy-title").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("click reply button", function() {
|
|
||||||
$(".post-controls:first .create").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("composer is open", function() {
|
|
||||||
return $("#reply-control .d-editor-input").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
exec("compose reply", function() {
|
|
||||||
var post = "I can even write a reply inside the smoke test ;) (" + (+new Date()) + ")";
|
|
||||||
$("#reply-control .d-editor-input").val(post).trigger("change");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("waiting for the preview", function() {
|
|
||||||
return $(".d-editor-preview").text().trim().indexOf("I can even write") === 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
execAsync("submit the reply", 6000, function() {
|
|
||||||
$("#reply-control .create").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("reply is created", function() {
|
|
||||||
return !document.querySelector(".saving-text")
|
|
||||||
&& $(".topic-post").length === 2;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
};
|
|
||||||
|
|
||||||
phantom.clearCookies();
|
|
||||||
page.open(system.args[1], function() {
|
|
||||||
page.evaluate(function() { localStorage.clear(); });
|
|
||||||
console.log("OPENED: " + system.args[1]);
|
|
||||||
runTests();
|
|
||||||
});
|
|
|
@ -38,11 +38,10 @@ QUnit.test("Updating topic notification level", assert => {
|
||||||
"it should display the right notification level"
|
"it should display the right notification level"
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: tgxworld I can't figure out why the topic timeline doesn't show when
|
assert.equal(
|
||||||
// running the tests in phantomjs
|
find(`.timeline-footer-controls .select-kit-header`).data().name,
|
||||||
// ok(
|
'Watching',
|
||||||
// exists(".timeline-footer-controls .notifications-button .watching"),
|
'it should display the right notification level in topic timeline'
|
||||||
// 'it should display the right notification level in topic timeline'
|
);
|
||||||
// );
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -62209,13 +62209,6 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
"test": false,
|
"test": false,
|
||||||
"throws": false
|
"throws": false
|
||||||
},
|
},
|
||||||
"phantomjs": {
|
|
||||||
"console": true,
|
|
||||||
"exports": true,
|
|
||||||
"phantom": true,
|
|
||||||
"require": true,
|
|
||||||
"WebPage": true
|
|
||||||
},
|
|
||||||
"couch": {
|
"couch": {
|
||||||
"emit": false,
|
"emit": false,
|
||||||
"exports": false,
|
"exports": false,
|
||||||
|
|
|
@ -1,171 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
/* globals Promise */
|
|
||||||
|
|
||||||
var args = process.argv.slice(2);
|
|
||||||
|
|
||||||
if (args.length < 1 || args.length > 2) {
|
|
||||||
console.log("Usage: node run-qunit-chrome.js <URL> <timeout>");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const chromeLauncher = require('chrome-launcher');
|
|
||||||
const CDP = require('chrome-remote-interface');
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
function launchChrome() {
|
|
||||||
return chromeLauncher.launch({
|
|
||||||
chromeFlags: [
|
|
||||||
'--disable-gpu',
|
|
||||||
'--headless',
|
|
||||||
'--no-sandbox'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
launchChrome().then(chrome => {
|
|
||||||
CDP({
|
|
||||||
port: chrome.port
|
|
||||||
}).then(protocol => {
|
|
||||||
const {Page, Runtime} = protocol;
|
|
||||||
Promise.all([Page.enable(), Runtime.enable()]).then(()=>{
|
|
||||||
|
|
||||||
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(() => {
|
|
||||||
|
|
||||||
Runtime.evaluate({
|
|
||||||
expression: `(${qunit_script})()`
|
|
||||||
}).then(() => {
|
|
||||||
const timeout = parseInt(args[1] || 300000, 10);
|
|
||||||
var start = Date.now();
|
|
||||||
|
|
||||||
var interval = setInterval(() => {
|
|
||||||
if (Date.now() > start + timeout) {
|
|
||||||
console.error("Tests timed out");
|
|
||||||
|
|
||||||
protocol.close();
|
|
||||||
chrome.kill();
|
|
||||||
process.exit(124);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Runtime.evaluate({
|
|
||||||
expression: `(${check_script})()`
|
|
||||||
}).then(numFails => {
|
|
||||||
if (numFails.result.type !== 'undefined') {
|
|
||||||
clearInterval(interval);
|
|
||||||
protocol.close();
|
|
||||||
chrome.kill();
|
|
||||||
|
|
||||||
if (numFails.result.value > 0) {
|
|
||||||
process.exit(1);
|
|
||||||
} else {
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).catch(error);
|
|
||||||
}
|
|
||||||
}, 250);
|
|
||||||
}).catch(error(1));
|
|
||||||
});
|
|
||||||
}).catch(error(3));
|
|
||||||
}).catch(error(4));
|
|
||||||
}).catch(error(5));
|
|
||||||
})();
|
|
||||||
|
|
||||||
function error(code){
|
|
||||||
return function(){
|
|
||||||
console.log("A promise failed to resolve code:"+code);
|
|
||||||
process.exit(1);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<moduleErrors.length; idx++) {
|
|
||||||
console.error(moduleErrors[idx]+"\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var stats = [
|
|
||||||
"Time: " + context.runtime + "ms",
|
|
||||||
"Total: " + context.total,
|
|
||||||
"Passed: " + context.passed,
|
|
||||||
"Failed: " + context.failed
|
|
||||||
];
|
|
||||||
console.log(stats.join(", "));
|
|
||||||
window.qunitDone = context;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const qunit_script = logQUnit.toString();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
if(window.qunitDone){
|
|
||||||
return window.qunitDone.failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const check_script = check.toString();
|
|
|
@ -1,66 +1,104 @@
|
||||||
// PhantomJS QUnit Test Runner
|
// 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
|
||||||
|
|
||||||
/*globals QUnit phantom*/
|
/* globals Promise */
|
||||||
|
|
||||||
var system = require("system"),
|
var args = process.argv.slice(2);
|
||||||
args = phantom.args;
|
|
||||||
|
|
||||||
if (args === undefined) {
|
|
||||||
args = system.args;
|
|
||||||
args.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length < 1 || args.length > 2) {
|
if (args.length < 1 || args.length > 2) {
|
||||||
console.log("Usage: " + phantom.scriptName + " <URL> <timeout>");
|
console.log("Usage: node run-qunit.js <URL> <timeout>");
|
||||||
phantom.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = require("webpage").create();
|
const chromeLauncher = require('chrome-launcher');
|
||||||
|
const CDP = require('chrome-remote-interface');
|
||||||
|
|
||||||
page.onConsoleMessage = function(msg) {
|
(function() {
|
||||||
if (msg.slice(0, 8) === "WARNING:") { return; }
|
|
||||||
if (msg.slice(0, 6) === "DEBUG:") { return; }
|
|
||||||
|
|
||||||
console.log(msg);
|
function launchChrome() {
|
||||||
};
|
return chromeLauncher.launch({
|
||||||
|
chromeFlags: [
|
||||||
|
'--disable-gpu',
|
||||||
|
'--headless',
|
||||||
|
'--no-sandbox'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
page.onCallback = function (message) {
|
launchChrome().then(chrome => {
|
||||||
// forward the message to the standard output
|
CDP({
|
||||||
system.stdout.write(message);
|
port: chrome.port
|
||||||
};
|
}).then(protocol => {
|
||||||
|
const {Page, Runtime} = protocol;
|
||||||
|
Promise.all([Page.enable(), Runtime.enable()]).then(()=>{
|
||||||
|
|
||||||
page.open(args[0], function(status) {
|
Runtime.consoleAPICalled((response) => {
|
||||||
if (status !== "success") {
|
const message = response['args'][0].value;
|
||||||
console.error("Unable to access network");
|
|
||||||
phantom.exit(1);
|
|
||||||
} else {
|
|
||||||
page.evaluate(logQUnit);
|
|
||||||
|
|
||||||
var timeout = parseInt(args[1] || 300000, 10),
|
// If it's a simple test result, write without newline
|
||||||
start = Date.now();
|
if(message === "." || message === "F"){
|
||||||
|
process.stdout.write(message);
|
||||||
var interval = setInterval(function() {
|
}else{
|
||||||
if (Date.now() > start + timeout) {
|
console.log(message);
|
||||||
console.error("Tests timed out");
|
}
|
||||||
phantom.exit(124);
|
|
||||||
} else {
|
|
||||||
var qunitDone = page.evaluate(function() {
|
|
||||||
return window.qunitDone;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (qunitDone) {
|
Page.navigate({
|
||||||
clearInterval(interval);
|
url: args[0]
|
||||||
if (qunitDone.failed > 0) {
|
});
|
||||||
phantom.exit(1);
|
|
||||||
} else {
|
|
||||||
phantom.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
Page.loadEventFired(() => {
|
||||||
|
|
||||||
|
Runtime.evaluate({
|
||||||
|
expression: `(${qunit_script})()`
|
||||||
|
}).then(() => {
|
||||||
|
const timeout = parseInt(args[1] || 300000, 10);
|
||||||
|
var start = Date.now();
|
||||||
|
|
||||||
|
var interval = setInterval(() => {
|
||||||
|
if (Date.now() > start + timeout) {
|
||||||
|
console.error("Tests timed out");
|
||||||
|
|
||||||
|
protocol.close();
|
||||||
|
chrome.kill();
|
||||||
|
process.exit(124);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Runtime.evaluate({
|
||||||
|
expression: `(${check_script})()`
|
||||||
|
}).then(numFails => {
|
||||||
|
if (numFails.result.type !== 'undefined') {
|
||||||
|
clearInterval(interval);
|
||||||
|
protocol.close();
|
||||||
|
chrome.kill();
|
||||||
|
|
||||||
|
if (numFails.result.value > 0) {
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(error);
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
}).catch(error(1));
|
||||||
|
});
|
||||||
|
}).catch(error(3));
|
||||||
|
}).catch(error(4));
|
||||||
|
}).catch(error(5));
|
||||||
|
})();
|
||||||
|
|
||||||
|
function error(code){
|
||||||
|
return function(){
|
||||||
|
console.log("A promise failed to resolve code:"+code);
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following functions are converted to strings
|
||||||
|
// And then sent to chrome to be evalaluated
|
||||||
function logQUnit() {
|
function logQUnit() {
|
||||||
var moduleErrors = [];
|
var moduleErrors = [];
|
||||||
var testErrors = [];
|
var testErrors = [];
|
||||||
|
@ -83,9 +121,9 @@ function logQUnit() {
|
||||||
var msg = " Test Failed: " + context.name + assertionErrors.join(" ");
|
var msg = " Test Failed: " + context.name + assertionErrors.join(" ");
|
||||||
testErrors.push(msg);
|
testErrors.push(msg);
|
||||||
assertionErrors = [];
|
assertionErrors = [];
|
||||||
window.callPhantom("F");
|
console.log("F");
|
||||||
} else {
|
} else {
|
||||||
window.callPhantom(".");
|
console.log(".");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -123,3 +161,11 @@ function logQUnit() {
|
||||||
window.qunitDone = context;
|
window.qunitDone = context;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const qunit_script = logQUnit.toString();
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
if(window.qunitDone){
|
||||||
|
return window.qunitDone.failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const check_script = check.toString();
|
||||||
|
|
Loading…
Reference in New Issue