Ghost/ghost/recommendations/test/Recommendation.test.ts
Simon Backx fee402a340
🐛 Fixed adding recommendation with URL redirect breaking one-click-subscribe (#18863)
fixes https://github.com/TryGhost/Product/issues/4102

E.g. you recommend myghostsite.com, while that site redirects all
traffic to [www.myghostsite.com](#):

The redirect causes CORS issues, which means we cannot detect
one-click-subscribe support.
- This is fixed by moving the whole detection to the backend, which has
the additional benefit that we can update it in the background without
the frontend, and update it on every recommendation change.
- This change also fixes existing recommendations by doing a check on
boot (we can move this to a background job in the future).
2023-11-03 15:02:45 +01:00

242 lines
8.1 KiB
TypeScript

import assert from 'assert/strict';
import {Recommendation} from '../src';
describe('Recommendation', function () {
describe('validate', function () {
it('Throws for an empty title', function () {
assert.throws(() => {
Recommendation.validate({
title: '',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false
});
}, {
name: 'ValidationError',
message: 'Title must not be empty'
});
});
it('Throws for a long title', function () {
assert.throws(() => {
Recommendation.validate({
title: 'a'.repeat(2001),
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false
});
}, {
name: 'ValidationError',
message: 'Title must be less than 2000 characters'
});
});
it('Throws for a long description', function () {
assert.throws(() => {
Recommendation.validate({
title: 'Test',
description: 'a'.repeat(2001),
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false
});
}, {
name: 'ValidationError',
message: 'Description must be less than 2000 characters'
});
});
it('Throws for a long excerpt', function () {
assert.throws(() => {
Recommendation.validate({
title: 'Test',
description: null,
excerpt: 'a'.repeat(2001),
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false
});
}, {
name: 'ValidationError',
message: 'Excerpt must be less than 2000 characters'
});
});
});
describe('clean', function () {
it('sets createdAt ms to 0', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z')
});
assert.equal(recommendation.createdAt.getMilliseconds(), 0);
});
it('sets updatedAt ms to 0', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
updatedAt: new Date('2021-01-01T00:00:05Z')
});
assert.equal(recommendation.updatedAt!.getMilliseconds(), 0);
});
it('sets empty description to null', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: '',
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
updatedAt: new Date('2021-01-01T00:00:05Z')
});
assert.equal(recommendation.description, null);
});
it('removes search and hash params', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: '',
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com/?query=1#hash',
oneClickSubscribe: false,
updatedAt: new Date('2021-01-01T00:00:05Z')
});
assert.equal(recommendation.url.toString(), 'https://example.com/');
});
});
describe('plain', function () {
it('does not return instance of self', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z')
});
assert.equal(recommendation.plain instanceof Recommendation, false);
});
});
describe('edit', function () {
it('can edit known properties', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z'),
updatedAt: null
});
recommendation.edit({
title: 'Updated'
});
assert.equal(recommendation.title, 'Updated');
assert.notEqual(recommendation.updatedAt, null);
});
it('does not change updatedAt if nothing changed', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z'),
updatedAt: null
});
assert.equal(recommendation.updatedAt, null);
recommendation.edit({
title: 'Test',
url: undefined
} as any);
assert.equal(recommendation.title, 'Test');
assert.equal(recommendation.url.toString(), 'https://example.com/');
assert.equal(recommendation.updatedAt, null);
});
it('can not edit unknown properties', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z'),
updatedAt: null
});
recommendation.edit({
bla: true
} as any);
assert.notEqual(recommendation.updatedAt, null);
assert.equal((recommendation as any).bla, undefined);
});
});
describe('delete', function () {
it('can delete', function () {
const recommendation = Recommendation.create({
title: 'Test',
description: null,
excerpt: null,
featuredImage: null,
favicon: null,
url: 'https://example.com',
oneClickSubscribe: false,
createdAt: new Date('2021-01-01T00:00:05Z'),
updatedAt: null
});
assert.equal(recommendation.deleted, false);
recommendation.delete();
assert.equal(recommendation.deleted, true);
});
});
});