FIX: Do not track first AJAX request as a pageview (#22661)

When the app boots, Ember fires a `routeWillChange` event. This was causing us to set the `_trackView` flag in our ajax library, which would cause the next request to have the `Discourse-Track-View` header, despite not being relevant to the page view. Depending on the plugins/themes installed, this could lead to 'double counting' of pageviews. (because the initial HTML request is also counted as a page view)

This commit updates the the logic to ignore the first transition (by checking `transition.from`), and also introduces an acceptance test for the behaviour.

Co-authored-by: Régis Hanol <regis@hanol.fr>
This commit is contained in:
David Taylor 2023-07-18 09:58:01 +01:00 committed by GitHub
parent f76a9aab22
commit 104baab557
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 3 deletions

View File

@ -3,7 +3,7 @@ import {
resetPageTracking, resetPageTracking,
startPageTracking, startPageTracking,
} from "discourse/lib/page-tracker"; } from "discourse/lib/page-tracker";
import { viewTrackingRequired } from "discourse/lib/ajax"; import { resetAjax, trackNextAjaxAsPageview } from "discourse/lib/ajax";
export default { export default {
after: "inject-objects", after: "inject-objects",
@ -11,7 +11,7 @@ export default {
initialize(owner) { initialize(owner) {
// Tell our AJAX system to track a page transition // Tell our AJAX system to track a page transition
const router = owner.lookup("router:main"); const router = owner.lookup("router:main");
router.on("routeWillChange", viewTrackingRequired); router.on("routeWillChange", this.handleRouteWillChange);
let appEvents = owner.lookup("service:app-events"); let appEvents = owner.lookup("service:app-events");
let documentTitle = owner.lookup("service:document-title"); let documentTitle = owner.lookup("service:document-title");
@ -64,7 +64,15 @@ export default {
} }
}, },
handleRouteWillChange(transition) {
// will be null on initial boot transition, which is already tracked as a pageview via the HTML request
if (transition.from) {
trackNextAjaxAsPageview();
}
},
teardown() { teardown() {
resetPageTracking(); resetPageTracking();
resetAjax();
}, },
}; };

View File

@ -15,10 +15,14 @@ export function setTransientHeader(key, value) {
_transientHeader = { key, value }; _transientHeader = { key, value };
} }
export function viewTrackingRequired() { export function trackNextAjaxAsPageview() {
_trackView = true; _trackView = true;
} }
export function resetAjax() {
_trackView = false;
}
export function setLogoffCallback(cb) { export function setLogoffCallback(cb) {
_logoffCallback = cb; _logoffCallback = cb;
} }

View File

@ -0,0 +1,39 @@
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
import { click, visit } from "@ember/test-helpers";
import { test } from "qunit";
import pretender from "discourse/tests/helpers/create-pretender";
acceptance("Page tracking", function () {
test("sets the discourse-track-view header correctly", async function (assert) {
const trackViewHeaderName = "Discourse-Track-View";
assert.strictEqual(
pretender.handledRequests.length,
0,
"no requests logged before app boot"
);
await visit("/");
assert.strictEqual(
pretender.handledRequests.length,
1,
"one request logged during app boot"
);
assert.strictEqual(
pretender.handledRequests[0].requestHeaders[trackViewHeaderName],
undefined,
"does not track view for ajax before a transition has taken place"
);
await click("#site-logo");
assert.strictEqual(
pretender.handledRequests.length,
2,
"second request logged during next transition"
);
assert.strictEqual(
pretender.handledRequests[1].requestHeaders[trackViewHeaderName],
"true",
"sends track-view header for subsequent requests"
);
});
});