Skip to content

Commit

Permalink
Angular: Don't trigger Route Change on $locationChangeStart if other …
Browse files Browse the repository at this point in the history
…events fire
  • Loading branch information
nicjansma committed Apr 4, 2018
1 parent 4fe7ec0 commit 1cce81c
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 7 deletions.
25 changes: 19 additions & 6 deletions plugins/angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
enabled = true,
hadMissedRouteChange = false,
lastRouteChangeTime = 0,
locationChangeTrigger = false;
locationChangeTrigger = false,
disableLocationChangeTrigger = false;

if (BOOMR.plugins.Angular || typeof BOOMR.plugins.SPA === "undefined") {
return;
Expand Down Expand Up @@ -124,6 +125,10 @@
log("$routeChangeStart: " + (next ? next.templateUrl : ""));

fireRouteChange(event, next, current);

// Since we've seen a $routeChangeStart, we don't need to have
// $locationChangeStarts also trigger navigations.
disableLocationChangeTrigger = true;
});

// Listen for $locationChangeStart to know the new URL when the route changes
Expand All @@ -136,11 +141,15 @@

BOOMR.fireEvent("spa_init", [BOOMR.plugins.SPA.current_spa_nav(), newState]);

// Fire a route change (on a short delay) after this callback in case
// $routeChangeStart never fires. We'd prefer to use $routeChangeStart's
// arguments (next, current) for any routeFilter, so use a setTimeout
// that may be cancelled by the $routeChangeStart/$stateChangeStart event.
locationChangeTrigger = setTimeout(fireRouteChange, 0);
// If we haven't yet seen $routeChangeStart or $stateChangeStart, we might
// be in an app that only uses $locationChangeStart to trigger navigations.
if (!disableLocationChangeTrigger) {
// Fire a route change (on a short delay) after this callback in case
// $routeChangeStart is about to fire. We'd prefer to use $routeChangeStart's
// arguments (next, current) for any routeFilter, so use a setTimeout
// that may be cancelled by the $routeChangeStart/$stateChangeStart event.
locationChangeTrigger = setTimeout(fireRouteChange, 0);
}
});

//
Expand All @@ -155,6 +164,10 @@
log("$stateChangeStart: " + toState);

fireRouteChange(event, toState, toParams, fromState, fromParams);

// Since we've seen a $stateChangeStart, we don't need to have
// $locationChangeStarts also trigger navigations.
disableLocationChangeTrigger = true;
});

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// view a widget then come back so debugging (F5) is easier
window.angular_nav_routes = ["/nothing", "108-location-change-only.html"];

window.angular_only_change_loc = true;
window.angular_no_route = true;
</script>
<script src="support/app.js"></script>
Expand Down
34 changes: 34 additions & 0 deletions tests/page-templates/05-angular/113-late-locationchangestart.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<%= header %>
<%= boomerangScript %>
<base href="/pages/05-angular/113-late-locationchangestart.html" />
<script src="../../vendor/angular/angular.js"></script>
<script src="../../vendor/angular-resource/angular-resource.js"></script>
<script src="../../vendor/angular-ui-router/release/angular-ui-router.js"></script>
<script>
window.angular_imgs = [3000];

window.angular_html5_mode = true;

window.angular_nav_routes = ["/widgets/1", "113-late-locationchangestart.html"];

window.angularBroadcastLocationAfterStateChange = true;
</script>
<script src="support/app-ui-router.js"></script>
<div ui-view></div>
<script src="113-late-locationchangestart.js" type="text/javascript"></script>
<script>
BOOMR_test.init({
testAfterOnBeacon: 3,
Angular: {
enabled: true
},
instrument_xhr: true,
autorun: false
});

