sitespeed.io/lib/analyze/browsertime.js

207 lines
4.9 KiB
JavaScript

/**
* Sitespeed.io - How speedy is your site? (https://www.sitespeed.io)
* Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
* and other contributors
* Released under the Apache 2.0 License
*/
'use strict';
var util = require('../util/util'),
fs = require('fs-extra'),
path = require('path'),
winston = require('winston'),
Browsertime = require('browsertime'),
btProxy = require('browsertime/lib/proxy'),
browserListenerProxy = require('browsertime/lib/proxy/browserListenerProxy'),
browsers = require('browsertime/lib/browsers'),
logger = require('browsertime/lib/logger'),
inspect = require('util').inspect,
async = require('async');
var proxy;
module.exports = {
setupProxy: function(config) {
var btConfig = {
// TODO this will not work if we feed with different domain
url: config.url || config.urls[0],
basicAuth: config.basicAuth,
headers: config.requestHeaders,
userAgent: config.userAgent,
connection: config.connection,
silent: (config.tap || config.junit),
verbose: config.verbose,
noColor: config.noColor,
logDir: config.run.absResultDir,
seleniumServer: config.seleniumServer,
useProxy: true
};
if (config.btConfig) {
Object.keys(config.btConfig).forEach(function(key) {
btConfig[key] = config.btConfig[key];
});
}
logger.addLog(null, btConfig);
proxy = btProxy.createProxy(btConfig);
},
analyze: function(urls, config, asyncDoneCallback) {
var browserList = config.browsertime;
var log = winston.loggers.get('sitespeed.io');
var pre = [];
browserList.forEach(function(browser) {
pre.push(
function(callback) {
fs.mkdirs(path.join(config.run.absResultDir, config.dataDir, 'browsertime', browser), callback);
}
);
pre.push(
function(callback) {
fs.mkdirs(path.join(config.run.absResultDir, config.dataDir, 'har', browser), callback);
}
);
});
pre.push(
function(callback) {
proxy.launchProcess(callback);
}
);
// setup the proxy
this.setupProxy(config);
async.parallel(pre,
function(err) {
if (err) {
return asyncDoneCallback(err);
}
var queue = async.queue(runBrowsertime, 1);
var errors = {};
var pageData = {};
urls.forEach(function(u) {
browserList.forEach(function(browser) {
log.info('Queueing browsertime for %s %s', u, browser);
queue.push({
'url': u,
'browser': browser,
'config': config
}, function(error, data) {
if (error) {
log.error('Error running browsertime: %s', inspect(error));
errors[u] = error;
} else {
if (pageData[u]) {
pageData[u].push(data);
} else {
pageData[u] = [data];
}
}
});
});
});
queue.drain = function() {
proxy.stopProcess(function() {});
asyncDoneCallback(undefined, {
'type': 'browsertime',
'data': pageData,
'errors': errors
});
};
});
}
};
function runBrowsertime(args, callback) {
var url = args.url;
var browser = args.browser;
var config = args.config;
var log = winston.loggers.get('sitespeed.io');
var measurementFile = path.join(config.run.absResultDir, config.dataDir, 'browsertime', browser,
util.getFileName(url) + '-browsertime.json');
var harFile = path.join(config.run.absResultDir, config.dataDir, 'har', browser,
util.getFileName(url) + '.har');
// TODO add useProxy,scriptPath
var btConfig = {
url: args.url,
browser: browser,
runs: config.no,
basicAuth: config.basicAuth,
headers: config.requestHeaders,
size: config.viewPort,
userAgent: config.userAgent,
harFile: harFile,
filename: measurementFile,
connection: config.connection,
silent: (config.tap || config.junit),
verbose: config.verbose,
noColor: config.noColor,
logDir: config.run.absResultDir,
waitScript: config.waitScript,
customScripts: config.customScripts,
seleniumServer: config.seleniumServer,
useProxy: true
};
if (config.btConfig) {
Object.keys(config.btConfig).forEach(function(key) {
btConfig[key] = config.btConfig[key];
});
}
log.log('info', 'Running browsertime for ' + browser + ' ' + url);
browsers.setProxy(proxy);
var bt = new Browsertime(browsers);
browserListenerProxy.setup(bt, proxy, btConfig);
bt.fetch(btConfig, function(err) {
if (err) {
return callback(err);
}
fs.readFile(measurementFile, function(err2, btData) {
if (err2) {
log.log('error', 'Couldn\'t read the file:' + measurementFile);
return callback(err2);
}
// TODO we should only read the HAR if we ask for one
fs.readFile(harFile, function(err3, harData) {
if (err3) {
log.log('error', 'Couldn\'t read the file:' + harFile);
return callback(err3);
}
var harJson;
var btJson;
try {
btJson = JSON.parse(btData);
harJson = JSON.parse(harData);
} catch (e) {
return callback(e);
}
return callback(undefined, {
'browser': browser,
'browsertime': btJson,
'har': harJson
});
});
});
});
}