Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added junit output, including message for tap format too

  • Loading branch information...
commit 7fa6d2295a899371db595dd3334f97e03d1ca612 1 parent 72f92c8
Marcel Duran authored
Showing with 153 additions and 22 deletions.
  1. +135 −18 src/common/util.js
  2. +18 −4 src/phantomjs/controller.js
View
153 src/common/util.js
@@ -861,6 +861,12 @@ YSLOW.util = {
obj.score = 'n/a';
}
}
+ // removing hardcoded open link,
+ // TODO: remove those links from original messages
+ obj.message = result.message.replace(
+ /javascript:document\.ysview\.openLink\('(.+)'\)/,
+ '$1'
+ );
comps = result.components;
if (isArray(comps)) {
obj.components = [];
@@ -1153,6 +1159,21 @@ YSLOW.util = {
.replace(/"/g, '"');
},
+ safeXML: (function () {
+ var decodeComp = this.decodeURIComponent,
+ reInvalid = /[<&>]/;
+
+ return function (value, decode) {
+ if (decode) {
+ value = decodeComp(value);
+ }
+ if (reInvalid.test(value)) {
+ return '<![CDATA[' + value + ']]>';
+ }
+ return value;
+ };
+ }()),
+
/**
* convert Object to XML
* @param {Object} obj the Object to be converted to XML
@@ -1162,21 +1183,11 @@ YSLOW.util = {
objToXML: function (obj, root) {
var toXML,
util = YSLOW.util,
- reInvalid = /[<&>]/,
+ safeXML = util.safeXML,
xml = '<?xml version="1.0" encoding="UTF-8"?>';
toXML = function (o) {
- var item, value, i, len, val, type,
-
- safeXML = function (value, decode) {
- if (decode) {
- value = util.decodeURIComponent(value);
- }
- if (reInvalid.test(value)) {
- return '<![CDATA[' + value + ']]>';
- }
- return value;
- };
+ var item, value, i, len, val, type;
for (item in o) {
if (o.hasOwnProperty(item)) {
@@ -1361,7 +1372,7 @@ YSLOW.util = {
}
},
- test = function (score, ts, name, offenders) {
+ test = function (score, ts, name, message, offenders) {
var desc = rules.hasOwnProperty(name) && rules[name].name;
tests.push({
@@ -1370,6 +1381,7 @@ YSLOW.util = {
grade: util.prettyScore(score),
name: name,
description: desc || '',
+ message: message,
offenders: offenders
});
};
@@ -1390,7 +1402,8 @@ YSLOW.util = {
if (typeof score === 'undefined') {
score = -1;
}
- test(score, getThreshold(grade), grade, g.components);
+ test(score, getThreshold(grade), grade,
+ g.message, g.components);
}
}
}
@@ -1409,8 +1422,7 @@ YSLOW.util = {
len = results.length,
tap = [],
util = YSLOW.util,
- decodeURI = util.decodeURIComponent,
- decodeEntities = util.decodeEntities;
+ decodeURI = util.decodeURIComponent;
// tap version
tap.push('TAP version 13');
@@ -1431,26 +1443,131 @@ YSLOW.util = {
}
tap.push(line);
+ // message
+ if (res.message) {
+ tap.push(' ---');
+ tap.push(' message: ' + res.message);
+ }
+
// offenders
offenders = res.offenders;
if (offenders) {
lenJ = offenders.length;
if (lenJ > 0) {
- tap.push(' ---');
+ if (!res.message) {
+ tap.push(' ---');
+ }
tap.push(' offenders:');
for (j = 0; j < lenJ; j += 1) {
tap.push(' - "' +
decodeURI(offenders[j]) + '"');
}
- tap.push(' ...');
}
}
+
+ if (res.message || lenJ > 0) {
+ tap.push(' ...');
+ }
}
return tap.join('\n');
},
/**
+ * Format test results as JUnit XML for CI
+ * @see: http://www.junit.org/
+ * @param {Array} tests the arrays containing the test results from testResults.
+ * @return {String} the results as JUnit XML text
+ */
+ formatAsJUnit: function (results) {
+ var i, res, line, offenders, j, lenJ,
+ len = results.length,
+ skipped = 0,
+ failures = 0,
+ junit = [],
+ cases = [],
+ util = YSLOW.util,
+ decodeURI = util.decodeURIComponent,
+ safeXML = util.safeXML,
+
+ safeAttr = function (str) {
+ return str
+ .replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;');
+ };
+
+ for (i = 0; i < len; i += 1) {
+ res = results[i];
+ line = ' <testcase name="' + safeAttr(res.name +
+ (res.description ? ': ' + res.description : '')) + '"';
+ line += ' status="' + res.grade +
+ ' (' + res.score + ')';
+ if (res.ok) {
+ cases.push(line + '"/>');
+ } else {
+ failures += 1;
+ cases.push(line + '">');
+
+ // skipped
+ if (res.score < 0) {
+ skipped += 1;
+ cases.push(' <skipped>score N/A</skipped>');
+ }
+
+ line = ' <failure';
+ if (res.message) {
+ line += ' message="' + safeAttr(res.message) + '"';
+ }
+
+ // offenders
+ offenders = res.offenders;
+ if (offenders) {
+ cases.push(line + '>');
+ lenJ = offenders.length;
+ for (j = 0; j < lenJ; j += 1) {
+ cases.push(' ' + safeXML(decodeURI(offenders[j])));
+ }
+ cases.push(' </failure>');
+ } else {
+ cases.push(line + '/>');
+ }
+
+ cases.push(' </testcase>');
+ }
+ }
+
+ // xml
+ junit.push('<?xml version="1.0" encoding="UTF-8" ?>');
+
+ // open test suites wrapper
+ junit.push('<testsuites>');
+
+ // open test suite w/ summary
+ line = ' <testsuite name="YSlow" tests="' + len + '"';
+ if (failures) {
+ line += ' failures="' + failures + '"';
+ }
+ if (skipped) {
+ line += ' skipped="' + skipped + '"';
+ }
+ line += '>';
+ junit.push(line);
+
+ // concat test cases
+ junit = junit.concat(cases);
+
+ // close test suite
+ junit.push(' </testsuite>');
+
+ // close test suites wrapper
+ junit.push('</testsuites>');
+
+ return junit.join('\n');
+ },
+
+ /**
* Try to find a spaceid in the HTML document source.
* @param {YSLOW.ComponentSet} cset Component set.
* @return spaceID string
View
22 src/phantomjs/controller.js
@@ -101,7 +101,7 @@ if (len === 0 || urlCount === 0 || unaryArgs.help) {
' -h, --help output usage information',
' -V, --version output the version number',
' -i, --info <info> specify the information to display/log (basic|grade|stats|comps|all) [all]',
- ' -f, --format <format> specify the output results format (json|xml|plain|tap) [json]',
+ ' -f, --format <format> specify the output results format (json|xml|plain|tap|junit) [json]',
' -r, --ruleset <ruleset> specify the YSlow performance ruleset to be used (ydefault|yslow1|yblog) [ydefault]',
' -b, --beacon <url> specify an URL to log the results',
' -d, --dict include dictionary of results fields',
@@ -260,7 +260,19 @@ urls.forEach(function (url) {
// format out with appropriate content type
formatOutput = function (content) {
- switch (args.format) {
+ var format = (args.format || '').toLowerCase(),
+ harness = {
+ 'tap': {
+ func: ysutil.formatAsTAP,
+ contentType: 'text/plain'
+ },
+ 'junit': {
+ func: ysutil.formatAsJUnit,
+ contentType: 'text/xml'
+ }
+ };
+
+ switch (format) {
case 'xml':
return {
content: ysutil.objToXML(content),
@@ -273,20 +285,22 @@ urls.forEach(function (url) {
),
contentType: 'text/plain'
};
+ // test formats
case 'tap':
+ case 'junit':
try {
threshold = JSON.parse(args.threshold);
} catch (err) {
threshold = args.threshold;
}
return {
- content: ysutil.formatAsTAP(
+ content: harness[format].func(
ysutil.testResults(
content,
threshold
)
),
- contentType: 'text/plain'
+ contentType: harness[format].contentType
};
default:
return {
Please sign in to comment.
Something went wrong with that request. Please try again.