Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:referrer #327

Merged
merged 12 commits into from
Jan 26, 2023
9 changes: 9 additions & 0 deletions app/page_event.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@
cwr('recordPageView', '/page_view_two');
}

function createReferrer() {
Object.defineProperty(document, 'referrer', {
value: 'http://amazon.com/searchresults/1/'
});
}

function recordPageViewWithPageTagAttribute() {
cwr('recordPageView', {
pageId: '/page_view_two',
Expand Down Expand Up @@ -179,6 +185,9 @@
<button id="doNotRecordPageView" onclick="doNotRecordPageView()">
Do Not Record Page View
</button>
<button id="createReferrer" onclick="createReferrer()">
Create Referrer
</button>
<hr />
<span id="request"></span>
<span id="response"></span>
Expand Down
4 changes: 3 additions & 1 deletion src/event-schemas/page-view-event.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"pageId": { "type": "string" },
"pageInteractionId": { "type": "string" },
"interaction": { "type": "number" },
"parentPageInteractionId": { "type": "string" }
"parentPageInteractionId": { "type": "string" },
"referrer": { "type": "string" },
"referrerDomain": { "type": "string" }
},
"additionalProperties": false,
"required": ["pageId"]
Expand Down
22 changes: 22 additions & 0 deletions src/sessions/PageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export type Page = {
pageId: string;
interaction: number;
parentPageId?: string;
referrer?: string | null;
referrerDomain?: string | null;
start: number;
};

Expand Down Expand Up @@ -129,6 +131,8 @@ export class PageManager {
pageId,
parentPageId: resumed.pageId,
interaction: resumed.interaction + 1,
referrer: document.referrer,
referrerDomain: this.getDomainFromReferrer(),
start: Date.now()
};
this.resumed = undefined;
Expand Down Expand Up @@ -165,6 +169,8 @@ export class PageManager {
pageId,
parentPageId: currentPage.pageId,
interaction: currentPage.interaction + 1,
referrer: document.referrer,
referrerDomain: this.getDomainFromReferrer(),
start: startTime
};
}
Expand All @@ -173,6 +179,8 @@ export class PageManager {
this.page = {
pageId,
interaction: 0,
referrer: document.referrer,
referrerDomain: this.getDomainFromReferrer(),
start: Date.now()
};
}
Expand Down Expand Up @@ -220,6 +228,9 @@ export class PageManager {
pageViewEvent.parentPageInteractionId =
page.parentPageId + '-' + (page.interaction - 1);
}

pageViewEvent.referrer = document.referrer;
pageViewEvent.referrerDomain = this.getDomainFromReferrer();
}

return pageViewEvent;
Expand All @@ -235,4 +246,15 @@ export class PageManager {
private useCookies() {
return navigator.cookieEnabled && this.config.allowCookies;
}

/*
Parses the domain from the referrer, if it is available
*/
private getDomainFromReferrer() {
try {
return new URL(document.referrer).hostname;
} catch (e) {
return document.referrer === 'localhost' ? document.referrer : '';
}
}
Comment on lines +253 to +259
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider covering these (localhost and empty referrer) with unit tests.

}
30 changes: 30 additions & 0 deletions src/sessions/__integ__/PageManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const recordPageViewWithCustomPageAttributes: Selector = Selector(
const dispatch: Selector = Selector(`#dispatch`);
const clear: Selector = Selector(`#clearRequestResponse`);
const doNotRecordPageView = Selector(`#doNotRecordPageView`);
const createReferrer: Selector = Selector(`#createReferrer`);

fixture('PageViewEventPlugin').page('http://localhost:8080/page_event.html');

Expand Down Expand Up @@ -206,3 +207,32 @@ test('when custom page attributes are set when manually recording page view even
customPageAttributeBoolean: true
});
});

