Skip to content

Commit 09ca119

Browse files
haretonjmeta-codesync[bot]
authored andcommitted
Add ReferrerUrl.test.js
Summary: Add unit tests for the getReferrerUrl() functionality added in the previous commit. Do NOT modify any source files — only create the test file. Create `tests/ReferrerUrl.test.js` following existing test conventions (see `tests/ParamBuilder.test.js` and `tests/ProcessRequestFromContext.test.js` for patterns). Tests should cover: - Referrer stored before fbclid extraction (pass URL with fbclid, verify full URL preserved) - getReferrerUrl() returns null when no referer - getReferrerUrl() via processRequest() with all params - getReferrerUrl() via processRequestFromContext() with PlainDataObject and with raw request object - Reset between consecutive calls - Null vs empty string - Various URL formats (HTTP, HTTPS, with query, with fragment) Differential Revision: D105628060 fbshipit-source-id: 8039a545f8a5cc22aadecac5ab17262a27e1af2d
1 parent 542aef8 commit 09ca119

1 file changed

Lines changed: 366 additions & 0 deletions

File tree

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
const pb = require('../src/ParamBuilder');
12+
const ParamBuilder = pb.ParamBuilder;
13+
const PlainDataObject = require('../src/model/PlainDataObject');
14+
15+
const DUMMY_TIMESTAMP = 1234567890;
16+
17+
jest.mock('../package.json', () => ({version: '1.0.0'}));
18+
19+
describe('ParamBuilder.getReferrerUrl', () => {
20+
beforeAll(() => {
21+
jest.spyOn(Date, 'now').mockImplementation(() => DUMMY_TIMESTAMP);
22+
jest.spyOn(Math, 'random').mockImplementation(() => 1);
23+
});
24+
25+
afterAll(() => {
26+
jest.restoreAllMocks();
27+
});
28+
29+
// =========================================================================
30+
// Referrer Preserved Before fbclid Extraction
31+
// =========================================================================
32+
33+
describe('Referrer preserved before fbclid extraction', () => {
34+
test('full referrer URL with fbclid is preserved as-is', () => {
35+
const builder = new ParamBuilder();
36+
const referer = 'https://facebook.com/ad?fbclid=IwAR_test123&utm=campaign';
37+
38+
builder.processRequest('example.com', {}, {}, referer);
39+
40+
expect(builder.getReferrerUrl()).toBe(referer);
41+
});
42+
43+
test('referrer with fbclid in query is not stripped or modified', () => {
44+
const builder = new ParamBuilder();
45+
const referer = 'https://landing.page.com/path?fbclid=abc123&other=value';
46+
47+
builder.processRequest('example.com', null, null, referer);
48+
49+
expect(builder.getReferrerUrl()).toBe(referer);
50+
expect(builder.getReferrerUrl()).toContain('fbclid=abc123');
51+
});
52+
53+
test('referrer without protocol and with fbclid is preserved', () => {
54+
const builder = new ParamBuilder();
55+
const referer = 'example.com?fbclid=noProtocol';
56+
57+
builder.processRequest('[::1]:8080', null, undefined, referer);
58+
59+
expect(builder.getReferrerUrl()).toBe(referer);
60+
});
61+
});
62+
63+
// =========================================================================
64+
// getReferrerUrl Returns Null When No Referer
65+
// =========================================================================
66+
67+
describe('getReferrerUrl returns null when no referer', () => {
68+
test('returns null when referer is not provided (default)', () => {
69+
const builder = new ParamBuilder();
70+
71+
builder.processRequest('example.com', {fbclid: 'test'}, {});
72+
73+
expect(builder.getReferrerUrl()).toBeNull();
74+
});
75+
76+
test('returns null when referer is explicitly null', () => {
77+
const builder = new ParamBuilder();
78+
79+
builder.processRequest('example.com', {}, {}, null);
80+
81+
expect(builder.getReferrerUrl()).toBeNull();
82+
});
83+
84+
test('returns null before any processRequest call', () => {
85+
const builder = new ParamBuilder();
86+
87+
expect(builder.getReferrerUrl()).toBeNull();
88+
});
89+
});
90+
91+
// =========================================================================
92+
// getReferrerUrl via processRequest with All Params
93+
// =========================================================================
94+
95+
describe('getReferrerUrl via processRequest with all params', () => {
96+
test('referrer is stored when all params provided', () => {
97+
const builder = new ParamBuilder();
98+
const referer = 'https://facebook.com/ad';
99+
100+
builder.processRequest(
101+
'shop.example.com',
102+
{fbclid: 'click123'},
103+
{_fbp: 'fb.1.123.456'},
104+
referer,
105+
'203.0.113.50',
106+
'10.0.0.1'
107+
);
108+
109+
expect(builder.getReferrerUrl()).toBe(referer);
110+
});
111+
112+
test('referrer stored even when fbclid comes from query not referer', () => {
113+
const builder = new ParamBuilder();
114+
const referer = 'https://google.com/search?q=test';
115+
116+
builder.processRequest(
117+
'example.com',
118+
{fbclid: 'fromQuery'},
119+
{},
120+
referer
121+
);
122+
123+
expect(builder.getReferrerUrl()).toBe(referer);
124+
expect(builder.getFbc()).toMatch(/\.fromQuery\./);
125+
});
126+
});
127+
128+
// =========================================================================
129+
// getReferrerUrl via processRequestFromContext
130+
// =========================================================================
131+
132+
describe('getReferrerUrl via processRequestFromContext', () => {
133+
test('with PlainDataObject containing referer', () => {
134+
const builder = new ParamBuilder();
135+
const referer = 'https://facebook.com/ad?fbclid=IwAR_pdo';
136+
137+
const dataObject = new PlainDataObject(
138+
'example.com',
139+
{fbclid: 'test'},
140+
{},
141+
referer,
142+
null,
143+
null
144+
);
145+
146+
builder.processRequestFromContext(dataObject);
147+
148+
expect(builder.getReferrerUrl()).toBe(referer);
149+
});
150+
151+
test('with PlainDataObject without referer', () => {
152+
const builder = new ParamBuilder();
153+
154+
const dataObject = new PlainDataObject(
155+
'example.com',
156+
{},
157+
{},
158+
null,
159+
null,
160+
null
161+
);
162+
163+
builder.processRequestFromContext(dataObject);
164+
165+
expect(builder.getReferrerUrl()).toBeNull();
166+
});
167+
168+
test('with raw request object containing referer header', () => {
169+
const builder = new ParamBuilder();
170+
171+
const req = {
172+
headers: {
173+
host: 'landing.example.com',
174+
referer: 'https://facebook.com/ad?fbclid=IwAR_raw',
175+
},
176+
socket: {remoteAddress: '203.0.113.1'},
177+
url: '/landing',
178+
};
179+
180+
builder.processRequestFromContext(req);
181+
182+
expect(builder.getReferrerUrl()).toBe(
183+
'https://facebook.com/ad?fbclid=IwAR_raw'
184+
);
185+
});
186+
187+
test('with raw request object without referer header', () => {
188+
const builder = new ParamBuilder();
189+
190+
const req = {
191+
headers: {host: 'example.com'},
192+
url: '/?fbclid=test',
193+
};
194+
195+
builder.processRequestFromContext(req);
196+
197+
expect(builder.getReferrerUrl()).toBeNull();
198+
});
199+
});
200+
201+
// =========================================================================
202+
// Reset Between Consecutive Calls
203+
// =========================================================================
204+
205+
describe('Reset between consecutive calls', () => {
206+
test('referrer resets on each processRequest call', () => {
207+
const builder = new ParamBuilder();
208+
209+
builder.processRequest(
210+
'first.example.com',
211+
{},
212+
{},
213+
'https://first-referer.com'
214+
);
215+
expect(builder.getReferrerUrl()).toBe('https://first-referer.com');
216+
217+
builder.processRequest(
218+
'second.example.com',
219+
{},
220+
{},
221+
'https://second-referer.com'
222+
);
223+
expect(builder.getReferrerUrl()).toBe('https://second-referer.com');
224+
});
225+
226+
test('referrer resets to null when second call has no referer', () => {
227+
const builder = new ParamBuilder();
228+
229+
builder.processRequest(
230+
'example.com',
231+
{},
232+
{},
233+
'https://has-referer.com'
234+
);
235+
expect(builder.getReferrerUrl()).toBe('https://has-referer.com');
236+
237+
builder.processRequest('example.com', {}, {});
238+
expect(builder.getReferrerUrl()).toBeNull();
239+
});
240+
241+
test('referrer resets between processRequestFromContext calls', () => {
242+
const builder = new ParamBuilder();
243+
244+
const dataObject1 = new PlainDataObject(
245+
'first.example.com',
246+
{},
247+
{},
248+
'https://first.com/page',
249+
null,
250+
null
251+
);
252+
builder.processRequestFromContext(dataObject1);
253+
expect(builder.getReferrerUrl()).toBe('https://first.com/page');
254+
255+
const dataObject2 = new PlainDataObject(
256+
'second.example.com',
257+
{},
258+
{},
259+
'https://second.com/page',
260+
null,
261+
null
262+
);
263+
builder.processRequestFromContext(dataObject2);
264+
expect(builder.getReferrerUrl()).toBe('https://second.com/page');
265+
});
266+
});
267+
268+
// =========================================================================
269+
// Null vs Empty String
270+
// =========================================================================
271+
272+
describe('Null vs empty string', () => {
273+
test('null referer returns null', () => {
274+
const builder = new ParamBuilder();
275+
276+
builder.processRequest('example.com', {}, {}, null);
277+
278+
expect(builder.getReferrerUrl()).toBeNull();
279+
});
280+
281+
test('undefined referer (default param) returns null', () => {
282+
const builder = new ParamBuilder();
283+
284+
builder.processRequest('example.com', {}, {});
285+
286+
expect(builder.getReferrerUrl()).toBeNull();
287+
});
288+
289+
test('empty string referer returns empty string', () => {
290+
const builder = new ParamBuilder();
291+
292+
builder.processRequest('example.com', {}, {}, '');
293+
294+
expect(builder.getReferrerUrl()).toBe('');
295+
});
296+
});
297+
298+
// =========================================================================
299+
// Various URL Formats
300+
// =========================================================================
301+
302+
describe('Various URL formats', () => {
303+
test('HTTP URL', () => {
304+
const builder = new ParamBuilder();
305+
const referer = 'http://example.com/page';
306+
307+
builder.processRequest('landing.com', {}, {}, referer);
308+
309+
expect(builder.getReferrerUrl()).toBe(referer);
310+
});
311+
312+
test('HTTPS URL', () => {
313+
const builder = new ParamBuilder();
314+
const referer = 'https://secure.example.com/page';
315+
316+
builder.processRequest('landing.com', {}, {}, referer);
317+
318+
expect(builder.getReferrerUrl()).toBe(referer);
319+
});
320+
321+
test('URL with query parameters', () => {
322+
const builder = new ParamBuilder();
323+
const referer = 'https://example.com/search?q=test&lang=en';
324+
325+
builder.processRequest('landing.com', {}, {}, referer);
326+
327+
expect(builder.getReferrerUrl()).toBe(referer);
328+
});
329+
330+
test('URL with fragment', () => {
331+
const builder = new ParamBuilder();
332+
const referer = 'https://example.com/page#section-2';
333+
334+
builder.processRequest('landing.com', {}, {}, referer);
335+
336+
expect(builder.getReferrerUrl()).toBe(referer);
337+
});
338+
339+
test('URL with query and fragment', () => {
340+
const builder = new ParamBuilder();
341+
const referer = 'https://example.com/page?key=value#anchor';
342+
343+
builder.processRequest('landing.com', {}, {}, referer);
344+
345+
expect(builder.getReferrerUrl()).toBe(referer);
346+
});
347+
348+
test('URL with port', () => {
349+
const builder = new ParamBuilder();
350+
const referer = 'https://example.com:8443/path';
351+
352+
builder.processRequest('landing.com', {}, {}, referer);
353+
354+
expect(builder.getReferrerUrl()).toBe(referer);
355+
});
356+
357+
test('URL without protocol (bare hostname)', () => {
358+
const builder = new ParamBuilder();
359+
const referer = 'example.com/path?query=1';
360+
361+
builder.processRequest('landing.com', {}, {}, referer);
362+
363+
expect(builder.getReferrerUrl()).toBe(referer);
364+
});
365+
});
366+
});

0 commit comments

Comments
 (0)