2012-12-28 21:41:14 +04:00
|
|
|
(function(){
|
|
|
|
"use strict;"
|
|
|
|
var webdriver = require("webdriver.js").webdriver,
|
|
|
|
http = require("http"),
|
|
|
|
url = require("url"),
|
|
|
|
path = require("path"),
|
|
|
|
base64_arraybuffer = require('base64-arraybuffer'),
|
|
|
|
PNG = require('png-js'),
|
|
|
|
fs = require("fs");
|
|
|
|
|
|
|
|
function createServer(port) {
|
|
|
|
return http.createServer(function(request, response) {
|
|
|
|
var uri = url.parse(request.url).pathname,
|
2012-12-29 17:02:05 +04:00
|
|
|
filename = path.join(process.cwd(), uri);
|
2012-12-28 21:41:14 +04:00
|
|
|
|
|
|
|
fs.exists(filename, function(exists) {
|
|
|
|
if(!exists) {
|
|
|
|
response.writeHead(404, {
|
2012-12-28 01:06:47 +04:00
|
|
|
"Content-Type": "text/plain"
|
|
|
|
});
|
2012-12-28 21:41:14 +04:00
|
|
|
response.write("404 Not Found\n");
|
2012-12-28 01:06:47 +04:00
|
|
|
response.end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
|
|
|
|
|
|
|
|
fs.readFile(filename, "binary", function(err, file) {
|
|
|
|
if(err) {
|
|
|
|
response.writeHead(500, {
|
|
|
|
"Content-Type": "text/plain"
|
|
|
|
});
|
|
|
|
response.write(err + "\n");
|
|
|
|
response.end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
response.writeHead(200);
|
|
|
|
response.write(file, "binary");
|
|
|
|
response.end();
|
|
|
|
});
|
2012-12-28 01:06:47 +04:00
|
|
|
});
|
2012-12-22 18:28:34 +04:00
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
}).listen(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
function walkDir(dir, done) {
|
|
|
|
var results = [];
|
|
|
|
fs.readdir(dir, function(err, list) {
|
|
|
|
if (err) return done(err);
|
|
|
|
var i = 0;
|
|
|
|
(function next() {
|
|
|
|
var file = list[i++];
|
|
|
|
if (!file) return done(null, results);
|
|
|
|
file = dir + '/' + file;
|
|
|
|
fs.stat(file, function(err, stat) {
|
|
|
|
if (stat && stat.isDirectory()) {
|
|
|
|
walkDir(file, function(err, res) {
|
|
|
|
results = results.concat(res);
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
results.push(file);
|
2012-12-28 01:06:47 +04:00
|
|
|
next();
|
2012-12-28 21:41:14 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
function getPixelArray(base64, func) {
|
|
|
|
var arraybuffer = base64_arraybuffer.decode(base64);
|
|
|
|
(new PNG(arraybuffer)).decode(func);
|
|
|
|
}
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
function getBaselineFiles() {
|
|
|
|
return fs.readdirSync("tests/results/").filter(function(name) {
|
|
|
|
return /\.baseline$/.test(name);
|
|
|
|
}).map(function(item) {
|
|
|
|
return "tests/results/" + item;
|
|
|
|
});
|
|
|
|
}
|
2012-12-28 21:41:14 +04:00
|
|
|
|
|
|
|
function testPage(browser, url, done) {
|
|
|
|
browser.url(url)
|
|
|
|
.$(".html2canvas", 5000, function(){
|
|
|
|
this.execute(function(){
|
|
|
|
var canvas = $('.html2canvas')[0];
|
|
|
|
return canvas.toDataURL("image/png").substring(22);
|
|
|
|
},[], function(dataurl) {
|
|
|
|
getPixelArray(dataurl, function(h2cPixels) {
|
|
|
|
browser.screenshot(function(base64){
|
|
|
|
getPixelArray(base64, function(screenPixels) {
|
|
|
|
var len = h2cPixels.length, index = 0, diff = 0;
|
|
|
|
for (; index < len; index++) {
|
|
|
|
if (screenPixels[index] - h2cPixels[index] !== 0) {
|
|
|
|
diff++;
|
|
|
|
}
|
2012-12-22 18:28:34 +04:00
|
|
|
}
|
2012-12-28 21:41:14 +04:00
|
|
|
done(100 - (Math.round((diff/h2cPixels.length) * 10000) / 100));
|
|
|
|
});
|
|
|
|
})
|
|
|
|
});
|
2012-12-22 18:28:34 +04:00
|
|
|
});
|
|
|
|
});
|
2012-12-28 21:41:14 +04:00
|
|
|
}
|
2012-12-22 18:28:34 +04:00
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
var writeResultFile = function(filename, json, append) {
|
|
|
|
fs.writeFile(filename + (append || ""), json);
|
|
|
|
};
|
2012-12-22 18:28:34 +04:00
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
var openResultFile = function(stats, browser) {
|
|
|
|
var tests = stats[browser].tests,
|
2012-12-29 17:02:05 +04:00
|
|
|
filename = "tests/results/" + browser + ".json",
|
2012-12-28 21:41:14 +04:00
|
|
|
write = writeResultFile.bind(null, filename, JSON.stringify(stats[browser]));
|
2012-12-28 01:06:47 +04:00
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
fs.exists(filename, function(exists) {
|
|
|
|
if(exists) {
|
|
|
|
fs.readFile(filename, "binary", parseResultFile.bind(null, tests, browser, write));
|
|
|
|
} else {
|
|
|
|
write();
|
|
|
|
}
|
|
|
|
});
|
2012-12-28 01:06:47 +04:00
|
|
|
};
|
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
var setColor = function(color, text) {
|
2012-12-29 17:02:05 +04:00
|
|
|
return [color, " * ", ((isNaN(text.amount)) ? "NEW" : text.amount + "%"), " ", text.test].join("");
|
2012-12-28 21:41:14 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
var parseResultFile = function(tests, browser, createResultFile, err, file) {
|
|
|
|
if (err) throw err;
|
|
|
|
var data = JSON.parse(file),
|
|
|
|
improved = [],
|
2012-12-29 17:02:05 +04:00
|
|
|
regressed = [],
|
|
|
|
newItems = [],
|
2012-12-28 21:41:14 +04:00
|
|
|
colors = {
|
|
|
|
red: "\x1b[1;31m",
|
2012-12-29 17:02:05 +04:00
|
|
|
blue: "\x1b[1;36m",
|
|
|
|
violet: "\x1b[0;35m",
|
2012-12-28 21:41:14 +04:00
|
|
|
green: "\x1b[0;32m"
|
2012-12-29 17:02:05 +04:00
|
|
|
};
|
2012-12-28 21:41:14 +04:00
|
|
|
|
|
|
|
Object.keys(tests).forEach(function(test){
|
|
|
|
var testResult = tests[test],
|
|
|
|
dataResult = data.tests[test],
|
|
|
|
dataObject = {
|
2012-12-29 17:02:05 +04:00
|
|
|
amount: (Math.abs(testResult - dataResult) < 0.02) ? 0 : testResult - dataResult,
|
2012-12-28 21:41:14 +04:00
|
|
|
test: test
|
2012-12-28 01:06:47 +04:00
|
|
|
};
|
2012-12-28 21:41:14 +04:00
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
if (dataObject.amount > 0) {
|
2012-12-28 21:41:14 +04:00
|
|
|
improved.push(dataObject);
|
2012-12-29 17:02:05 +04:00
|
|
|
} else if (dataObject.amount < 0) {
|
2012-12-28 21:41:14 +04:00
|
|
|
regressed.push(dataObject);
|
2012-12-29 17:02:05 +04:00
|
|
|
} else if (dataResult === undefined) {
|
|
|
|
newItems.push(dataObject);
|
2012-12-28 21:41:14 +04:00
|
|
|
}
|
|
|
|
|
2012-12-22 18:28:34 +04:00
|
|
|
});
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
if (newItems.length > 0 || improved.length > 0 || regressed.length > 0) {
|
2012-12-28 21:41:14 +04:00
|
|
|
if (regressed.length === 0) {
|
|
|
|
createResultFile(".baseline");
|
|
|
|
}
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
console.log(colors.violet, "********************");
|
2012-12-28 21:41:14 +04:00
|
|
|
console.log((regressed.length > 0) ? colors.red : colors.green, browser);
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
improved.map(setColor.bind(null, colors.green))
|
|
|
|
.concat(regressed.map(setColor.bind(null, colors.red)))
|
|
|
|
.concat(newItems.map(setColor.bind(null, colors.blue)))
|
|
|
|
.forEach(function(item) {
|
|
|
|
console.log(item);
|
2012-12-28 01:06:47 +04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
function handleResults(stats) {
|
|
|
|
Object.keys(stats).forEach(openResultFile.bind(null, stats));
|
|
|
|
}
|
|
|
|
|
|
|
|
function runBrowsers(pages){
|
|
|
|
|
|
|
|
var port = 5555,
|
|
|
|
stats = {},
|
|
|
|
browsers = ["chrome", "firefox", "internet explorer"],
|
|
|
|
browsersDone = 0,
|
|
|
|
server = createServer(port),
|
|
|
|
numPages = pages.length;
|
|
|
|
|
|
|
|
var browserDone = function() {
|
|
|
|
if (++browsersDone >= browsers.length) {
|
|
|
|
server.close();
|
|
|
|
handleResults(stats);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
browsers.forEach(function(browserName){
|
|
|
|
var browser = new webdriver({
|
|
|
|
browser: browserName
|
|
|
|
}),
|
|
|
|
browserType;
|
|
|
|
browserName = browserName.replace("internet explorer", "iexplorer");
|
|
|
|
browser.status(function(browserInfo){
|
|
|
|
browserType = [browserName, browser.version, browserInfo.os.name.replace(/\s+/g, "-").toLowerCase()].join("-");
|
|
|
|
var date = new Date(),
|
|
|
|
obj = {
|
|
|
|
tests: {},
|
|
|
|
date: date.toISOString(),
|
|
|
|
version: browser.version
|
|
|
|
};
|
|
|
|
stats[browserType] = obj;
|
|
|
|
stats[browserName] = obj;
|
|
|
|
processPage(0);
|
|
|
|
});
|
2012-12-28 01:06:47 +04:00
|
|
|
|
2012-12-28 21:41:14 +04:00
|
|
|
function processPage(index) {
|
|
|
|
var page = pages[index++];
|
2012-12-29 17:02:05 +04:00
|
|
|
testPage(browser, "http://localhost:" + port + "/" + page + "?selenium", function(result) {
|
2012-12-28 21:41:14 +04:00
|
|
|
if (numPages > index) {
|
|
|
|
processPage(index);
|
|
|
|
} else {
|
|
|
|
browser.close(browserDone);
|
|
|
|
}
|
|
|
|
stats[browserType].tests[page] = result;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
exports.tests = function() {
|
|
|
|
getBaselineFiles().forEach(fs.unlinkSync.bind(fs));
|
|
|
|
walkDir("tests/cases", function(err, results) {
|
|
|
|
if (err) throw err;
|
|
|
|
runBrowsers(results);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.baseline = function() {
|
|
|
|
getBaselineFiles().forEach(function(file) {
|
|
|
|
var newName = file.substring(0, file.length - 9);
|
|
|
|
fs.renameSync(file, newName);
|
|
|
|
console.log(newName, "created");
|
|
|
|
});
|
|
|
|
};
|
2012-12-28 01:06:47 +04:00
|
|
|
|
2012-12-30 18:29:01 +04:00
|
|
|
exports.markdown = function() {
|
|
|
|
var data = {}, html = "<table><thead><tr><td></td>",
|
|
|
|
browsers = ["chrome", "firefox", "iexplorer"];
|
|
|
|
|
|
|
|
browsers.forEach(function(browser) {
|
|
|
|
data[browser] = JSON.parse(fs.readFileSync("tests/results/" + browser + ".json"));
|
|
|
|
html += "<th>" + browser + "<br />" + data[browser].version + "</th>";
|
|
|
|
});
|
|
|
|
html += "</tr></thead><tbody>\n";
|
|
|
|
|
|
|
|
Object.keys(data[browsers[0]].tests).forEach(function(testFile) {
|
|
|
|
html += "<tr><td>" + testFile.substring(12) + "</td>";
|
|
|
|
browsers.forEach(function(browser) {
|
|
|
|
html += "<td>" + Math.round(data[browser].tests[testFile] * 100) / 100 + "%</td>";
|
|
|
|
});
|
|
|
|
html += "</tr>\n"
|
|
|
|
});
|
|
|
|
|
|
|
|
html += "</tbody></table>";
|
|
|
|
|
2012-12-30 18:30:28 +04:00
|
|
|
fs.writeFileSync("tests/readme.md", html);
|
2012-12-30 18:29:01 +04:00
|
|
|
};
|
|
|
|
|
2012-12-29 17:02:05 +04:00
|
|
|
})();
|