From aee6c740b4e7626215a9af241a3972997414b5c5 Mon Sep 17 00:00:00 2001 From: diosmosis <benaka@piwik.pro> Date: Fri, 12 Jun 2015 02:23:40 -0700 Subject: [PATCH] Use Q promise library to accurately and cleanly test the heart beat feature in the JS tracker. --- js/piwik.js | 2 +- tests/javascript/index.php | 129 ++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 61 deletions(-) diff --git a/js/piwik.js b/js/piwik.js index 16701cf08c..ec93b97806 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -3253,7 +3253,7 @@ if (typeof Piwik !== 'object') { */ function heartBeatPingIfActivity() { var now = new Date(); - if (lastTrackerRequestTime + configHeartBeatDelay < now.getTime()) { + if (lastTrackerRequestTime + configHeartBeatDelay <= now.getTime()) { var requestPing = getRequest('ping=1', null, 'ping'); sendRequest(requestPing, configTrackerPause); diff --git a/tests/javascript/index.php b/tests/javascript/index.php index f45bb06dac..5872b490d9 100644 --- a/tests/javascript/index.php +++ b/tests/javascript/index.php @@ -54,6 +54,7 @@ testTrackPageViewAsync(); } ?> </script> + <script src="../lib/q-1.4.1/q.js" type="text/javascript"></script> <script src="../../js/piwik.js?rand=<?php echo md5(uniqid(mt_rand(), true)) ?>" type="text/javascript"></script> <script src="../../plugins/Overlay/client/urlnormalizer.js" type="text/javascript"></script> <script src="piwiktest.js" type="text/javascript"></script> @@ -215,8 +216,9 @@ function triggerEvent(element, type, buttonNumber) { buttonNumber = 0; } - var event = document.createEvent( "MouseEvents" ); - event.initMouseEvent(type, true, true, element.ownerDocument.defaultView, + var event = document.createEvent( "MouseEvents" ), + docView = element == window ? element : element.ownerDocument.defaultView; + event.initMouseEvent(type, true, true, docView, 0, 0, 0, 0, 0, false, false, false, false, buttonNumber, null); element.dispatchEvent( event ); } else if ( element.fireEvent ) { @@ -2547,7 +2549,7 @@ function PiwikTest() { function link() { lastInteractionType = "link"; } function load() { lastInteractionType = "load"; } function log() { lastInteractionType = "log"; } - function ping() { lastInteractionType = "ping"; } + function ping() { lastInteractionType = "ping"; return "&dummy=1"; } function sitesearch() { lastInteractionType = "sitesearch"; } function unload() { lastInteractionType = "unload"; } function getLastInteractionType() { return lastInteractionType; } @@ -2720,9 +2722,7 @@ if ($sqlite) { test("tracking", function() { expect(101); - /* - * Prevent Opera and HtmlUnit from performing the default action (i.e., load the href URL) - */ + // Prevent Opera and HtmlUnit from performing the default action (i.e., load the href URL) var stopEvent = function (evt) { evt = evt || window.event; @@ -3103,80 +3103,87 @@ if ($sqlite) { // heartbeat tests test("trackingHeartBeat", function () { - expect(11); + expect(14); var tokenBase = getHeartbeatToken(); var tracker = Piwik.getTracker(); tracker.setTrackerUrl("piwik.php"); tracker.setSiteId(1); - tracker.setHeartBeatTimer(1); - - // test ping heart beat not set up until an initial request tracked - tracker.setCustomData('token', 1 + tokenBase); - wait(1200); - - // test ping not sent on initial page load, and sent if inactive for N secs. - tracker.setCustomData('token', 2 + tokenBase); - tracker.trackPageView('whatever'); // normal request sent here - triggerEvent(document.body, 'focus'); - - wait(1200); // ping request sent after this - - // test ping not sent after N secs, if tracking request sent in the mean time - tracker.setCustomData('token', 3 + tokenBase); - - wait(200); - tracker.trackPageView('whatever2'); // normal request sent here - wait(200); - - wait(1000); // ping request NOT sent here - - // test ping sent N secs after second tracking request if inactive. - tracker.setCustomData('token', 4 + tokenBase); - - wait(1000); // ping request sent here - - // test ping not sent N secs after, if window blur event triggered (ie tab switch) and N secs pass. - tracker.setCustomData('token', 5 + tokenBase); - triggerEvent(document.body, 'blur'); - - wait(1000); // ping request not sent here - - // test ping sent immediately if tab switched and more than N secs pass, then tab switched back - tracker.setCustomData('token', 6 + tokenBase); - - triggerEvent(document.body, 'focus'); // ping request sent here + tracker.setHeartBeatTimer(3); stop(); - setTimeout(function() { + Q.delay(1).then(function () { + // test ping heart beat not set up until an initial request tracked + tracker.setCustomData('token', 1 + tokenBase); + + return Q.delay(3500); + }).then(function () { + // test ping not sent on initial page load, and sent if inactive for N secs. + tracker.setCustomData('token', 2 + tokenBase); + tracker.trackPageView('whatever'); // normal request sent here + }).then(function () { + triggerEvent(window, 'focus'); + + return Q.delay(4000); // ping request sent after this (afterwards 2 secs to next heartbeat) + }).then(function () { + // test ping not sent after N secs, if tracking request sent in the mean time + tracker.setCustomData('token', 3 + tokenBase); + + tracker.trackPageView('whatever2'); // normal request sent here + // heart beat will trigger in 2 secs, then reset to 1 sec later, since tracker request + // was sent 2 secs ago + }).then(function () { + return Q.delay(2100); // ping request NOT sent here (heart beat triggered. after, .9s to next heartbeat) + }).then(function () { + // test ping sent N secs after second tracking request if inactive. + tracker.setCustomData('token', 4 + tokenBase); + + return Q.delay(2100); // ping request sent here (heart beat triggered after 1s; 2s to next heart beat) + }).then(function () { + // test ping not sent N secs after, if window blur event triggered (ie tab switch) and N secs pass. + tracker.setCustomData('token', 5 + tokenBase); + + triggerEvent(window, 'blur'); + + return Q.delay(3000); // ping request not sent here (heart beat triggered after 2s; 1s to next heart beat) + }).then(function () { + // test ping sent immediately if tab switched and more than N secs pass, then tab switched back + tracker.setCustomData('token', 6 + tokenBase); + + triggerEvent(window, 'focus'); // ping request sent here + + tracker.clearHeartBeat(); // flatline + + return Q.delay(1000); // for the ping request to get sent + }).then(function () { var token; var requests = fetchTrackedRequests(token = 1 + tokenBase, true); - equal(requests.length, 0, "no requests sent before initial non-ping request sent"); + equal(requests.length, 0, "[token = 1] no requests sent before initial non-ping request sent"); requests = fetchTrackedRequests(token = 2 + tokenBase, true); - ok(/action_name=whatever/.test(requests[0]) && !(/ping=1/.test(requests[0])), "first request is page view not ping"); - ok(/ping=1/.test(requests[1]), "second request is ping request"); - equal(requests.length, 2, "only 2 requests sent for normal ping"); + ok(/action_name=whatever/.test(requests[0]) && !(/ping=1/.test(requests[0])), "[token = 2] first request is page view not ping"); + ok(/ping=1/.test(requests[1]), "[token = 2] second request is ping request"); + equal(requests.length, 2, "[token = 2] only 2 requests sent for normal ping"); requests = fetchTrackedRequests(token = 3 + tokenBase, true); - ok(/action_name=whatever2/.test(requests[0]) && !(/ping=1/.test(requests[0])), "first request is page view not ping"); - equal(requests.length, 1, "no ping request sent if other request sent in meantime"); + ok(/action_name=whatever2/.test(requests[0]) && !(/ping=1/.test(requests[0])), "[token = 3] first request is page view not ping"); + equal(requests.length, 1, "[token = 3] no ping request sent if other request sent in meantime"); requests = fetchTrackedRequests(token = 4 + tokenBase, true); - ok(/ping=1/.test(requests[0]), "ping request sent if no other activity and after heart beat"); - equal(requests.length, 1, "only ping request sent if no other activity"); + ok(/ping=1/.test(requests[0]), "[token = 4] ping request sent if no other activity and after heart beat"); + equal(requests.length, 1, "[token = 4] only ping request sent if no other activity"); requests = fetchTrackedRequests(token = 5 + tokenBase, true); - equal(requests.length, 0, "no requests sent if window not in focus"); + equal(requests.length, 0, "[token = 5] no requests sent if window not in focus"); requests = fetchTrackedRequests(token = 6 + tokenBase, true); - ok(/ping=1/.test(requests[0]), "ping sent after window regains focus"); - equal(requests.length, 1, "only one ping request sent after window regains focus"); + ok(/ping=1/.test(requests[0]), "[token = 6] ping sent after window regains focus"); + equal(requests.length, 1, "[token = 6] only one ping request sent after window regains focus"); start(); - }, 6000); + }); }); test("trackingContent", function() { @@ -3664,7 +3671,8 @@ if ($sqlite) { ?> } -function addEventListener(element, eventType, eventHandler, useCapture) { +// do not name this addEventListener so it won't overwrite the member in window +function customAddEventListener(element, eventType, eventHandler, useCapture) { if (element.addEventListener) { element.addEventListener(eventType, eventHandler, useCapture); return true; @@ -3677,7 +3685,7 @@ function addEventListener(element, eventType, eventHandler, useCapture) { (function (f) { if (document.addEventListener) { - addEventListener(document, 'DOMContentLoaded', function ready() { + customAddEventListener(document, 'DOMContentLoaded', function ready() { document.removeEventListener('DOMContentLoaded', ready, false); f(); }); @@ -3702,8 +3710,9 @@ function addEventListener(element, eventType, eventHandler, useCapture) { } }()); } + } else { + customAddEventListener(window, 'load', f, false); } - addEventListener(window, 'load', f, false); })(PiwikTest); </script> -- GitLab