Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useEffect } from 'react';
import { getSkimlinksAccountId, isSkimlink } from '../lib/affiliateLinksUtils';
import { useBetaAB } from '../lib/useAB';

/**
* Add custom parameters to skimlink URLs:
* - referrer
* - Referrer
* - Skimlinks account ID
* - AB test participations
*
* ## Why does this need to be an Island?
*
Expand All @@ -15,6 +17,18 @@ import { getSkimlinksAccountId, isSkimlink } from '../lib/affiliateLinksUtils';
* (No visual story exists as this does not render anything)
*/
export const EnhanceAffiliateLinks = () => {
const abTests = useBetaAB();

// Get users server/client-side AB test participations
const abTestParticipations = abTests?.getParticipations();

// Reduce abTestParticipations to a comma-separated string
const abTestString = abTestParticipations
? Object.entries(abTestParticipations)
.map(([key, value]) => `${key}:${value}`)
.join(',')
: '';

useEffect(() => {
const allLinksOnPage = [...document.querySelectorAll('a')];

Expand All @@ -28,7 +42,9 @@ export const EnhanceAffiliateLinks = () => {
const skimlinksAccountId = getSkimlinksAccountId(link.href);

// Skimlinks treats xcust as one long string, so we use | to separate values
const xcustValue = `referrer|${referrerDomain}|accountId|${skimlinksAccountId}`;
const xcustValue = `referrer|${referrerDomain}|accountId|${skimlinksAccountId}${
abTestString ? `|abTestParticipations|${abTestString}` : ''
}`;

link.href = `${link.href}&xcust=${encodeURIComponent(
xcustValue,
Expand Down
84 changes: 84 additions & 0 deletions dotcom-rendering/src/components/EnhanceAffiliateLinks.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import { useBetaAB } from '../lib/useAB';
import { EnhanceAffiliateLinks } from './EnhanceAffiliateLinks.importable';

// Mock the useAB module
jest.mock('../lib/useAB', () => ({
useBetaAB: jest.fn(),
}));

describe('EnhanceAffiliateLinks', () => {
beforeEach(() => {
// Clear the DOM before each test
document.body.innerHTML = '';
jest.restoreAllMocks();
});

it('should not modify links if no Skimlinks are present', () => {
document.body.innerHTML = `
<a href="https://example.com">Not a Skimlink</a>
`;

render(<EnhanceAffiliateLinks />);

const link = document.querySelector('a');
expect(link?.href).toBe('https://example.com/');
});

it('should append xcust parameter to Skimlinks with refferer set to none if unavailable', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

minor: referrer rather than refferer

Object.defineProperty(document, 'referrer', {
value: '',
configurable: true,
});

document.body.innerHTML = `
<a href="https://go.skimresources.com/?id=12345">Skimlink</a>
`;

render(<EnhanceAffiliateLinks />);

const link = document.querySelector('a');
expect(link?.href).toContain(
'xcust=referrer%7Cnone%7CaccountId%7C12345',
);
});

it('should append xcust parameter to Skimlinks with refferer set if available', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

also minor spelling mistake on referrer

Object.defineProperty(document, 'referrer', {
value: 'https://foo.com',
configurable: true,
});

document.body.innerHTML = `
<a href="https://go.skimresources.com/?id=12345">Skimlink</a>
`;

render(<EnhanceAffiliateLinks />);

const link = document.querySelector('a');
expect(link?.href).toContain(
'xcust=referrer%7Cfoo.com%7CaccountId%7C12345',
);
});

it('should include AB test participations in xcust if present', () => {
document.body.innerHTML = `
<a href="https://go.skimresources.com/?id=12345">Skimlink</a>
`;

(useBetaAB as jest.Mock).mockReturnValue({
getParticipations: () => ({
test1: 'variantA',
test2: 'variantB',
}),
});

render(<EnhanceAffiliateLinks />);

const link = document.querySelector('a');
expect(link?.href).toContain(
'xcust=referrer%7Cfoo.com%7CaccountId%7C12345%7CabTestParticipations%7Ctest1%3AvariantA%2Ctest2%3AvariantB',
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious, is the test naming case sensitive?
just incase we inadvertantly change the name from variantA to varianta ... will it have any ramifications on data? If so, it maybe best to lowercase the entire querystring, i.e. accountid, abtestparticipations, varianta, variantb

);
});
});
Loading