Skip to content

Commit

Permalink
πŸ’„ rewrite all the things πŸ’„
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Jan 10, 2015
1 parent 770788a commit 9af7f45
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 143 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
Run mobile and desktop performance tests for your deployed site using [Google PageSpeed Insights](https://developers.google.com/speed/docs/insights/v1/getting_started) with tidy reporting for your build process. A sample [Gulpfile](https://github.com/addyosmani/psi-gulp-sample) demonstrating use is also available.

Uses [gpagespeed](https://github.com/zrrrzzt/gpagespeed/) and the reporter in [grunt-pagespeed](https://github.com/jrcryer/grunt-pagespeed).


## Install

Expand Down Expand Up @@ -137,5 +135,5 @@ For testing local project, we recommend using [ngrok](http://www.jamescryer.com/

## License

Apache 2.0
Apache-2.0
Copyright 2014 Google Inc
49 changes: 26 additions & 23 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,50 @@
var meow = require('meow');
var updateNotifier = require('update-notifier');
var prependHttp = require('prepend-http');
var output = require('./lib/output').init();
var output = require('./lib/output');
var psi = require('./');

var cli = meow({
help: [
'Usage',
' a11y <url>',
'',
'Example',
' a11y todomvc.com',
'',
'Options',
' --key Google API Key. By default the free tier is used.',
' --format Output format: cli|json|tap',
' --strategy Strategy to use when analyzing the page: desktop|mobile',
' --prettyprint Pretty print the result.',
' --locale Locale results should be generated in.'
].join('\n')
help: [
'Usage',
' a11y <url>',
'',
'Example',
' a11y todomvc.com',
'',
'Options',
' --key Google API Key. By default the free tier is used.',
' --format Output format: cli|json|tap',
' --strategy Strategy to use when analyzing the page: desktop|mobile',
' --prettyprint Pretty print the result.',
' --locale Locale results should be generated in.'
].join('\n')
});

updateNotifier({
packageName: cli.pkg.name,
packageVersion: cli.pkg.version
packageName: cli.pkg.name,
packageVersion: cli.pkg.version
}).notify();

if (!cli.input[0]) {
console.error('Please supply an URL');
process.exit(1);
console.error('Please supply an URL');
process.exit(1);
}

var opts = cli.flags;
opts.url = prependHttp(cli.input[0]);
opts.format = opts.format || 'cli';
opts.strategy = opts.strategy || 'desktop';

psi(opts, function (err, res) {
if (err) {
console.error(err);
process.exit(1);
if (err.noStack) {
console.error(err.message);
process.exit(1);
} else {
throw err;
}
}

output.process(opts, res);
output(opts, res);
process.exit(0);
});
6 changes: 3 additions & 3 deletions lib/formats/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var _ = require('lodash');
var chalk = require('chalk');
var utils = require('../utils');

exports.render = function (overview, statistics, ruleSetResults) {
module.exports = function (overview, statistics, ruleSetResults) {
var renderOverview = function (item) {
var color = item.label === 'Score' ? utils.scoreColor(item.value) : chalk.cyan;
return item.label + ':' + utils.buffer(item.label, 11) + color(item.value);
Expand All @@ -13,12 +13,12 @@ exports.render = function (overview, statistics, ruleSetResults) {
return utils.labelize(item.label) + chalk.cyan(item.value);
};

console.log([
return [
utils.divider,
_.map(overview, renderOverview).join('\n') + '\n',
_.map(statistics, renderSection).join('\n'),
utils.labelize(''),
_.map(ruleSetResults, renderSection).join('\n'),
utils.divider
].join('\n'));
].join('\n');
};
6 changes: 3 additions & 3 deletions lib/formats/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
var _ = require('lodash');
var utils = require('../utils');

exports.render = function (overview, statistics, ruleSetResults) {
module.exports = function (overview, statistics, ruleSetResults) {
var mapSection = function (section) {
return utils.firstToUpperCaseAndAddSpace(section.label);
};
Expand All @@ -15,9 +15,9 @@ exports.render = function (overview, statistics, ruleSetResults) {
statistics = zip(statistics, mapSection);
ruleSetResults = zip(ruleSetResults, mapSection);

console.log(JSON.stringify({
return JSON.stringify({
'overview': overview,
'statistics': statistics,
'ruleResults': ruleSetResults
}, undefined, 2));
}, undefined, 2);
};
6 changes: 3 additions & 3 deletions lib/formats/tap.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
'use strict';
exports.render = function (overview, statistics, ruleSetResults, threshold) {
module.exports = function (overview, statistics, ruleSetResults, threshold) {
var outputTest = function (overview, threshold) {
var score = overview[1].value;
var result = score < threshold ? 'not ok' : 'ok';
return result + ' 1 - psi';
};

console.log([
return [
'TAP version 13',
'1..1',
outputTest(overview, threshold)
].join('\n'));
].join('\n');
};
172 changes: 69 additions & 103 deletions lib/output.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,72 @@
'use strict';
// Based on the reporting in grunt-pagespeed by James Cryer
// TODO: Refactor further as this still uses patterns that
// are based on Grunt conventions.
var prettyBytes = require('pretty-bytes');

exports.init = function () {
/**
* @var {int} default threshold
*/
var threshold = 70;

/**
* Gather overview of PageSpeed results
*
* @param {String} url
* @param {String} strategy
* @param {String} score
* @return array
*/
var overview = function (url, strategy, score) {
var _results = [];

_results.push({label: 'URL', value: url});
_results.push({label: 'Score', value: score});
_results.push({label: 'Strategy', value: strategy});

return _results;
};

/**
* Gather and normalise rule results for PageSpeed result
*
* @param {Object} rulesets
* @return array
*/
var ruleSetResults = function (rulesets) {
var title;
var result;
var ruleImpact;
var _results = [];

for (title in rulesets) {
result = rulesets[title];
ruleImpact = Math.ceil(result.ruleImpact * 100) / 100;
_results.push({label: title, value: ruleImpact});
}

return _results;
};

/**
* Gather and normalise statistics for PageSpeed result
*
* @param {Object} statistics
* @return array
*/
var statistics = function (statistics) {
var title;
var result;
var _results = [];

for (title in statistics) {
result = title.indexOf('Bytes') !== -1 ?
prettyBytes(Number(statistics[title])) :
statistics[title];

_results.push({label: title, value: result});
}

return _results;
};

/**
* Loads the correct output format
*
* @param {String} formt
* @return Function
*/
var format = function (format) {
if (['cli', 'json', 'tap'].indexOf(format) === -1) {
format = 'cli';
}

return require('./formats/' + format).render;
};

return {
process: function (parameters, response) {
var renderer = format(parameters.format);

threshold = parameters.threshold || threshold;

renderer(
overview(response.id, parameters.strategy, response.score),
statistics(response.pageStats),
ruleSetResults(response.formattedResults.ruleResults),
threshold
);

if (response.score < threshold) {
throw new Error('Threshold of ' + threshold + ' not met with score of ' + response.score);
}
}
};
var THRESHOLD = 70;

function overview(url, strategy, score) {
var ret = [];

ret.push({
label: 'URL',
value: url
});

ret.push({
label: 'Score',
value: score
});

ret.push({
label: 'Strategy',
value: strategy
});

return ret;
}

function ruleSetResults(rulesets) {
var ret = [];

for (var title in rulesets) {
ret.push({
label: title,
value: Math.ceil(rulesets[title].ruleImpact * 100) / 100
});
}

return ret;
}

function statistics(stats) {
var ret = [];

for (var title in stats) {
ret.push({
label: title,
value: title.indexOf('Bytes') !== -1 ? prettyBytes(Number(stats[title])) : stats[title]
});
}

return ret;
}

function getReporter(format) {
format = ['cli', 'json', 'tap'].indexOf(format) === -1 ? 'cli' : format;
return require('./formats/' + format);
}

module.exports = function (parameters, response) {
var renderer = getReporter(parameters.format);
var threshold = parameters.threshold || THRESHOLD;

console.log(renderer(
overview(response.id, parameters.strategy, response.score),
statistics(response.pageStats),
ruleSetResults(response.formattedResults.ruleResults),
threshold
));

if (response.score < threshold) {
var err = new Error('Threshold of ' + threshold + ' not met with score of ' + response.score);
err.noStack = true;
}
};
9 changes: 4 additions & 5 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
var assert = require('assert');
var chalk = require('chalk');
var output = require('../lib/output');
var response = require('./fixtures/response');

describe('PSI formatting', function () {
beforeEach(function () {
this.log = console.log;
this.response = require('./fixtures/response');
this.output = output.init();
this.formattedOutput = '';

console.log = function (content) {
Expand All @@ -22,17 +21,17 @@ describe('PSI formatting', function () {
});

it('should correctly format PageSpeed Insights response', function () {
this.output.process({strategy: 'desktop'}, this.response);
output({strategy: 'desktop'}, response);
assert(/Score: 88/.test(chalk.stripColor(this.formattedOutput)));
});

it('should format PageSpeed Insights response as TAP output', function () {
this.output.process({strategy: 'desktop', format: 'tap'}, this.response);
output({strategy: 'desktop', format: 'tap'}, response);
assert(/ok 1 - psi/.test(chalk.stripColor(this.formattedOutput)));
});

it('should format PageSpeed Insights response as JSON output', function () {
this.output.process({strategy: 'desktop', format: 'json'}, this.response);
output({strategy: 'desktop', format: 'json'}, response);
assert(/"Score": 88/.test(chalk.stripColor(this.formattedOutput)));
});
});

2 comments on commit 9af7f45

@addyosmani
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the amount of effort you've put into improving the module, please feel free to add yourself to the package.json authors :)

@sindresorhus
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, don't care. Thanks though :)

Please sign in to comment.