test('when referrer exists, then page view event details records it', async (t: TestController) => {
// If we click too soon, the client/event collector plugin will not be loaded and will not record the click.
// This could be a symptom of an issue with RUM web client load speed, or prioritization of script execution.

await t
.wait(300)
.click(dispatch)
.expect(REQUEST_BODY.textContent)
.contains('BatchId')
.click(clear)
.wait(300)
.click(createReferrer)
.click(recordPageView)
.click(dispatch)
.expect(REQUEST_BODY.textContent)
.contains('BatchId');

const requestBody = JSON.parse(await REQUEST_BODY.textContent);

const pages = requestBody.RumEvents.filter(
(e) => e.type === PAGE_VIEW_EVENT_TYPE
).map((e) => JSON.parse(e.details));

await t.expect(pages.length).eql(1).expect(pages[0]).contains({
referrer: 'http://amazon.com/searchresults/1/',
referrerDomain: 'amazon.com'
});
});
116 changes: 115 additions & 1 deletion src/sessions/__tests__/PageManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const record = jest.fn();
declare const jsdom: any;

Object.defineProperty(document, 'referrer', {
value: 'https://console.aws.amazon.com'
value: 'https://console.aws.amazon.com',
configurable: true
});
Object.defineProperty(document, 'title', { value: 'Amazon AWS Console' });
global.fetch = mockFetch;
Expand Down Expand Up @@ -487,3 +488,116 @@ describe('PageManager tests', () => {
expect(pageManager.getPage().start).toEqual(2500);
});
});

test('when complete referrer is available from the DOM then is recorded in page view event', async () => {
// Init
const config: Config = {
...DEFAULT_CONFIG,
allowCookies: true
};
const pageManager: PageManager = new PageManager(config, record);

Object.defineProperty(document, 'referrer', {
value: 'http://abc.com/consoles',
configurable: true
});

// Run
pageManager.recordPageView('/console/home');

// Assert
expect(pageManager.getPage()).toMatchObject({
referrer: 'http://abc.com/consoles',
referrerDomain: 'abc.com',
pageId: '/console/home'
});

window.removeEventListener(
'popstate',
(pageManager as any).popstateListener
);
});

test('when only domain level referrer is available from the DOM then is recorded in page view event', async () => {
// Init
const config: Config = {
...DEFAULT_CONFIG,
allowCookies: true
};
const pageManager: PageManager = new PageManager(config, record);

Object.defineProperty(document, 'referrer', {
value: 'http://abc.com',
configurable: true
});
// Run
pageManager.recordPageView('/console/home');

// Assert
expect(pageManager.getPage()).toMatchObject({
referrer: 'http://abc.com',
referrerDomain: 'abc.com',
pageId: '/console/home'
});

window.removeEventListener(
'popstate',
(pageManager as any).popstateListener
);
});

test('when referrer from the DOM is empty then it is recorded as empty in the page view event', async () => {
// Init
const config: Config = {
...DEFAULT_CONFIG,
allowCookies: true
};
const pageManager: PageManager = new PageManager(config, record);

Object.defineProperty(document, 'referrer', {
value: '',
configurable: true
});
// Run
pageManager.recordPageView('/console/home');

// Assert
expect(pageManager.getPage()).toMatchObject({
pageId: '/console/home',
referrer: '',
referrerDomain: ''
});

window.removeEventListener(
'popstate',
(pageManager as any).popstateListener
);
});

test('when referrer from the DOM is localhost then referrerDomain is also recorded as localhost', async () => {
// Init
const config: Config = {
...DEFAULT_CONFIG,
allowCookies: true
};
const pageManager: PageManager = new PageManager(config, record);

Object.defineProperty(document, 'referrer', {
value: 'localhost',
configurable: true
});
// Run
pageManager.recordPageView('/console/home');

// Assert
expect(pageManager.getPage()).toMatchObject({
pageId: '/console/home',
referrer: 'localhost',
referrerDomain: 'localhost'
});

window.removeEventListener(
'popstate',
(pageManager as any).popstateListener
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do we need a unit test for when localhost is the referrer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handled in next revision