Added missing unit tests to the Recommendations package (#18489)
refs https://github.com/TryGhost/Product/issues/3954
This commit is contained in:
parent
2391ccc3db
commit
380f3b5ca2
@ -11,7 +11,7 @@
|
||||
"build": "tsc",
|
||||
"build:ts": "yarn build",
|
||||
"prepare": "tsc",
|
||||
"test:unit": "NODE_ENV=testing c8 --src src --all --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'",
|
||||
"test:unit": "NODE_ENV=testing c8 --src src --all --check-coverage --100 --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'",
|
||||
"test": "yarn test:types && yarn test:unit",
|
||||
"test:types": "tsc --noEmit",
|
||||
"lint:code": "eslint src/ --ext .ts --cache",
|
||||
|
@ -1,9 +0,0 @@
|
||||
export type IncomingRecommendation = {
|
||||
id: string;
|
||||
title: string;
|
||||
url: URL;
|
||||
excerpt: string|null;
|
||||
favicon: URL|null;
|
||||
featuredImage: URL|null;
|
||||
recommendingBack: boolean;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import {IncomingRecommendationService} from './IncomingRecommendationService';
|
||||
import {IncomingRecommendation} from './IncomingRecommendation';
|
||||
import {IncomingRecommendation} from './IncomingRecommendationService';
|
||||
import {UnsafeData} from './UnsafeData';
|
||||
|
||||
type Frame = {
|
||||
@ -23,6 +23,7 @@ export class IncomingRecommendationController {
|
||||
|
||||
const page = options.optionalKey('page')?.integer ?? 1;
|
||||
const limit = options.optionalKey('limit')?.integer ?? 5;
|
||||
|
||||
const {incomingRecommendations, meta} = await this.service.listIncomingRecommendations({page, limit});
|
||||
|
||||
return this.#serialize(
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {EmailRecipient} from './IncomingRecommendationService';
|
||||
import {IncomingRecommendation} from './IncomingRecommendation';
|
||||
import {IncomingRecommendation} from './IncomingRecommendationService';
|
||||
|
||||
type StaffService = {
|
||||
api: {
|
||||
|
@ -1,8 +1,17 @@
|
||||
import {IncomingRecommendation} from './IncomingRecommendation';
|
||||
import {IncomingRecommendationEmailRenderer} from './IncomingRecommendationEmailRenderer';
|
||||
import {RecommendationService} from './RecommendationService';
|
||||
import logging from '@tryghost/logging';
|
||||
|
||||
export type IncomingRecommendation = {
|
||||
id: string;
|
||||
title: string;
|
||||
url: URL;
|
||||
excerpt: string|null;
|
||||
favicon: URL|null;
|
||||
featuredImage: URL|null;
|
||||
recommendingBack: boolean;
|
||||
}
|
||||
|
||||
export type Report = {
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
@ -21,7 +30,14 @@ type Mention = {
|
||||
}
|
||||
|
||||
type MentionMeta = {
|
||||
pagination: object,
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
pages: number;
|
||||
total: number;
|
||||
next: null | number;
|
||||
prev: null | number;
|
||||
}
|
||||
}
|
||||
|
||||
type MentionsAPI = {
|
||||
@ -75,11 +91,7 @@ export class IncomingRecommendationService {
|
||||
}
|
||||
|
||||
#getMentionFilter() {
|
||||
const base = `source:~$'/.well-known/recommendations.json'`;
|
||||
// if (verified) {
|
||||
// return `${base}+verified:true`;
|
||||
// }
|
||||
return base;
|
||||
return `source:~$'/.well-known/recommendations.json'`;
|
||||
}
|
||||
|
||||
async #updateIncomingRecommendations() {
|
||||
|
@ -0,0 +1,157 @@
|
||||
import assert from 'assert/strict';
|
||||
import {IncomingRecommendationController, IncomingRecommendationService} from '../src';
|
||||
import sinon, {SinonSpy} from 'sinon';
|
||||
|
||||
describe('IncomingRecommendationController', function () {
|
||||
let service: Partial<IncomingRecommendationService>;
|
||||
let controller: IncomingRecommendationController;
|
||||
|
||||
beforeEach(function () {
|
||||
service = {};
|
||||
controller = new IncomingRecommendationController({service: service as IncomingRecommendationService});
|
||||
});
|
||||
|
||||
describe('browse', function () {
|
||||
beforeEach(function () {
|
||||
service.listIncomingRecommendations = async () => {
|
||||
return {
|
||||
incomingRecommendations: [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Test 1',
|
||||
url: new URL('https://test1.com'),
|
||||
excerpt: 'Excerpt 1',
|
||||
favicon: new URL('https://test1.com/favicon.ico'),
|
||||
featuredImage: new URL('https://test1.com/image.png'),
|
||||
recommendingBack: true
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Test 2',
|
||||
url: new URL('https://test2.com'),
|
||||
excerpt: 'Excerpt 2',
|
||||
favicon: null,
|
||||
featuredImage: null,
|
||||
recommendingBack: false
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
pagination: {
|
||||
page: 1,
|
||||
limit: 5,
|
||||
pages: 1,
|
||||
total: 2,
|
||||
next: null,
|
||||
prev: null
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
it('without options', async function () {
|
||||
const result = await controller.browse({
|
||||
data: {},
|
||||
options: {}
|
||||
});
|
||||
|
||||
assert.deepEqual(result, {
|
||||
data: [{
|
||||
id: '1',
|
||||
title: 'Test 1',
|
||||
excerpt: 'Excerpt 1',
|
||||
featured_image: 'https://test1.com/image.png',
|
||||
favicon: 'https://test1.com/favicon.ico',
|
||||
url: 'https://test1.com/',
|
||||
recommending_back: true
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Test 2',
|
||||
excerpt: 'Excerpt 2',
|
||||
featured_image: null,
|
||||
favicon: null,
|
||||
url: 'https://test2.com/',
|
||||
recommending_back: false
|
||||
}],
|
||||
meta: {
|
||||
pagination: {
|
||||
page: 1,
|
||||
limit: 5,
|
||||
pages: 1,
|
||||
total: 2,
|
||||
next: null,
|
||||
prev: null
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('with options', function () {
|
||||
let listSpy: SinonSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
listSpy = sinon.spy(service, 'listIncomingRecommendations');
|
||||
});
|
||||
|
||||
it('limit is set to 5 by default', async function () {
|
||||
await controller.browse({
|
||||
data: {},
|
||||
options: {}
|
||||
});
|
||||
assert(listSpy.calledOnce);
|
||||
const args = listSpy.getCall(0).args[0];
|
||||
assert.deepEqual(args.limit, 5);
|
||||
});
|
||||
|
||||
it('limit can be set to 100', async function () {
|
||||
await controller.browse({
|
||||
data: {},
|
||||
options: {
|
||||
limit: 100
|
||||
}
|
||||
});
|
||||
assert(listSpy.calledOnce);
|
||||
const args = listSpy.getCall(0).args[0];
|
||||
assert.deepEqual(args.limit, 100);
|
||||
});
|
||||
|
||||
it('limit cannot be set to "all"', async function () {
|
||||
await assert.rejects(
|
||||
controller.browse({
|
||||
data: {},
|
||||
options: {
|
||||
limit: 'all'
|
||||
}
|
||||
}),
|
||||
{
|
||||
message: 'limit must be an integer'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('page is set to 1 by default', async function () {
|
||||
await controller.browse({
|
||||
data: {},
|
||||
options: {
|
||||
}
|
||||
});
|
||||
assert(listSpy.calledOnce);
|
||||
const args = listSpy.getCall(0).args[0];
|
||||
assert.deepEqual(args.page, 1);
|
||||
});
|
||||
|
||||
it('page can be set to 2', async function () {
|
||||
await controller.browse({
|
||||
data: {},
|
||||
options: {
|
||||
page: 2
|
||||
}
|
||||
});
|
||||
assert(listSpy.calledOnce);
|
||||
const args = listSpy.getCall(0).args[0];
|
||||
assert.deepEqual(args.page, 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -103,4 +103,73 @@ describe('IncomingRecommendationService', function () {
|
||||
assert(!send.calledOnce);
|
||||
});
|
||||
});
|
||||
|
||||
describe('listIncomingRecommendations', function () {
|
||||
beforeEach(function () {
|
||||
refreshMentions = sinon.stub().resolves();
|
||||
send = sinon.stub().resolves();
|
||||
readRecommendationByUrl = sinon.stub().resolves(null);
|
||||
service = new IncomingRecommendationService({
|
||||
recommendationService: {
|
||||
readRecommendationByUrl
|
||||
} as any as RecommendationService,
|
||||
mentionsApi: {
|
||||
refreshMentions,
|
||||
listMentions: () => Promise.resolve({data: [
|
||||
{
|
||||
id: 'Incoming recommendation',
|
||||
source: new URL('https://incoming-rec.com/.well-known/recommendations.json'),
|
||||
sourceTitle: 'Incoming recommendation title',
|
||||
sourceSiteTitle: null,
|
||||
sourceAuthor: null,
|
||||
sourceExcerpt: 'Incoming recommendation excerpt',
|
||||
sourceFavicon: new URL('https://incoming-rec.com/favicon.ico'),
|
||||
sourceFeaturedImage: new URL('https://incoming-rec.com/image.png')
|
||||
}
|
||||
], meta: {
|
||||
pagination: {
|
||||
page: 1,
|
||||
limit: 5,
|
||||
pages: 1,
|
||||
total: 1,
|
||||
next: null,
|
||||
prev: null
|
||||
}
|
||||
}})
|
||||
},
|
||||
emailService: {
|
||||
send
|
||||
},
|
||||
emailRenderer: {
|
||||
renderSubject: () => Promise.resolve(''),
|
||||
renderHTML: () => Promise.resolve(''),
|
||||
renderText: () => Promise.resolve('')
|
||||
} as any as IncomingRecommendationEmailRenderer,
|
||||
getEmailRecipients: () => Promise.resolve([
|
||||
{
|
||||
email: 'example@example.com'
|
||||
}
|
||||
])
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a list of incoming recommendations and pagination', async function () {
|
||||
const list = await service.listIncomingRecommendations({});
|
||||
|
||||
assert.equal(list.incomingRecommendations.length, 1);
|
||||
assert.equal(list.incomingRecommendations[0].id, 'Incoming recommendation');
|
||||
assert.equal(list.incomingRecommendations[0].title, 'Incoming recommendation title');
|
||||
assert.equal(list.incomingRecommendations[0].excerpt, 'Incoming recommendation excerpt');
|
||||
assert.equal(list.incomingRecommendations[0].url.toString(), 'https://incoming-rec.com/');
|
||||
assert.equal(list.incomingRecommendations[0].favicon?.toString(), 'https://incoming-rec.com/favicon.ico');
|
||||
assert.equal(list.incomingRecommendations[0].featuredImage?.toString(), 'https://incoming-rec.com/image.png');
|
||||
|
||||
assert.equal(list.meta?.pagination.page, 1);
|
||||
assert.equal(list.meta?.pagination.limit, 5);
|
||||
assert.equal(list.meta?.pagination.pages, 1);
|
||||
assert.equal(list.meta?.pagination.total, 1);
|
||||
assert.equal(list.meta?.pagination.prev, null);
|
||||
assert.equal(list.meta?.pagination.next, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +0,0 @@
|
||||
import assert from 'assert/strict';
|
||||
|
||||
describe('Hello world', function () {
|
||||
it('Runs a test', function () {
|
||||
// TODO: Write me!
|
||||
assert.ok(require('../'));
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user