From d74c974fbb560e2efa002a1a4d4fcb0fd62c6122 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 00:19:52 +0100 Subject: [PATCH 1/8] IPC: handle passing multiple values --- core/ipc.js | 4 ++-- lib/ipc.js | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/ipc.js b/core/ipc.js index e5fca2d05..f8217a78b 100644 --- a/core/ipc.js +++ b/core/ipc.js @@ -9,10 +9,10 @@ function ipc(event) { this.event = event; } -ipc.prototype.push = function(data) { +ipc.prototype.push = function() { stderr.writeLine(JSON.stringify({ event: this.event, - data: data + data: Array.prototype.slice.apply(arguments) })); }; diff --git a/lib/ipc.js b/lib/ipc.js index 7ddb0e0c5..058dbf70e 100644 --- a/lib/ipc.js +++ b/lib/ipc.js @@ -23,10 +23,14 @@ ipc.prototype.init = function() { messages.forEach(function(msg) { if (msg === '') return; - debug('%s', msg); msg = JSON.parse(msg); + debug('%s: %j', msg.event, msg.data); - self.events.emit(msg.event, msg.data); + // send event name and the rest of the data + var args = msg.data; + args.unshift(msg.event); + + self.events.emit.apply(self.events, args); }); }); }; From cf81c3c1ec8ac19ecf92dca94b08304528603f07 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 00:20:32 +0100 Subject: [PATCH 2/8] Handle "milestone" event in npm module Bind to IPC event and propagate it via npm module --- lib/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/index.js b/lib/index.js index f2236588e..59453808a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -112,6 +112,14 @@ function phantomas(url, options, callback) { events.emit('progress', progress); }); + // handle page loading milestones (#240) + var milestoneDebug = require('debug')('phantomas:milestone'); + + ipc.on('milestone', function(ev, time) { + milestoneDebug('%s: %d ms', ev, time); + events.emit('milestone', ev. time); + }); + // process results proc.on('close', function(code) { var debug = require('debug')('phantomas:results'), From 94254fc449df0bc02f205765671a47e7a3def840 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 00:21:20 +0100 Subject: [PATCH 3/8] requestsMonitor: emit "milestone" emit on TTFB / TTLB --- core/modules/requestsMonitor/requestsMonitor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/modules/requestsMonitor/requestsMonitor.js b/core/modules/requestsMonitor/requestsMonitor.js index 1582cf7cf..10033fcb0 100644 --- a/core/modules/requestsMonitor/requestsMonitor.js +++ b/core/modules/requestsMonitor/requestsMonitor.js @@ -1,7 +1,7 @@ /** * Simple HTTP requests monitor and analyzer */ -exports.version = '1.1'; +exports.version = '1.2'; exports.module = function(phantomas) { // imports @@ -275,7 +275,8 @@ exports.module = function(phantomas) { }); // TTFB / TTLB metrics - var ttfbMeasured = false; + var ttfbMeasured = false, + ipc = new (require('../../ipc'))('milestone'); phantomas.on('recv', function(entry, res) { // check the first response which is not a redirect (issue #74) @@ -283,6 +284,9 @@ exports.module = function(phantomas) { phantomas.setMetric('timeToFirstByte', entry.timeToFirstByte); phantomas.setMetric('timeToLastByte', entry.timeToLastByte); + ipc.push('timeToFirstByte', entry.timeToFirstByte); + ipc.push('timeToLastByte', entry.timeToLastByte); + ttfbMeasured = true; phantomas.log('Time to first byte: set to %d ms for <%s> (HTTP %d)', entry.timeToFirstByte, entry.url, entry.status); From 6df55876e4610d39624138adb23b888b32bb6060 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 20:57:23 +0100 Subject: [PATCH 4/8] Typo --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 59453808a..3f343f553 100644 --- a/lib/index.js +++ b/lib/index.js @@ -117,7 +117,7 @@ function phantomas(url, options, callback) { ipc.on('milestone', function(ev, time) { milestoneDebug('%s: %d ms', ev, time); - events.emit('milestone', ev. time); + events.emit('milestone', ev, time); }); // process results From 10a500291385a3569336dc17c8d8a7c122d66061 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 20:57:47 +0100 Subject: [PATCH 5/8] Add an example script for npm module --- examples/npm.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 examples/npm.js diff --git a/examples/npm.js b/examples/npm.js new file mode 100755 index 000000000..f1bfce76e --- /dev/null +++ b/examples/npm.js @@ -0,0 +1,36 @@ +#!/usr/bin/env node + +/** + * Example script that uses phantomas npm module + */ +var phantomas = require('../'), + run; + +console.log('phantomas v%s loaded from %s', phantomas.version, phantomas.path); + +run = phantomas('http://google.is', { + 'analyze-css': true, + 'assert-requests': 1 +}); + +console.log('Running phantomas: pid %d', run.pid); + +// errors handling +run.on('error', function(code) { + console.log('Exit code #%d', code); +}); + +// handle results +run.on('results', function(results) { + console.log('Number of requests: %d', results.getMetric('requests')); + console.log('Failed asserts: %j', results.getFailedAsserts()); +}); + +// events handling +run.on('progress', function(progress) { + console.log('Loading progress: %d%', progress); +}); + +run.on('milestone', function(milestone, timing) { + console.log('%s at %d ms', milestone, timing); +}); From ba9a4775ca492446ed9675213ef2c6daf8fc4f14 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 21:01:14 +0100 Subject: [PATCH 6/8] Extend the mock for system module --- test/public-api-test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/public-api-test.js b/test/public-api-test.js index 1777a89e1..243cd5e04 100644 --- a/test/public-api-test.js +++ b/test/public-api-test.js @@ -14,7 +14,10 @@ mockery.registerMock('fs', { list: function() {} }); mockery.registerMock('system', { - os: {} + os: {}, + stderr: { + writeLine: function() {} + } }); mockery.registerMock('webpage', { create: function() { From dff0488cbdba494fb10f9fd00fde006c9efa687f Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 21:52:34 +0100 Subject: [PATCH 7/8] Send "metric" event via IPC from setMetric method --- core/phantomas.js | 17 ++++++++++++----- core/scope.js | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/phantomas.js b/core/phantomas.js index ddb115783..8b01c0d39 100644 --- a/core/phantomas.js +++ b/core/phantomas.js @@ -692,7 +692,7 @@ phantomas.prototype = { break; case 'setMetric': - this.setMetric(data.name, data.value); + this.setMetric(data.name, data.value, data.isFinal); break; case 'incrMetric': @@ -718,13 +718,20 @@ phantomas.prototype = { }, // metrics reporting - setMetric: function(name, value) { + setMetric: function(name, value, isFinal) { + var ipc = new (require('./ipc'))('metric'); + value = typeof value === 'string' ? value : (value || 0); // set to zero if undefined / null is provided this.results.setMetric(name, value); + + // trigger an event when the metric value is said to be final (isse #240) + if (isFinal === true) { + ipc.push(name, value); + } }, setMetricEvaluate: function(name, fn) { - this.setMetric(name, this.page.evaluate(fn)); + this.setMetric(name, this.page.evaluate(fn), true /* isFinal */); }, setMarkerMetric: function(name) { @@ -735,7 +742,7 @@ phantomas.prototype = { throw 'setMarkerMetric() called before responseEnd event!'; } - this.results.setMetric(name, value); + this.setMetric(name, value, true /* isFinal */); return value; }, @@ -746,7 +753,7 @@ phantomas.prototype = { // @ee https://github.com/ariya/phantomjs/wiki/API-Reference-WebPage#evaluatefunction-arg1-arg2--object this.setMetric(name, this.page.evaluate(function(key) { return window.__phantomas.get(key) || 0; - }, key)); + }, key), true /* isFinal */); }, // get a value set using window.__phantomas browser scope diff --git a/core/scope.js b/core/scope.js index 7092560d7..b02202249 100644 --- a/core/scope.js +++ b/core/scope.js @@ -141,8 +141,8 @@ sendMsg('log', msg); } - function setMetric(name, value) { - sendMsg('setMetric', {name: name, value: (typeof value !== 'undefined') ? value : 0}); + function setMetric(name, value, isFinal) { + sendMsg('setMetric', {name: name, value: (typeof value !== 'undefined') ? value : 0, isFinal: isFinal === true}); } function incrMetric(name, incr /* =1 */) { From ba3add39bb6169675b58a1261588761c827c3798 Mon Sep 17 00:00:00 2001 From: Maciej Brencz Date: Thu, 27 Feb 2014 22:23:53 +0100 Subject: [PATCH 8/8] Emit "milestone" event for certain metrics --- core/modules/requestsMonitor/requestsMonitor.js | 10 +++------- lib/index.js | 13 ++++++++++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/modules/requestsMonitor/requestsMonitor.js b/core/modules/requestsMonitor/requestsMonitor.js index 10033fcb0..afb2b9f20 100644 --- a/core/modules/requestsMonitor/requestsMonitor.js +++ b/core/modules/requestsMonitor/requestsMonitor.js @@ -275,17 +275,13 @@ exports.module = function(phantomas) { }); // TTFB / TTLB metrics - var ttfbMeasured = false, - ipc = new (require('../../ipc'))('milestone'); + var ttfbMeasured = false; phantomas.on('recv', function(entry, res) { // check the first response which is not a redirect (issue #74) if (!ttfbMeasured && !entry.isRedirect) { - phantomas.setMetric('timeToFirstByte', entry.timeToFirstByte); - phantomas.setMetric('timeToLastByte', entry.timeToLastByte); - - ipc.push('timeToFirstByte', entry.timeToFirstByte); - ipc.push('timeToLastByte', entry.timeToLastByte); + phantomas.setMetric('timeToFirstByte', entry.timeToFirstByte, true); + phantomas.setMetric('timeToLastByte', entry.timeToLastByte, true); ttfbMeasured = true; diff --git a/lib/index.js b/lib/index.js index 3f343f553..761e16acb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -115,9 +115,16 @@ function phantomas(url, options, callback) { // handle page loading milestones (#240) var milestoneDebug = require('debug')('phantomas:milestone'); - ipc.on('milestone', function(ev, time) { - milestoneDebug('%s: %d ms', ev, time); - events.emit('milestone', ev, time); + ipc.on('metric', function(metric, value) { + switch(metric) { + case 'timeToFirstByte': + case 'timeToLastByte': + case 'onDOMReadyTime': + case 'windowOnLoadTime': + milestoneDebug('%s: %d ms', metric, value); + events.emit('milestone', metric, value); + break; + } }); // process results