203 lines
5.5 KiB
JavaScript
203 lines
5.5 KiB
JavaScript
/**
|
|
* Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
|
|
* Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
|
|
* and other contributors
|
|
* Released under the Apache 2.0 License
|
|
*/
|
|
var builder = require('xmlbuilder'),
|
|
config = require('./conf'),
|
|
fs = require('fs-extra'),
|
|
path = require('path'),
|
|
util = require('./util');
|
|
|
|
module.exports = JUnitRenderer;
|
|
|
|
function JUnitRenderer(collector) {
|
|
this.collector = collector;
|
|
this.ruleTestsuites = builder.create('testsuites', {
|
|
version: '1.0',
|
|
encoding: 'UTF-8'
|
|
});
|
|
this.timingTestsuites = builder.create('testsuites', {
|
|
version: '1.0',
|
|
encoding: 'UTF-8'
|
|
});
|
|
}
|
|
|
|
JUnitRenderer.prototype.renderForEachPage = function(url, pageData) {
|
|
|
|
var yslowData = pageData.yslow,
|
|
ruleDictionary = yslowData.dictionary.rules,
|
|
rules = pageData.yslow.g,
|
|
score = pageData.yslow.o,
|
|
browserTimeData = pageData.browsertime;
|
|
generateRuleTestSuitePerPage(url, score, rules, ruleDictionary, this.ruleTestsuites);
|
|
|
|
if (browserTimeData)
|
|
generateBrowserTimeTestSuitePerPage(browserTimeData, this.timingTestsuites);
|
|
|
|
};
|
|
|
|
function generateBrowserTimeTestSuitePerPage(browserTimeData, timingTestsuites) {
|
|
|
|
browserTimeData.forEach(function(run) {
|
|
var testsuite = timingTestsuites.ele('testsuite', {
|
|
'name': 'sitespeed.io.timings.' + run.pageData.url.replace(/\./g, '_')
|
|
});
|
|
|
|
var url = run.pageData.url;
|
|
|
|
// First check if we have specific values configured for that URL else use the default ones
|
|
if (config.timingThresholds.pages) {
|
|
if (config.timingThresholds.pages.hasOwnProperty(url)) {
|
|
|
|
Object.keys(config.timingThresholds.pages[url]).forEach(function(
|
|
timing) {
|
|
run.statistics.forEach(function(stats) {
|
|
if (stats.name === timing) {
|
|
generateTimingTestCase(stats, timing, run, testsuite,
|
|
config.timingThresholds
|
|
.pages[url][timing]);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
// Use default values
|
|
else {
|
|
Object.keys(config.timingThresholds.
|
|
default).forEach(function(timing) {
|
|
run.statistics.forEach(function(stats) {
|
|
if (stats.name === timing) {
|
|
generateTimingTestCase(stats, timing, run, testsuite,
|
|
config.timingThresholds.
|
|
default [timing]);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function generateTimingTestCase(stats, timing, run, testsuite, limit) {
|
|
var browser = run.pageData.browserName,
|
|
version = run.pageData.browserVersion,
|
|
url = run.pageData.url;
|
|
|
|
// The time in Jenkins needs to be in seconds
|
|
var testCase = testsuite.ele('testcase', {
|
|
'name': timing,
|
|
'time': stats[config.timingThresholds.type] / 1000
|
|
});
|
|
|
|
// is it a failure
|
|
if (stats[config.timingThresholds.type] > limit) {
|
|
testCase.ele('failure', {
|
|
'type': 'failedTiming',
|
|
'message': 'The time for ' + timing + ' is ' + stats[
|
|
config.timingThresholds.type] +
|
|
' ms, that is higher than your limit of ' + limit + ' ms. Using ' +
|
|
browser + ' ' +
|
|
version + ' ' + config.timingThresholds.type + ' value'
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
|
|
function generateRuleTestSuitePerPage(url, score, rules, ruleDictionary,
|
|
testsuites) {
|
|
var rule = Object.keys(rules);
|
|
|
|
var failures = 0,
|
|
skipped = 0;
|
|
|
|
var testsuite = testsuites.ele('testsuite', {
|
|
'name': 'sitespeed.io.rules.' + url.replace(/\./g, '_'),
|
|
'tests': (rule.length + 1)
|
|
});
|
|
var overallPageTestCase = testsuite.ele('testcase');
|
|
|
|
overallPageTestCase.att({
|
|
'name': 'Overall page score',
|
|
'status': score
|
|
});
|
|
if (isFailure("overall", score)) {
|
|
overallPageTestCase.ele('failure', {
|
|
'type': 'failedRule',
|
|
'message': 'The average overall page score ' + score +
|
|
' is below your limit'
|
|
});
|
|
failures++;
|
|
}
|
|
|
|
|
|
for (var i = 0; i < rule.length; i++) {
|
|
|
|
// is this skippable?
|
|
if (config.skipTest) {
|
|
if (config.skipTest.indexOf(rule[i]) > -1) {
|
|
skipped++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
var testCase = testsuite.ele('testcase', {
|
|
'name': '(' + rule[i] + ') ' + ruleDictionary[rule[i]].name,
|
|
'status': rules[rule[i]].score
|
|
});
|
|
|
|
if (isFailure(rule[i], rules[rule[i]].score)) {
|
|
failures++;
|
|
var failure = testCase.ele('failure', {
|
|
'type': 'failedRule',
|
|
'message': 'Score ' + score + ' - ' + rules[rule[i]].message
|
|
});
|
|
|
|
var comps = '';
|
|
rules[rule[i]].components.forEach(function(comp) {
|
|
comps += util.decodeURIComponent(comp) + '\n';
|
|
});
|
|
|
|
failure.txt(comps);
|
|
}
|
|
|
|
}
|
|
|
|
testsuite.att('failures', failures);
|
|
testsuite.att('skipped', skipped);
|
|
}
|
|
|
|
function isFailure(ruleid, value) {
|
|
if (config.thresholds) {
|
|
if (config.thresholds.hasOwnProperty(ruleid))
|
|
return (value < config.thresholds[ruleid]);
|
|
else return (value < config.threshold);
|
|
} else return (value < config.threshold);
|
|
}
|
|
|
|
JUnitRenderer.prototype.renderAfterFullAnalyse = function(cb) {
|
|
// create testsuites and write to disk
|
|
var rulesXML = this.ruleTestsuites.end({
|
|
pretty: true,
|
|
indent: ' ',
|
|
newline: '\n'
|
|
});
|
|
var timingXML = this.timingTestsuites.end({
|
|
pretty: true,
|
|
indent: ' ',
|
|
newline: '\n'
|
|
});
|
|
|
|
renderXMLFile(rulesXML,"junit.xml");
|
|
renderXMLFile(timingXML,"junit-timings.xml");
|
|
// TODO render the files async and call the cb once the two is finished
|
|
cb();
|
|
|
|
};
|
|
|
|
function renderXMLFile(xml, fileName) {
|
|
console.log("Writing " + fileName);
|
|
fs.outputFileSync(path.join(config.run.absResultDir,fileName), xml);
|
|
}
|