use median values for phantomjd timings
This commit is contained in:
parent
89d4ceb5f3
commit
73e6a0b28d
535
lib/cli.js
535
lib/cli.js
|
|
@ -5,283 +5,282 @@
|
|||
* Released under the Apache 2.0 License
|
||||
*/
|
||||
var fs = require('fs-extra'),
|
||||
defaultConfig = require('./default'),
|
||||
cli = require('nomnom').options({
|
||||
url: {
|
||||
abbr: 'u',
|
||||
metavar: '<URL>',
|
||||
help: 'The start url'
|
||||
},
|
||||
file: {
|
||||
abbr: 'f',
|
||||
metavar: '<FILE>',
|
||||
help: 'The path to a plain text file with one URL on each row. Each line must end with a new line in the file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Could not find the file:' + file;
|
||||
defaultConfig = require('./default'),
|
||||
cli = require('nomnom').options({
|
||||
url: {
|
||||
abbr: 'u',
|
||||
metavar: '<URL>',
|
||||
help: 'The start url'
|
||||
},
|
||||
file: {
|
||||
abbr: 'f',
|
||||
metavar: '<FILE>',
|
||||
help: 'The path to a plain text file with one URL on each row. Each line must end with a new line in the file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Could not find the file:' + file;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
sites: {
|
||||
metavar: '<FILE>',
|
||||
help: 'The path to a plain text file with one URL on each row. Each line must end with a new line in the file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Couldnt find the file:' + file;
|
||||
},
|
||||
sites: {
|
||||
metavar: '<FILE>',
|
||||
help: 'The path to a plain text file with one URL on each row. Each line must end with a new line in the file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Couldnt find the file:' + file;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
version: {
|
||||
flag: true,
|
||||
abbr: 'v',
|
||||
help: 'Display the sitespeed.io version',
|
||||
callback: function() {
|
||||
return require('../package.json').version;
|
||||
}
|
||||
},
|
||||
deep: {
|
||||
abbr: 'd',
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.deep,
|
||||
help: 'How deep to crawl.',
|
||||
callback: function(deep) {
|
||||
if (deep != parseInt(deep)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how deep you want to crawl';
|
||||
},
|
||||
version: {
|
||||
flag: true,
|
||||
abbr: 'v',
|
||||
help: 'Display the sitespeed.io version',
|
||||
callback: function() {
|
||||
return require('../package.json').version;
|
||||
}
|
||||
}
|
||||
},
|
||||
containInPath: {
|
||||
abbr: 'c',
|
||||
metavar: '<KEYWORD>',
|
||||
help: 'Only crawl URLs that contains this in the path'
|
||||
},
|
||||
skip: {
|
||||
abbr: 's',
|
||||
metavar: '<KEYWORD>',
|
||||
help: 'Do not crawl pages that contains this in the path'
|
||||
},
|
||||
threads: {
|
||||
abbr: 't',
|
||||
metavar: '<NOOFTHREADS>',
|
||||
default: defaultConfig.threads,
|
||||
help: 'The number of threads/processes that will analyze pages.',
|
||||
callback: function(threads) {
|
||||
if (threads != parseInt(threads)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how many processes/threads that will analyze your page';
|
||||
},
|
||||
deep: {
|
||||
abbr: 'd',
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.deep,
|
||||
help: 'How deep to crawl.',
|
||||
callback: function(deep) {
|
||||
if (deep != parseInt(deep)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how deep you want to crawl';
|
||||
}
|
||||
}
|
||||
else if (parseInt(threads) <= 0) {
|
||||
return 'You must specify a positive integer';
|
||||
},
|
||||
containInPath: {
|
||||
abbr: 'c',
|
||||
metavar: '<KEYWORD>',
|
||||
help: 'Only crawl URLs that contains this in the path'
|
||||
},
|
||||
skip: {
|
||||
abbr: 's',
|
||||
metavar: '<KEYWORD>',
|
||||
help: 'Do not crawl pages that contains this in the path'
|
||||
},
|
||||
threads: {
|
||||
abbr: 't',
|
||||
metavar: '<NOOFTHREADS>',
|
||||
default: defaultConfig.threads,
|
||||
help: 'The number of threads/processes that will analyze pages.',
|
||||
callback: function(threads) {
|
||||
if (threads != parseInt(threads)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how many processes/threads that will analyze your page';
|
||||
} else if (parseInt(threads) <= 0) {
|
||||
return 'You must specify a positive integer';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
name: {
|
||||
metavar: '<NAME>',
|
||||
help: 'Give your test a name, it will be added to all HTML pages'
|
||||
},
|
||||
memory: {
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.memory,
|
||||
help: 'We still use Java for a couple of things and you can configure how much memory that the process will have (in mb).'
|
||||
},
|
||||
resultBaseDir: {
|
||||
abbr: 'r',
|
||||
metavar: '<DIR>',
|
||||
default: defaultConfig.resultBaseDir,
|
||||
help: 'The result base directory',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
fs.mkdirs(file, function(err){
|
||||
if (err) {
|
||||
return 'Couldnt create the result base dir:' + err;
|
||||
}
|
||||
},
|
||||
name: {
|
||||
metavar: '<NAME>',
|
||||
help: 'Give your test a name, it will be added to all HTML pages'
|
||||
},
|
||||
memory: {
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.memory,
|
||||
help: 'We still use Java for a couple of things and you can configure how much memory that the process will have (in mb).'
|
||||
},
|
||||
resultBaseDir: {
|
||||
abbr: 'r',
|
||||
metavar: '<DIR>',
|
||||
default: defaultConfig.resultBaseDir,
|
||||
help: 'The result base directory',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
fs.mkdirs(file, function(err) {
|
||||
if (err) {
|
||||
return 'Couldnt create the result base dir:' + err;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
userAgent: {
|
||||
metavar: '<USER-AGENT>',
|
||||
default: defaultConfig.userAgent,
|
||||
help: 'The full User Agent string, default is Chrome for MacOSX. You can also set the value as iphone or ipad (will automagically change the viewport)'
|
||||
},
|
||||
viewPort: {
|
||||
metavar: '<WidthxHeight>',
|
||||
default: defaultConfig.viewPort,
|
||||
help: 'The view port, the page viewport size WidthxHeight, like 400x300.'
|
||||
},
|
||||
yslow: {
|
||||
abbr: 'y',
|
||||
metavar: '<FILE>',
|
||||
default: defaultConfig.yslow,
|
||||
help: 'The compiled YSlow file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Couldnt find the file:' + fs.realpathSync(file);
|
||||
},
|
||||
userAgent: {
|
||||
metavar: '<USER-AGENT>',
|
||||
default: defaultConfig.userAgent,
|
||||
help: 'The full User Agent string, default is Chrome for MacOSX. You can also set the value as iphone or ipad (will automagically change the viewport)'
|
||||
},
|
||||
viewPort: {
|
||||
metavar: '<WidthxHeight>',
|
||||
default: defaultConfig.viewPort,
|
||||
help: 'The view port, the page viewport size WidthxHeight, like 400x300.'
|
||||
},
|
||||
yslow: {
|
||||
abbr: 'y',
|
||||
metavar: '<FILE>',
|
||||
default: defaultConfig.yslow,
|
||||
help: 'The compiled YSlow file.',
|
||||
callback: function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return 'Couldnt find the file:' + fs.realpathSync(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ruleSet: {
|
||||
metavar: '<RULE-SET>',
|
||||
default: defaultConfig.ruleSet,
|
||||
help: 'Which ruleset to use.'
|
||||
},
|
||||
limitFile: {
|
||||
metavar: '<PATH>',
|
||||
default: defaultConfig.limitFile,
|
||||
help: 'The path to the limit configuration file'
|
||||
},
|
||||
basicAuth: {
|
||||
metavar: '<USERNAME:PASSWORD>',
|
||||
help: 'Basic auth user & password'
|
||||
},
|
||||
browser: {
|
||||
abbr: 'b',
|
||||
metavar: '<BROWSER>',
|
||||
help: 'Choose which browser to use to collect timing data. You can set multiple browsers in a comma separated list (firefox|chrome|ie|phantomjs)',
|
||||
callback: function(browsers) {
|
||||
var b = browsers.split(','),
|
||||
invalidBrowsers = b.filter(function(browser) {
|
||||
return defaultConfig.supportedBrowsers.indexOf(browser) < 0;
|
||||
});
|
||||
},
|
||||
ruleSet: {
|
||||
metavar: '<RULE-SET>',
|
||||
default: defaultConfig.ruleSet,
|
||||
help: 'Which ruleset to use.'
|
||||
},
|
||||
limitFile: {
|
||||
metavar: '<PATH>',
|
||||
default: defaultConfig.limitFile,
|
||||
help: 'The path to the limit configuration file'
|
||||
},
|
||||
basicAuth: {
|
||||
metavar: '<USERNAME:PASSWORD>',
|
||||
help: 'Basic auth user & password'
|
||||
},
|
||||
browser: {
|
||||
abbr: 'b',
|
||||
metavar: '<BROWSER>',
|
||||
help: 'Choose which browser to use to collect timing data. You can set multiple browsers in a comma separated list (firefox|chrome|ie|phantomjs)',
|
||||
callback: function(browsers) {
|
||||
var b = browsers.split(','),
|
||||
invalidBrowsers = b.filter(function(browser) {
|
||||
return defaultConfig.supportedBrowsers.indexOf(browser.toLowerCase()) < 0;
|
||||
});
|
||||
|
||||
if (invalidBrowsers.length > 0) {
|
||||
return 'You specified a browser that is not supported:' + invalidBrowsers;
|
||||
if (invalidBrowsers.length > 0) {
|
||||
return 'You specified a browser that is not supported:' + invalidBrowsers;
|
||||
}
|
||||
}
|
||||
},
|
||||
profile: {
|
||||
metavar: '<desktop|mobile>',
|
||||
choices: ['desktop', 'mobile'],
|
||||
default: defaultConfig.profile,
|
||||
help: 'Choose between testing for desktop or mobile. Testing for desktop will use desktop rules & user agents, and vice verca'
|
||||
},
|
||||
no: {
|
||||
abbr: 'n',
|
||||
metavar: '<NUMBEROFTIMES>',
|
||||
default: defaultConfig.no,
|
||||
help: 'The number of times you should test each URL when fetching timing metrics. Default is ' + defaultConfig.no +
|
||||
' times',
|
||||
callback: function(n) {
|
||||
if (n != parseInt(n)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how many times you want to test one URL';
|
||||
} else if (parseInt(n) <= 0) {
|
||||
return 'You must specify a positive integer of how many times you want to test one URL';
|
||||
}
|
||||
}
|
||||
},
|
||||
screenshot: {
|
||||
flag: true,
|
||||
help: 'Take screenshots for each page (using the configured view port).'
|
||||
},
|
||||
junit: {
|
||||
flag: true,
|
||||
help: 'Create JUnit output'
|
||||
},
|
||||
tap: {
|
||||
flag: true,
|
||||
help: 'Create TAP output'
|
||||
},
|
||||
skipTest: {
|
||||
metavar: '<ruleid1,ruleid2,...>',
|
||||
help: 'A comma separeted list of rules to skip when generating JUnit'
|
||||
},
|
||||
threshold: {
|
||||
default: defaultConfig.threshold,
|
||||
metavar: '[0-100]',
|
||||
help: 'Threshold score for tests, will be used of no mathing thresholdFile with values match. Use : --threshold 95'
|
||||
},
|
||||
thresholdFile: {
|
||||
metavar: '<FILE>',
|
||||
help: 'A file containing JSON like {\'overall\': 90, \'thirdpartyversions\': 85}'
|
||||
},
|
||||
timingsThresholdFile: {
|
||||
metavar: '<FILE>',
|
||||
help: 'A file containing JSON like ...'
|
||||
},
|
||||
csv: {
|
||||
flag: true,
|
||||
help: 'Also output CSV where applicable'
|
||||
},
|
||||
maxPagesToTest: {
|
||||
abbr: 'm',
|
||||
metavar: '<NUMBEROFPAGES>',
|
||||
help: 'The max number of pages to test. Default is no limit'
|
||||
},
|
||||
proxy: {
|
||||
abbr: 'p',
|
||||
metavar: '<PROXY>',
|
||||
help: 'http://proxy.soulgalore.com:80'
|
||||
},
|
||||
cdns: {
|
||||
metavar: '<cdn1,cdn2>',
|
||||
list: true,
|
||||
help: 'A comma separated list of additional CDNs'
|
||||
},
|
||||
boxes: {
|
||||
metavar: '<box1,box2>',
|
||||
list: true,
|
||||
help: 'The boxes showed on site summary page, see http://www.sitespeed.io/documentation/#config-boxes for more info'
|
||||
},
|
||||
columns: {
|
||||
abbr: 'c',
|
||||
metavar: '<column1,column2>',
|
||||
list: true,
|
||||
help: 'The columns showed on detailed page summary table, see http://www.sitespeed.io/documentation/#config-columns for more info'
|
||||
},
|
||||
configFile: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a sitespeed.io config.json file, if it exists all other input parameters will be overidden'
|
||||
},
|
||||
// TODO How to override existing
|
||||
aggregators: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a directory with extra aggregators, see YYY'
|
||||
},
|
||||
// TODO maybe collectors are overkill
|
||||
collectors: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a directory with extra collectors, see YYY'
|
||||
},
|
||||
graphiteHost: {
|
||||
metavar: '<HOST>',
|
||||
help: 'The Graphite host'
|
||||
},
|
||||
graphitePort: {
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.graphitePort,
|
||||
help: 'Graphite port'
|
||||
},
|
||||
graphiteNamespace: {
|
||||
metavar: '<NAMESPACE>',
|
||||
default: defaultConfig.graphiteNamespace,
|
||||
help: 'The namespace of the data sent to Graphite'
|
||||
},
|
||||
graphiteData: {
|
||||
default: defaultConfig.graphiteData,
|
||||
help: 'Choose which data to send to Graphite by a comma separated list. Default all data is sent. [summary,rules,pagemetrics,timings]'
|
||||
},
|
||||
gpsiKey: {
|
||||
help: 'Your Google API Key, configure it to also fetch data from Google Page Speed Insights'
|
||||
},
|
||||
noYslow: {
|
||||
flag: true,
|
||||
help: 'Set to true to turn of collecting metrics using YSlow.',
|
||||
},
|
||||
wptLocation: {
|
||||
metavar: '<STRING>',
|
||||
help: 'WebPageTest location, something like Dulles:Chrome ',
|
||||
},
|
||||
wptUrl: {
|
||||
metavar: '<URL>',
|
||||
help: 'The URL to your private webpagetest instance'
|
||||
},
|
||||
wptKey: {
|
||||
metavar: '<KEY>',
|
||||
help: 'The API key if running on webpagetest on the public instances'
|
||||
},
|
||||
requestHeaders: {
|
||||
metavar: '<JSON>',
|
||||
help: 'Any request headers to use, in the JSON form of {\"name\":\"value\",\"name\":\"value\"}. Not supported for WPT & GPSI'
|
||||
}
|
||||
},
|
||||
profile: {
|
||||
metavar: '<desktop|mobile>',
|
||||
choices: ['desktop', 'mobile'],
|
||||
default: defaultConfig.profile,
|
||||
help: 'Choose between testing for desktop or mobile. Testing for desktop will use desktop rules & user agents, and vice verca'
|
||||
},
|
||||
no: {
|
||||
abbr: 'n',
|
||||
metavar: '<NUMBEROFTIMES>',
|
||||
default: defaultConfig.no,
|
||||
help: 'The number of times you should test each URL when fetching timing metrics. Default is ' + defaultConfig.no + ' times',
|
||||
callback: function(n) {
|
||||
if (n != parseInt(n)) { // jshint ignore:line
|
||||
return 'You must specify an integer of how many times you want to test one URL';
|
||||
}
|
||||
else if (parseInt(n) <= 0) {
|
||||
return 'You must specify a positive integer of how many times you want to test one URL';
|
||||
}
|
||||
}
|
||||
},
|
||||
screenshot: {
|
||||
flag: true,
|
||||
help: 'Take screenshots for each page (using the configured view port).'
|
||||
},
|
||||
junit: {
|
||||
flag: true,
|
||||
help: 'Create JUnit output'
|
||||
},
|
||||
tap: {
|
||||
flag: true,
|
||||
help: 'Create TAP output'
|
||||
},
|
||||
skipTest: {
|
||||
metavar: '<ruleid1,ruleid2,...>',
|
||||
help: 'A comma separeted list of rules to skip when generating JUnit'
|
||||
},
|
||||
threshold: {
|
||||
default: defaultConfig.threshold,
|
||||
metavar: '[0-100]',
|
||||
help: 'Threshold score for tests, will be used of no mathing thresholdFile with values match. Use : --threshold 95'
|
||||
},
|
||||
thresholdFile: {
|
||||
metavar: '<FILE>',
|
||||
help: 'A file containing JSON like {\'overall\': 90, \'thirdpartyversions\': 85}'
|
||||
},
|
||||
timingsThresholdFile: {
|
||||
metavar: '<FILE>',
|
||||
help: 'A file containing JSON like ...'
|
||||
},
|
||||
csv: {
|
||||
flag: true,
|
||||
help: 'Also output CSV where applicable'
|
||||
},
|
||||
maxPagesToTest: {
|
||||
abbr: 'm',
|
||||
metavar: '<NUMBEROFPAGES>',
|
||||
help: 'The max number of pages to test. Default is no limit'
|
||||
},
|
||||
proxy: {
|
||||
abbr: 'p',
|
||||
metavar: '<PROXY>',
|
||||
help: 'http://proxy.soulgalore.com:80'
|
||||
},
|
||||
cdns: {
|
||||
metavar: '<cdn1,cdn2>',
|
||||
list: true,
|
||||
help: 'A comma separated list of additional CDNs'
|
||||
},
|
||||
boxes: {
|
||||
metavar: '<box1,box2>',
|
||||
list: true,
|
||||
help: 'The boxes showed on site summary page, see http://www.sitespeed.io/documentation/#config-boxes for more info'
|
||||
},
|
||||
columns: {
|
||||
abbr: 'c',
|
||||
metavar: '<column1,column2>',
|
||||
list: true,
|
||||
help: 'The columns showed on detailed page summary table, see http://www.sitespeed.io/documentation/#config-columns for more info'
|
||||
},
|
||||
configFile: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a sitespeed.io config.json file, if it exists all other input parameters will be overidden'
|
||||
},
|
||||
// TODO How to override existing
|
||||
aggregators: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a directory with extra aggregators, see YYY'
|
||||
},
|
||||
// TODO maybe collectors are overkill
|
||||
collectors: {
|
||||
metavar: '<PATH>',
|
||||
help: 'The path to a directory with extra collectors, see YYY'
|
||||
},
|
||||
graphiteHost: {
|
||||
metavar: '<HOST>',
|
||||
help: 'The Graphite host'
|
||||
},
|
||||
graphitePort: {
|
||||
metavar: '<INTEGER>',
|
||||
default: defaultConfig.graphitePort,
|
||||
help: 'Graphite port'
|
||||
},
|
||||
graphiteNamespace: {
|
||||
metavar: '<NAMESPACE>',
|
||||
default: defaultConfig.graphiteNamespace,
|
||||
help: 'The namespace of the data sent to Graphite'
|
||||
},
|
||||
graphiteData: {
|
||||
default: defaultConfig.graphiteData,
|
||||
help: 'Choose which data to send to Graphite by a comma separated list. Default all data is sent. [summary,rules,pagemetrics,timings]'
|
||||
},
|
||||
gpsiKey: {
|
||||
help: 'Your Google API Key, configure it to also fetch data from Google Page Speed Insights'
|
||||
},
|
||||
noYslow: {
|
||||
flag: true,
|
||||
help: 'Set to true to turn of collecting metrics using YSlow.',
|
||||
},
|
||||
wptLocation: {
|
||||
metavar: '<STRING>',
|
||||
help: 'WebPageTest location, something like Dulles:Chrome ',
|
||||
},
|
||||
wptUrl: {
|
||||
metavar: '<URL>',
|
||||
help: 'The URL to your private webpagetest instance'
|
||||
},
|
||||
wptKey: {
|
||||
metavar: '<KEY>',
|
||||
help: 'The API key if running on webpagetest on the public instances'
|
||||
},
|
||||
requestHeaders: {
|
||||
metavar: '<JSON>',
|
||||
help: 'Any request headers to use, in the JSON form of {\"name\":\"value\",\"name\":\"value\"}. Not supported for WPT & GPSI'
|
||||
}
|
||||
}).parse();
|
||||
}).parse();
|
||||
|
||||
module.exports = cli;
|
||||
module.exports = cli;
|
||||
|
|
@ -186,20 +186,17 @@ function collectGPSI(pageData, p) {
|
|||
}
|
||||
|
||||
function collectPhantomJS(pageData, p) {
|
||||
|
||||
// for now just take the first value, in the future calculate median etc
|
||||
var timingsWeWillPush = ['min', 'mean', 'median', 'p90', 'p99', 'max'];
|
||||
p.phantomjs = {};
|
||||
pageData.phantomjs.runs.forEach(function(run) {
|
||||
Object.keys(run.timings).forEach(function(timing) {
|
||||
p.phantomjs[timing] = {
|
||||
'v': run.timings[timing],
|
||||
pageData.phantomjs.getStats().forEach(function(timing) {
|
||||
p.phantomjs[timing.id] = {};
|
||||
timingsWeWillPush.forEach(function(number) {
|
||||
p.phantomjs[timing.id][number] = {
|
||||
'v': timing.stats[number],
|
||||
'unit': 'milliseconds'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
console.log(JSON.stringify(p.phantomjs));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ function setupConfiguration(config) {
|
|||
if (config.browser) {
|
||||
var b = config.browser.split(','),
|
||||
configuredBrowsers = b.filter(function(browser) {
|
||||
return supportedBrowsers.indexOf(browser) > -1;
|
||||
return supportedBrowsers.indexOf(browser.toLowerCase()) > -1;
|
||||
});
|
||||
|
||||
if (configuredBrowsers.indexOf('phantomjs') > -1) {
|
||||
|
|
@ -516,7 +516,7 @@ function setupConfiguration(config) {
|
|||
else if (config.phantomjs) {
|
||||
config.summaryBoxes.push('domContentLoadedTimePhantomJS', 'pageLoadTimePhantomJS');
|
||||
config.sitesColumns.push('domContentLoadedTimePhantomJS');
|
||||
config.pageColumns.push('phantomjs.domContentLoadedTime');
|
||||
config.pageColumns.push('phantomjs.domContentLoadedTime.median');
|
||||
}
|
||||
|
||||
if (config.boxes) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue