mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-23 02:41:50 +03:00
49d831d971
refs https://github.com/TryGhost/Team/issues/3428 - I'm taking an approach of adding specialized support for each event one-by-one. - The post resource deletion event is the most straight forward and works same for both types of collections.
397 lines
18 KiB
TypeScript
397 lines
18 KiB
TypeScript
import assert from 'assert';
|
|
import {
|
|
CollectionsService,
|
|
CollectionsRepositoryInMemory,
|
|
CollectionResourceChangeEvent
|
|
} from '../src/index';
|
|
import {PostsRepositoryInMemory} from './fixtures/PostsRepositoryInMemory';
|
|
import {posts} from './fixtures/posts';
|
|
|
|
const initPostsRepository = (): PostsRepositoryInMemory => {
|
|
const postsRepository = new PostsRepositoryInMemory();
|
|
|
|
for (const post of posts) {
|
|
const collectionPost = {
|
|
id: post.id,
|
|
title: post.title,
|
|
slug: post.slug,
|
|
featured: post.featured,
|
|
published_at: post.published_at,
|
|
deleted: false
|
|
};
|
|
postsRepository.save(collectionPost);
|
|
}
|
|
|
|
return postsRepository;
|
|
};
|
|
|
|
describe('CollectionsService', function () {
|
|
let collectionsService: CollectionsService;
|
|
let postsRepository: PostsRepositoryInMemory;
|
|
|
|
beforeEach(async function () {
|
|
const collectionsRepository = new CollectionsRepositoryInMemory();
|
|
postsRepository = initPostsRepository();
|
|
|
|
collectionsService = new CollectionsService({
|
|
collectionsRepository,
|
|
postsRepository
|
|
});
|
|
});
|
|
|
|
it('Instantiates a CollectionsService', function () {
|
|
assert.ok(collectionsService, 'CollectionsService should initialize');
|
|
});
|
|
|
|
it('Can do CRUD operations on a collection', async function () {
|
|
const savedCollection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
description: 'testing collections description',
|
|
type: 'manual',
|
|
filter: null
|
|
});
|
|
|
|
const createdCollection = await collectionsService.getById(savedCollection.id);
|
|
|
|
assert.ok(createdCollection, 'Collection should be saved');
|
|
assert.ok(createdCollection.id, 'Collection should have an id');
|
|
assert.equal(createdCollection.title, 'testing collections', 'Collection title should match');
|
|
|
|
const allCollections = await collectionsService.getAll();
|
|
assert.equal(allCollections.data.length, 1, 'There should be one collection');
|
|
|
|
await collectionsService.destroy(createdCollection.id);
|
|
const deletedCollection = await collectionsService.getById(savedCollection.id);
|
|
|
|
assert.equal(deletedCollection, null, 'Collection should be deleted');
|
|
});
|
|
|
|
it('Can retrieve a collection by slug', async function () {
|
|
const savedCollection = await collectionsService.createCollection({
|
|
title: 'slug test',
|
|
slug: 'get-me-by-slug',
|
|
type: 'manual',
|
|
filter: null
|
|
});
|
|
|
|
const retrievedCollection = await collectionsService.getBySlug('get-me-by-slug');
|
|
assert.ok(retrievedCollection, 'Collection should be saved');
|
|
assert.ok(retrievedCollection.slug, 'Collection should have a slug');
|
|
assert.equal(savedCollection.title, 'slug test', 'Collection title should match');
|
|
|
|
const nonExistingCollection = await collectionsService.getBySlug('i-do-not-exist');
|
|
assert.equal(nonExistingCollection, null, 'Collection should not exist');
|
|
});
|
|
|
|
it('Throws when built in collection is attempted to be deleted', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'Featured Posts',
|
|
slug: 'featured',
|
|
description: 'Collection of featured posts',
|
|
type: 'automatic',
|
|
deletable: false,
|
|
filter: 'featured:true'
|
|
});
|
|
|
|
await assert.rejects(async () => {
|
|
await collectionsService.destroy(collection.id);
|
|
}, (err: any) => {
|
|
assert.equal(err.message, 'Cannot delete builtin collection', 'Error message should match');
|
|
assert.equal(err.context, `The collection ${collection.id} is a builtin collection and cannot be deleted`, 'Error context should match');
|
|
return true;
|
|
});
|
|
});
|
|
|
|
describe('getCollectionsForPost', function () {
|
|
it('Can get collections for a post', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
type: 'manual'
|
|
});
|
|
|
|
await collectionsService.addPostToCollection(collection.id, posts[0]);
|
|
|
|
const collections = await collectionsService.getCollectionsForPost(posts[0].id);
|
|
|
|
assert.equal(collections.length, 1, 'There should be one collection');
|
|
assert.equal(collections[0].id, collection.id, 'Collection should be the correct one');
|
|
});
|
|
});
|
|
|
|
describe('getAllPosts', function () {
|
|
it('Can get paged posts of a collection', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'testing paging',
|
|
type: 'manual'
|
|
});
|
|
|
|
for (const post of posts) {
|
|
await collectionsService.addPostToCollection(collection.id, post);
|
|
}
|
|
|
|
const postsPage1 = await collectionsService.getAllPosts(collection.id, {page: 1, limit: 2});
|
|
|
|
assert.ok(postsPage1, 'Posts should be returned');
|
|
assert.equal(postsPage1.meta.pagination.page, 1, 'Page should be 1');
|
|
assert.equal(postsPage1.meta.pagination.limit, 2, 'Limit should be 2');
|
|
assert.equal(postsPage1.meta.pagination.pages, 2, 'Pages should be 2');
|
|
assert.equal(postsPage1.data.length, 2, 'There should be 2 posts');
|
|
assert.equal(postsPage1.data[0].id, posts[0].id, 'First post should be the correct one');
|
|
assert.equal(postsPage1.data[1].id, posts[1].id, 'Second post should be the correct one');
|
|
|
|
const postsPage2 = await collectionsService.getAllPosts(collection.id, {page: 2, limit: 2});
|
|
|
|
assert.ok(postsPage2, 'Posts should be returned');
|
|
assert.equal(postsPage2.meta.pagination.page, 2, 'Page should be 2');
|
|
assert.equal(postsPage2.meta.pagination.limit, 2, 'Limit should be 2');
|
|
assert.equal(postsPage2.meta.pagination.pages, 2, 'Pages should be 2');
|
|
assert.equal(postsPage2.data.length, 2, 'There should be 2 posts');
|
|
assert.equal(postsPage2.data[0].id, posts[2].id, 'First post should be the correct one');
|
|
assert.equal(postsPage2.data[1].id, posts[3].id, 'Second post should be the correct one');
|
|
});
|
|
|
|
it('Throws when trying to get posts of a collection that does not exist', async function () {
|
|
await assert.rejects(async () => {
|
|
await collectionsService.getAllPosts('fake id', {});
|
|
}, (err: any) => {
|
|
assert.equal(err.message, 'Collection not found', 'Error message should match');
|
|
assert.equal(err.context, 'Collection with id: fake id does not exist', 'Error context should match');
|
|
return true;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('addPostToCollection', function () {
|
|
it('Can add a Post to a Collection', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
description: 'testing collections description',
|
|
type: 'manual'
|
|
});
|
|
|
|
const editedCollection = await collectionsService.addPostToCollection(collection.id, posts[0]);
|
|
|
|
assert.equal(editedCollection?.posts.length, 1, 'Collection should have one post');
|
|
assert.equal(editedCollection?.posts[0].id, posts[0].id, 'Collection should have the correct post');
|
|
});
|
|
|
|
it('Does not error when trying to add a post to a collection that does not exist', async function () {
|
|
const editedCollection = await collectionsService.addPostToCollection('fake id', posts[0]);
|
|
assert(editedCollection === null);
|
|
});
|
|
});
|
|
|
|
describe('edit', function () {
|
|
it('Can edit existing collection', async function () {
|
|
const savedCollection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
description: 'testing collections description',
|
|
type: 'manual'
|
|
});
|
|
|
|
const editedCollection = await collectionsService.edit({
|
|
id: savedCollection.id,
|
|
title: 'Edited title',
|
|
description: 'Edited description',
|
|
feature_image: '/assets/images/edited.jpg'
|
|
});
|
|
|
|
assert.equal(editedCollection?.title, 'Edited title', 'Collection title should be edited');
|
|
assert.equal(editedCollection?.description, 'Edited description', 'Collection description should be edited');
|
|
assert.equal(editedCollection?.feature_image, '/assets/images/edited.jpg', 'Collection feature_image should be edited');
|
|
assert.equal(editedCollection?.type, 'manual', 'Collection type should not be edited');
|
|
});
|
|
|
|
it('Resolves to null when editing unexistend collection', async function () {
|
|
const editedCollection = await collectionsService.edit({
|
|
id: '12345'
|
|
});
|
|
|
|
assert.equal(editedCollection, null, 'Collection should be null');
|
|
});
|
|
|
|
it('Adds a Post to a Collection', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
description: 'testing collections description',
|
|
type: 'manual'
|
|
});
|
|
|
|
const editedCollection = await collectionsService.edit({
|
|
id: collection.id,
|
|
posts: [{
|
|
id: posts[0].id
|
|
}]
|
|
});
|
|
|
|
assert.equal(editedCollection?.posts.length, 1, 'Collection should have one post');
|
|
assert.equal(editedCollection?.posts[0].id, posts[0].id, 'Collection should have the correct post');
|
|
assert.equal(editedCollection?.posts[0].sort_order, 0, 'Collection should have the correct post sort order');
|
|
});
|
|
|
|
it('Removes a Post from a Collection', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'testing collections',
|
|
description: 'testing collections description',
|
|
type: 'manual'
|
|
});
|
|
|
|
let editedCollection = await collectionsService.edit({
|
|
id: collection.id,
|
|
posts: [{
|
|
id: posts[0].id
|
|
}, {
|
|
id: posts[1].id
|
|
}]
|
|
});
|
|
|
|
assert.equal(editedCollection?.posts.length, 2, 'Collection should have two posts');
|
|
|
|
editedCollection = await collectionsService.removePostFromCollection(collection.id, posts[0].id);
|
|
|
|
assert.equal(editedCollection?.posts.length, 1, 'Collection should have one posts');
|
|
});
|
|
|
|
it('Returns null when removing post from non existing collection', async function () {
|
|
const collection = await collectionsService.removePostFromCollection('i-do-not-exist', posts[0].id);
|
|
|
|
assert.equal(collection, null, 'Collection should be null');
|
|
});
|
|
});
|
|
|
|
describe('Automatic Collections', function () {
|
|
it('Can create an automatic collection', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'I am automatic',
|
|
description: 'testing automatic collection',
|
|
type: 'automatic',
|
|
filter: 'featured:true'
|
|
});
|
|
|
|
assert.equal(collection.type, 'automatic', 'Collection should be automatic');
|
|
assert.equal(collection.filter, 'featured:true', 'Collection should have the correct filter');
|
|
|
|
assert.equal(collection.posts.length, 2, 'Collection should have two posts');
|
|
});
|
|
|
|
it('Populates collection when the type is changed to automatic and filter is present', async function () {
|
|
const collection = await collectionsService.createCollection({
|
|
title: 'I am automatic',
|
|
description: 'testing automatic collection',
|
|
type: 'manual'
|
|
});
|
|
|
|
assert.equal(collection.type, 'manual', 'Collection should be manual');
|
|
assert.equal(collection.posts.length, 0, 'Collection should have no posts');
|
|
|
|
const automaticCollection = await collectionsService.edit({
|
|
id: collection.id,
|
|
type: 'automatic',
|
|
filter: 'featured:true'
|
|
});
|
|
|
|
assert.equal(automaticCollection?.posts.length, 2, 'Collection should have two featured post');
|
|
assert.equal(automaticCollection?.posts[0].id, 'post-3-featured', 'Collection should have the correct post');
|
|
});
|
|
|
|
it('Updates the automatic collection posts when the filter is changed', async function () {
|
|
let collection = await collectionsService.createCollection({
|
|
title: 'I am automatic',
|
|
description: 'testing automatic collection',
|
|
type: 'automatic',
|
|
filter: 'featured:true'
|
|
});
|
|
|
|
assert.equal(collection?.type, 'automatic', 'Collection should be automatic');
|
|
assert.equal(collection?.posts.length, 2, 'Collection should have two featured post');
|
|
assert.equal(collection?.posts[0].id, 'post-3-featured', 'Collection should have the correct post');
|
|
assert.equal(collection?.posts[1].id, 'post-4-featured', 'Collection should have the correct post');
|
|
|
|
let updatedCollection = await collectionsService.edit({
|
|
id: collection.id,
|
|
filter: 'slug:post-2'
|
|
});
|
|
|
|
assert.equal(updatedCollection?.posts.length, 1, 'Collection should have one post');
|
|
assert.equal(updatedCollection?.posts[0].id, 'post-2', 'Collection should have the correct post');
|
|
});
|
|
|
|
describe('updateCollections', function () {
|
|
let automaticFeaturedCollection: any;
|
|
let automaticNonFeaturedCollection: any;
|
|
let manualCollection: any;
|
|
|
|
beforeEach(async function () {
|
|
automaticFeaturedCollection = await collectionsService.createCollection({
|
|
title: 'Featured Collection',
|
|
description: 'testing automatic collection',
|
|
type: 'automatic',
|
|
filter: 'featured:true'
|
|
});
|
|
|
|
automaticNonFeaturedCollection = await collectionsService.createCollection({
|
|
title: 'Non-Featured Collection',
|
|
description: 'testing automatic collection',
|
|
type: 'automatic',
|
|
filter: 'featured:false'
|
|
});
|
|
|
|
manualCollection = await collectionsService.createCollection({
|
|
title: 'Manual Collection',
|
|
description: 'testing manual collection',
|
|
type: 'manual'
|
|
});
|
|
|
|
await collectionsService.addPostToCollection(manualCollection.id, posts[0]);
|
|
await collectionsService.addPostToCollection(manualCollection.id, posts[1]);
|
|
});
|
|
|
|
afterEach(async function () {
|
|
await collectionsService.destroy(automaticFeaturedCollection.id);
|
|
await collectionsService.destroy(automaticNonFeaturedCollection.id);
|
|
await collectionsService.destroy(manualCollection.id);
|
|
});
|
|
|
|
it('Updates all collections when post is deleted', async function () {
|
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 2);
|
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2);
|
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2);
|
|
|
|
const updateCollectionEvent = CollectionResourceChangeEvent.create('post.deleted', {
|
|
id: posts[0].id,
|
|
resource: 'post'
|
|
});
|
|
|
|
await collectionsService.updateCollections(updateCollectionEvent);
|
|
|
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 2);
|
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 1);
|
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 1);
|
|
});
|
|
|
|
it('Updates automatic collections only when post is published', async function () {
|
|
const newPost = {
|
|
id: 'post-published',
|
|
title: 'Post Published',
|
|
slug: 'post-published',
|
|
featured: true,
|
|
published_at: new Date('2023-03-16T07:19:07.447Z'),
|
|
deleted: false
|
|
};
|
|
await postsRepository.save(newPost);
|
|
|
|
const updateCollectionEvent = CollectionResourceChangeEvent.create('post.published', {
|
|
id: newPost.id,
|
|
resource: 'post'
|
|
});
|
|
|
|
await collectionsService.updateCollections(updateCollectionEvent);
|
|
|
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 3);
|
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2);
|
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2);
|
|
});
|
|
});
|
|
});
|
|
});
|