/*global angular*/
document.addEventListener("DOMContentLoaded", function() {
angular.bootstrap(document, ["app"]);
});
</script>
<%= footer %>
107 changes: 107 additions & 0 deletions tests/page-templates/05-angular/113-late-locationchangestart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*eslint-env mocha*/
/*global BOOMR_test,assert*/
describe("e2e/05-angular/113-late-locationchangestart", function() {
var tf = BOOMR.plugins.TestFramework;
var t = BOOMR_test;

var pathName = window.location.pathname;

it("Should pass basic beacon validation", function(done) {
t.validateBeaconWasSent(done);
});

it("Should have sent three beacons", function() {
assert.equal(tf.beacons.length, 3);
});

it("Should have sent the first beacon as http.initiator = spa_hard", function() {
assert.equal(tf.beacons[0]["http.initiator"], "spa_hard");
});

it("Should have sent all subsequent beacons as http.initiator = spa", function() {
for (var i = 1; i < 2; i++) {
assert.equal(tf.beacons[i]["http.initiator"], "spa");
}
});

//
// Beacon 1
//
it("Should have sent the first beacon for " + pathName, function() {
var b = tf.beacons[0];
assert.isTrue(b.u.indexOf(pathName) !== -1);
});

it("Should take as long as the longest img load (if MutationObserver and NavigationTiming are supported)", function() {
if (window.MutationObserver && typeof BOOMR.plugins.RT.navigationStart() !== "undefined") {
t.validateBeaconWasSentAfter(0, "img.jpg&id=home", 500, 3000, 30000, 0);
}
});

it("Should not have a load time (if MutationObserver is supported but NavigationTiming is not)", function() {
if (window.MutationObserver && typeof BOOMR.plugins.RT.navigationStart() === "undefined") {
var b = tf.beacons[0];
assert.equal(b.t_done, undefined);
}
});

it("Should take as long as the XHRs (if MutationObserver is not supported but NavigationTiming is)", function() {
if (typeof window.MutationObserver === "undefined" && typeof BOOMR.plugins.RT.navigationStart() !== "undefined") {
t.validateBeaconWasSentAfter(0, "widgets.json", 500, 0, 30000, false);
}
});

it("Shouldn't have a load time (if MutationObserver and NavigationTiming are not supported)", function() {
if (typeof window.MutationObserver === "undefined" && typeof BOOMR.plugins.RT.navigationStart() === "undefined") {
var b = tf.beacons[0];
assert.equal(b.t_done, undefined);
assert.equal(b["rt.start"], "none");
}
});

//
// Beacon 2
//
it("Should have sent the second beacon for /widgets/1", function() {
var b = tf.beacons[1];
assert.isTrue(b.u.indexOf("/widgets/1") !== -1);
});

it("Should have sent the second beacon with a timestamp of at least 1 second (if MutationObserver is supported)", function() {
if (window.MutationObserver) {
// because of the widget IMG delaying 1 second
var b = tf.beacons[1];
assert.operator(b.t_done, ">=", 1000);
}
});

it("Should have sent the second beacon with a timestamp of at least 1 millisecond (if MutationObserver is not supported)", function() {
if (typeof window.MutationObserver === "undefined") {
// because of the widget IMG delaying 1 second but we couldn't track it because no MO support
var b = tf.beacons[1];
assert.operator(b.t_done, ">=", 0);
}
});

//
// Beacon 3
//
it("Should have sent the third beacon for " + pathName, function() {
var b = tf.beacons[2];
assert.isTrue(b.u.indexOf(pathName) !== -1);
});

it("Should have sent the third with a timestamp of at least 3 seconds (if MutationObserver is supported)", function() {
if (window.MutationObserver) {
var b = tf.beacons[2];
assert.operator(b.t_done, ">=", 3000);
}
});

it("Should have sent the third with a timestamp of under 1 second (if MutationObserver is not supported)", function() {
if (!window.MutationObserver) {
var b = tf.beacons[2];
assert.operator(b.t_done, "<=", 1000);
}
});
});
7 changes: 7 additions & 0 deletions tests/page-templates/05-angular/support/app-ui-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ angular.module("app", ["ngResource", "ui.router"])

$timeout(function() {
$location.url(nextRoute);

if (window.angularBroadcastLocationAfterStateChange) {
$timeout(function() {
// for
$rootScope.$broadcast("$locationChangeStart", null, null, null, null);
}, 500);
}
}, 100);
}

Expand Down

0 comments on commit 1cce81c

Please sign in to comment.