Added LinkClickTrackingService unit tests and renamed wrapper (#15462)
refs https://github.com/TryGhost/Team/issues/1958 - Renamed wrapper service link-click-tracking to link-tracking to be consistent with the package name - Added unit tests for LinkClickTrackingService - Added DomainEvents dependency to LinkClickTrackingService - Fixes dependencies in link-tracking package
This commit is contained in:
parent
2bff2a22e0
commit
e658f7622a
@ -287,7 +287,7 @@ async function initServices({config}) {
|
||||
const staffService = require('./server/services/staff');
|
||||
const memberAttribution = require('./server/services/member-attribution');
|
||||
const membersEvents = require('./server/services/members-events');
|
||||
const linkTracking = require('./server/services/link-click-tracking');
|
||||
const linkTracking = require('./server/services/link-tracking');
|
||||
|
||||
const urlUtils = require('./shared/url-utils');
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
const linkTrackingService = require('../../services/link-click-tracking');
|
||||
const linkTrackingService = require('../../services/link-tracking');
|
||||
|
||||
module.exports = {
|
||||
docName: 'links',
|
||||
|
@ -19,7 +19,7 @@ class LinkTrackingServiceWrapper {
|
||||
const {MemberLinkClickEvent} = require('@tryghost/member-events');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
|
||||
const {LinkTrackingService} = require('@tryghost/link-tracking');
|
||||
const {LinkClickTrackingService} = require('@tryghost/link-tracking');
|
||||
|
||||
const postLinkRepository = new PostLinkRepository({
|
||||
LinkRedirect: models.LinkRedirect,
|
||||
@ -34,10 +34,11 @@ class LinkTrackingServiceWrapper {
|
||||
});
|
||||
|
||||
// Expose the service
|
||||
this.service = new LinkTrackingService({
|
||||
this.service = new LinkClickTrackingService({
|
||||
linkRedirectService: linkRedirection.service,
|
||||
linkClickRepository,
|
||||
postLinkRepository
|
||||
postLinkRepository,
|
||||
DomainEvents
|
||||
});
|
||||
|
||||
await this.service.init();
|
@ -15,7 +15,7 @@ const {textColorForBackgroundColor, darkenToContrastThreshold} = require('@trygh
|
||||
const logging = require('@tryghost/logging');
|
||||
const urlService = require('../../services/url');
|
||||
const linkReplacer = require('@tryghost/link-replacer');
|
||||
const linkTracking = require('../link-click-tracking');
|
||||
const linkTracking = require('../link-tracking');
|
||||
const memberAttribution = require('../member-attribution');
|
||||
|
||||
const ALLOWED_REPLACEMENTS = ['first_name', 'uuid'];
|
||||
|
@ -1,4 +1,3 @@
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const {RedirectEvent} = require('@tryghost/link-redirects');
|
||||
const LinkClick = require('./LinkClick');
|
||||
const PostLink = require('./PostLink');
|
||||
@ -43,17 +42,21 @@ class LinkClickTrackingService {
|
||||
#linkRedirectService;
|
||||
/** @type IPostLinkRepository */
|
||||
#postLinkRepository;
|
||||
/** @type DomainEvents */
|
||||
#DomainEvents;
|
||||
|
||||
/**
|
||||
* @param {object} deps
|
||||
* @param {ILinkClickRepository} deps.linkClickRepository
|
||||
* @param {ILinkRedirectService} deps.linkRedirectService
|
||||
* @param {IPostLinkRepository} deps.postLinkRepository
|
||||
* @param {DomainEvents} deps.DomainEvents
|
||||
*/
|
||||
constructor(deps) {
|
||||
this.#linkClickRepository = deps.linkClickRepository;
|
||||
this.#linkRedirectService = deps.linkRedirectService;
|
||||
this.#postLinkRepository = deps.postLinkRepository;
|
||||
this.#DomainEvents = deps.DomainEvents;
|
||||
}
|
||||
|
||||
async init() {
|
||||
@ -109,7 +112,7 @@ class LinkClickTrackingService {
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
DomainEvents.subscribe(RedirectEvent, async (event) => {
|
||||
this.#DomainEvents.subscribe(RedirectEvent, async (event) => {
|
||||
const uuid = event.data.url.searchParams.get('m');
|
||||
if (!uuid) {
|
||||
return;
|
||||
|
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
LinkTrackingService: require('./LinkClickTrackingService'),
|
||||
LinkClickTrackingService: require('./LinkClickTrackingService'),
|
||||
LinkClick: require('./LinkClick'),
|
||||
PostLink: require('./PostLink'),
|
||||
FullPostLink: require('./FullPostLink')
|
||||
|
@ -7,7 +7,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "echo \"Implement me!\"",
|
||||
"test:unit": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura mocha './test/**/*.test.js'",
|
||||
"test:unit": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura mocha './test/**/*.test.js'",
|
||||
"test": "yarn test:unit",
|
||||
"lint:code": "eslint *.js lib/ --ext .js --cache",
|
||||
"lint": "yarn lint:code && yarn lint:test",
|
||||
@ -24,7 +24,7 @@
|
||||
"sinon": "14.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/link-redirects": "0.0.0"
|
||||
"@tryghost/link-redirects": "0.0.0",
|
||||
"bson-objectid": "2.0.3"
|
||||
}
|
||||
}
|
||||
|
171
ghost/link-tracking/test/LinkClickTrackingService.test.js
Normal file
171
ghost/link-tracking/test/LinkClickTrackingService.test.js
Normal file
@ -0,0 +1,171 @@
|
||||
const LinkClickTrackingService = require('../lib/LinkClickTrackingService');
|
||||
const sinon = require('sinon');
|
||||
const assert = require('assert');
|
||||
const ObjectID = require('bson-objectid').default;
|
||||
const PostLink = require('../lib/PostLink');
|
||||
const {RedirectEvent} = require('@tryghost/link-redirects');
|
||||
|
||||
describe('LinkClickTrackingService', function () {
|
||||
it('exists', function () {
|
||||
require('../');
|
||||
});
|
||||
|
||||
describe('init', function () {
|
||||
it('initialises only once', function () {
|
||||
const subscribe = sinon.stub();
|
||||
const service = new LinkClickTrackingService({
|
||||
DomainEvents: {
|
||||
subscribe
|
||||
}
|
||||
});
|
||||
service.init();
|
||||
assert.ok(subscribe.calledOnce);
|
||||
service.init();
|
||||
assert.ok(subscribe.calledOnce);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLinks', function () {
|
||||
it('passes call to postLinkRepository', async function () {
|
||||
const getAll = sinon.stub().resolves(['test']);
|
||||
const service = new LinkClickTrackingService({
|
||||
postLinkRepository: {
|
||||
getAll
|
||||
}
|
||||
});
|
||||
const links = await service.getLinks({filter: 'post_id:1'});
|
||||
|
||||
// Check called with filter
|
||||
assert.ok(getAll.calledOnceWithExactly({filter: 'post_id:1'}));
|
||||
|
||||
// Check returned value
|
||||
assert.deepStrictEqual(links, ['test']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addRedirectToUrl', function () {
|
||||
it('Creates a redirect', async function () {
|
||||
const getSlugUrl = sinon.stub().resolves(new URL('https://example.com/r/uniqueslug'));
|
||||
const save = sinon.stub().resolves();
|
||||
const linkId = new ObjectID();
|
||||
const addRedirect = sinon.stub().resolves({link_id: linkId, to: new URL('https://example.com/destination'), from: new URL('https://example.com/r/uniqueslug')});
|
||||
|
||||
const service = new LinkClickTrackingService({
|
||||
linkRedirectService: {
|
||||
getSlugUrl,
|
||||
addRedirect
|
||||
},
|
||||
postLinkRepository: {
|
||||
save
|
||||
}
|
||||
});
|
||||
|
||||
const postId = new ObjectID().toHexString();
|
||||
const updatedUrl = await service.addRedirectToUrl(new URL('https://example.com/destination'), {id: postId});
|
||||
assert.equal(updatedUrl.toString(), 'https://example.com/r/uniqueslug');
|
||||
|
||||
// Check getSlugUrl called
|
||||
assert(getSlugUrl.calledOnce);
|
||||
|
||||
// Check save called
|
||||
assert(
|
||||
save.calledOnceWithExactly(
|
||||
new PostLink({
|
||||
post_id: postId,
|
||||
link_id: linkId
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addTrackingToUrl', function () {
|
||||
it('Creates a redirect', async function () {
|
||||
const getSlugUrl = sinon.stub().resolves(new URL('https://example.com/r/uniqueslug'));
|
||||
const save = sinon.stub().resolves();
|
||||
const linkId = new ObjectID();
|
||||
const addRedirect = sinon.stub().resolves({link_id: linkId, to: new URL('https://example.com/destination'), from: new URL('https://example.com/r/uniqueslug')});
|
||||
|
||||
const service = new LinkClickTrackingService({
|
||||
linkRedirectService: {
|
||||
getSlugUrl,
|
||||
addRedirect
|
||||
},
|
||||
postLinkRepository: {
|
||||
save
|
||||
}
|
||||
});
|
||||
|
||||
const postId = new ObjectID().toHexString();
|
||||
const updatedUrl = await service.addTrackingToUrl(new URL('https://example.com/destination'), {id: postId}, '123');
|
||||
assert.equal(updatedUrl.toString(), 'https://example.com/r/uniqueslug?m=123');
|
||||
|
||||
// Check getSlugUrl called
|
||||
assert(getSlugUrl.calledOnce);
|
||||
|
||||
// Check save called
|
||||
assert(
|
||||
save.calledOnceWithExactly(
|
||||
new PostLink({
|
||||
post_id: postId,
|
||||
link_id: linkId
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('subscribe', function () {
|
||||
it('Ignores redirects without a member id', async function () {
|
||||
const event = RedirectEvent.create({
|
||||
url: new URL('https://example.com/destination'),
|
||||
link: {}
|
||||
});
|
||||
const save = sinon.stub().resolves();
|
||||
|
||||
const service = new LinkClickTrackingService({
|
||||
DomainEvents: {
|
||||
subscribe: (eventType, callback) => {
|
||||
assert.equal(eventType, RedirectEvent);
|
||||
callback(event);
|
||||
}
|
||||
},
|
||||
linkClickRepository: {
|
||||
save
|
||||
}
|
||||
});
|
||||
|
||||
service.subscribe();
|
||||
assert(!save.called);
|
||||
});
|
||||
|
||||
it('Tracks redirects with a member id', async function () {
|
||||
const linkId = new ObjectID();
|
||||
const event = RedirectEvent.create({
|
||||
url: new URL('https://example.com/destination?m=memberId'),
|
||||
link: {
|
||||
link_id: linkId
|
||||
}
|
||||
});
|
||||
const save = sinon.stub().resolves();
|
||||
|
||||
const service = new LinkClickTrackingService({
|
||||
DomainEvents: {
|
||||
subscribe: (eventType, callback) => {
|
||||
assert.equal(eventType, RedirectEvent);
|
||||
callback(event);
|
||||
}
|
||||
},
|
||||
linkClickRepository: {
|
||||
save
|
||||
}
|
||||
});
|
||||
|
||||
service.subscribe();
|
||||
assert(save.calledOnce);
|
||||
|
||||
assert.equal(save.firstCall.args[0].member_uuid, 'memberId');
|
||||
assert.equal(save.firstCall.args[0].link_id, linkId);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,5 +0,0 @@
|
||||
describe('LinkTrackingService', function () {
|
||||
it('exists', function () {
|
||||
require('../');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user