mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-19 08:31:43 +03:00
e879406659
fixes https://github.com/TryGhost/Team/issues/2432 Adds outbound_link_tagging setting (enabled by default and behind feature flag). If the feature flag is enabled, and the setting is disabled, we won't add ?ref to links in emails. This includes new E2E tests for email click tracking, which were also extended to check outbound link tagging (for both MEGA and the new email stability flow). Also fixes a test fixture for the comments_enabled setting.
314 lines
12 KiB
JavaScript
314 lines
12 KiB
JavaScript
// Switch these lines once there are useful utils
|
|
// const testUtils = require('./utils');
|
|
require('./utils');
|
|
const MemberAttributionService = require('../lib/service');
|
|
|
|
describe('MemberAttributionService', function () {
|
|
describe('Constructor', function () {
|
|
it('doesn\'t throw', function () {
|
|
new MemberAttributionService({});
|
|
});
|
|
});
|
|
|
|
describe('addOutboundLinkTagging', function () {
|
|
it('uses sluggified sitename for external urls', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
|
|
should(updatedUrl.toString()).equal('https://example.com/?ref=hello-world');
|
|
});
|
|
|
|
it('does not add if disabled', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => false
|
|
});
|
|
const url = new URL('https://example.com/');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
|
|
should(updatedUrl.toString()).equal('https://example.com/');
|
|
});
|
|
|
|
it('uses sluggified newsletter name for internal urls', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/');
|
|
const newsletterName = 'used newsletter name';
|
|
const newsletter = {
|
|
get: (t) => {
|
|
if (t === 'name') {
|
|
return newsletterName;
|
|
}
|
|
}
|
|
};
|
|
|
|
const updatedUrl = await service.addOutboundLinkTagging(url, newsletter);
|
|
|
|
should(updatedUrl.toString()).equal('https://example.com/?ref=used-newsletter-name-newsletter');
|
|
});
|
|
|
|
it('does not repeat newsletter at the end of the newsletter name', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/');
|
|
const newsletterName = 'Weekly newsletter';
|
|
const newsletter = {
|
|
get: (t) => {
|
|
if (t === 'name') {
|
|
return newsletterName;
|
|
}
|
|
}
|
|
};
|
|
const updatedUrl = await service.addOutboundLinkTagging(url, newsletter);
|
|
|
|
should(updatedUrl.toString()).equal('https://example.com/?ref=weekly-newsletter');
|
|
});
|
|
|
|
it('does not add ref to blacklisted domains', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://facebook.com/');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
|
|
should(updatedUrl.toString()).equal('https://facebook.com/');
|
|
});
|
|
|
|
it('does not add ref if utm_source is present', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/?utm_source=hello');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
should(updatedUrl.toString()).equal('https://example.com/?utm_source=hello');
|
|
});
|
|
|
|
it('does not add ref if ref is present', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/?ref=hello');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
should(updatedUrl.toString()).equal('https://example.com/?ref=hello');
|
|
});
|
|
|
|
it('does not add ref if source is present', async function () {
|
|
const service = new MemberAttributionService({
|
|
getSiteTitle: () => 'Hello world',
|
|
getOutboundLinkTaggingEnabled: () => true
|
|
});
|
|
const url = new URL('https://example.com/?source=hello');
|
|
const updatedUrl = await service.addOutboundLinkTagging(url);
|
|
should(updatedUrl.toString()).equal('https://example.com/?source=hello');
|
|
});
|
|
});
|
|
|
|
describe('getAttributionFromContext', function () {
|
|
it('returns null if no context is provided', async function () {
|
|
const service = new MemberAttributionService({
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const attribution = await service.getAttributionFromContext();
|
|
|
|
should(attribution).be.null();
|
|
});
|
|
|
|
it('returns null if tracking is disabled is provided', async function () {
|
|
const service = new MemberAttributionService({
|
|
isTrackingEnabled: false
|
|
});
|
|
const attribution = await service.getAttributionFromContext();
|
|
|
|
should(attribution).be.null();
|
|
});
|
|
|
|
it('returns attribution for importer context', async function () {
|
|
const service = new MemberAttributionService({
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const attribution = await service.getAttributionFromContext({importer: true});
|
|
|
|
should(attribution).containEql({referrerSource: 'Imported', referrerMedium: 'Member Importer'});
|
|
});
|
|
|
|
it('returns attribution for admin context', async function () {
|
|
const service = new MemberAttributionService({
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const attribution = await service.getAttributionFromContext({user: 'abc'});
|
|
|
|
should(attribution).containEql({referrerSource: 'Created manually', referrerMedium: 'Ghost Admin'});
|
|
});
|
|
|
|
it('returns attribution for api without integration context', async function () {
|
|
const service = new MemberAttributionService({
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const attribution = await service.getAttributionFromContext({
|
|
api_key: 'abc'
|
|
});
|
|
|
|
should(attribution).containEql({referrerSource: 'Created via API', referrerMedium: 'Admin API'});
|
|
});
|
|
|
|
it('returns attribution for api with integration context', async function () {
|
|
const service = new MemberAttributionService({
|
|
models: {
|
|
Integration: {
|
|
findOne: () => {
|
|
return {
|
|
get: () => 'Test Integration'
|
|
};
|
|
}
|
|
}
|
|
},
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const attribution = await service.getAttributionFromContext({
|
|
api_key: 'abc',
|
|
integration: {id: 'integration_1'}
|
|
});
|
|
|
|
should(attribution).containEql({referrerSource: 'Integration: Test Integration', referrerMedium: 'Admin API'});
|
|
});
|
|
});
|
|
|
|
describe('getEventAttribution', function () {
|
|
it('returns null if attribution_type is null', function () {
|
|
const service = new MemberAttributionService({
|
|
attributionBuilder: {
|
|
build(attribution) {
|
|
return {
|
|
...attribution,
|
|
getResource() {
|
|
return {
|
|
...attribution,
|
|
title: 'added'
|
|
};
|
|
}
|
|
};
|
|
}
|
|
},
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const model = {
|
|
id: 'event_id',
|
|
get() {
|
|
return null;
|
|
}
|
|
};
|
|
should(service.getEventAttribution(model)).eql({
|
|
id: null,
|
|
url: null,
|
|
title: 'added',
|
|
type: null,
|
|
referrerSource: null,
|
|
referrerMedium: null,
|
|
referrerUrl: null
|
|
});
|
|
});
|
|
|
|
it('returns url attribution types', function () {
|
|
const service = new MemberAttributionService({
|
|
attributionBuilder: {
|
|
build(attribution) {
|
|
return {
|
|
...attribution,
|
|
getResource() {
|
|
return {
|
|
...attribution,
|
|
title: 'added'
|
|
};
|
|
}
|
|
};
|
|
}
|
|
},
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const model = {
|
|
id: 'event_id',
|
|
get(name) {
|
|
if (name === 'attribution_type') {
|
|
return 'url';
|
|
}
|
|
if (name === 'attribution_url') {
|
|
return '/my/url/';
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
should(service.getEventAttribution(model)).eql({
|
|
id: null,
|
|
type: 'url',
|
|
url: '/my/url/',
|
|
title: 'added',
|
|
referrerMedium: null,
|
|
referrerSource: null,
|
|
referrerUrl: null
|
|
});
|
|
});
|
|
|
|
it('returns first loaded relation', function () {
|
|
const service = new MemberAttributionService({
|
|
attributionBuilder: {
|
|
build(attribution) {
|
|
return {
|
|
...attribution,
|
|
getResource() {
|
|
return {
|
|
...attribution,
|
|
title: 'added'
|
|
};
|
|
}
|
|
};
|
|
}
|
|
},
|
|
getTrackingEnabled: () => true
|
|
});
|
|
const model = {
|
|
id: 'event_id',
|
|
get(name) {
|
|
if (name === 'attribution_type') {
|
|
return 'user';
|
|
}
|
|
if (name === 'attribution_url') {
|
|
return '/my/url/';
|
|
}
|
|
if (name.startsWith('referrer')) {
|
|
return null;
|
|
}
|
|
return 'test_user_id';
|
|
},
|
|
related(name) {
|
|
if (name === 'userAttribution') {
|
|
return {
|
|
id: 'test_user_id'
|
|
};
|
|
}
|
|
return {};
|
|
}
|
|
};
|
|
should(service.getEventAttribution(model)).eql({
|
|
id: 'test_user_id',
|
|
type: 'user',
|
|
url: '/my/url/',
|
|
title: 'added',
|
|
referrerMedium: null,
|
|
referrerSource: null,
|
|
referrerUrl: null
|
|
});
|
|
});
|
|
});
|
|
});
|