mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 03:14:03 +03:00
edcd6caf2b
Having this as a default means that API responses are HUGE! Co-authored-by: Daniel Lockyer <hi@daniellockyer.com>
862 lines
28 KiB
JavaScript
862 lines
28 KiB
JavaScript
const assert = require('assert/strict');
|
|
const DomainEvents = require('@tryghost/domain-events');
|
|
const {
|
|
agentProvider,
|
|
fixtureManager,
|
|
mockManager,
|
|
matchers
|
|
} = require('../../utils/e2e-framework');
|
|
const {
|
|
anyContentVersion,
|
|
anyEtag,
|
|
anyErrorId,
|
|
anyLocationFor,
|
|
anyObjectId,
|
|
anyISODateTime,
|
|
anyString,
|
|
anyUuid,
|
|
anyArray,
|
|
anyObject
|
|
} = matchers;
|
|
|
|
const matchCollection = {
|
|
id: anyObjectId,
|
|
created_at: anyISODateTime,
|
|
updated_at: anyISODateTime
|
|
};
|
|
|
|
const tagSnapshotMatcher = {
|
|
id: anyObjectId,
|
|
created_at: anyISODateTime,
|
|
updated_at: anyISODateTime
|
|
};
|
|
|
|
const matchPostShallowIncludes = {
|
|
id: anyObjectId,
|
|
uuid: anyUuid,
|
|
comment_id: anyString,
|
|
url: anyString,
|
|
authors: anyArray,
|
|
primary_author: anyObject,
|
|
tags: anyArray,
|
|
primary_tag: anyObject,
|
|
tiers: anyArray,
|
|
created_at: anyISODateTime,
|
|
updated_at: anyISODateTime,
|
|
published_at: anyISODateTime
|
|
};
|
|
|
|
async function trackDb(fn, skip) {
|
|
const db = require('../../../core/server/data/db');
|
|
if (db?.knex?.client?.config?.client !== 'sqlite3') {
|
|
return skip();
|
|
}
|
|
/** @type {import('sqlite3').Database} */
|
|
const database = db.knex.client;
|
|
|
|
const queries = [];
|
|
function handler(/** @type {{sql: string}} */ query) {
|
|
queries.push(query);
|
|
}
|
|
|
|
database.on('query', handler);
|
|
|
|
await fn();
|
|
|
|
database.off('query', handler);
|
|
|
|
return queries;
|
|
}
|
|
|
|
describe('Collections API', function () {
|
|
let agent;
|
|
|
|
before(async function () {
|
|
mockManager.mockLabsEnabled('collections');
|
|
agent = await agentProvider.getAdminAPIAgent();
|
|
await fixtureManager.init('users', 'posts');
|
|
await agent.loginAsOwner();
|
|
});
|
|
|
|
afterEach(function () {
|
|
mockManager.restore();
|
|
});
|
|
|
|
describe('Browse', function () {
|
|
it('Can browse Collections', async function () {
|
|
await agent
|
|
.get('/collections/')
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [
|
|
matchCollection,
|
|
matchCollection
|
|
]
|
|
});
|
|
});
|
|
|
|
it('Makes limited DB queries when browsing', async function () {
|
|
const queries = await trackDb(async () => {
|
|
await agent
|
|
.get('/collections/')
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [
|
|
matchCollection,
|
|
matchCollection
|
|
]
|
|
});
|
|
}, this.skip.bind(this));
|
|
const collectionRelatedQueries = queries.filter(query => query.sql.includes('collection'));
|
|
assert(collectionRelatedQueries.length === 3);
|
|
});
|
|
|
|
it('Can browse Collections and include the posts count', async function () {
|
|
await agent
|
|
.get('/collections/?include=count.posts')
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [
|
|
{...matchCollection, count: {posts: 13}},
|
|
{...matchCollection, count: {posts: 2}}
|
|
]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Read', function () {
|
|
it('Can read a Collection by id and slug', async function () {
|
|
const collection = {
|
|
title: 'Test Collection to Read'
|
|
};
|
|
|
|
const addResponse = await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
const collectionId = addResponse.body.collections[0].id;
|
|
|
|
const readResponse = await agent
|
|
.get(`/collections/${collectionId}/`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
assert.equal(readResponse.body.collections[0].title, 'Test Collection to Read');
|
|
|
|
const collectionSlug = addResponse.body.collections[0].slug;
|
|
const readBySlugResponse = await agent
|
|
.get(`/collections/slug/${collectionSlug}/`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
assert.equal(readBySlugResponse.body.collections[0].title, 'Test Collection to Read');
|
|
|
|
await agent
|
|
.delete(`/collections/${collectionId}/`)
|
|
.expectStatus(204);
|
|
});
|
|
|
|
it('Can read a Collection by id and slug and include the post counts', async function () {
|
|
const {body: {collections: [collection]}} = await agent.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
|
|
await agent.get(`/collections/${collection.id}/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Edit', function () {
|
|
let collectionToEdit;
|
|
|
|
before(async function () {
|
|
const collection = {
|
|
title: 'Test Collection to Edit'
|
|
};
|
|
|
|
const addResponse = await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201);
|
|
|
|
collectionToEdit = addResponse.body.collections[0];
|
|
});
|
|
|
|
it('Can edit a Collection', async function () {
|
|
const editResponse = await agent
|
|
.put(`/collections/${collectionToEdit.id}/`)
|
|
.body({
|
|
collections: [{
|
|
title: 'Test Collection Edited'
|
|
}]
|
|
})
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
assert.equal(editResponse.body.collections[0].title, 'Test Collection Edited');
|
|
});
|
|
|
|
it('Fails to edit unexistent Collection', async function () {
|
|
const unexistentID = '5951f5fca366002ebd5dbef7';
|
|
await agent
|
|
.put(`/collections/${unexistentID}/`)
|
|
.body({
|
|
collections: [{
|
|
id: unexistentID,
|
|
title: 'Editing unexistent Collection'
|
|
}]
|
|
})
|
|
.expectStatus(404)
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId
|
|
}]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Add', function () {
|
|
it('Can add a Collection', async function () {
|
|
const collection = {
|
|
title: 'Test Collection',
|
|
description: 'Test Collection Description'
|
|
};
|
|
|
|
const {body: {collections: [{id: collectionId}]}} = await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
await agent
|
|
.delete(`/collections/${collectionId}/`)
|
|
.expectStatus(204);
|
|
});
|
|
});
|
|
|
|
describe('Delete', function () {
|
|
it('Can delete a Collection', async function () {
|
|
const collection = {
|
|
title: 'Test Collection to Delete'
|
|
};
|
|
|
|
const addResponse = await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
const collectionId = addResponse.body.collections[0].id;
|
|
|
|
await agent
|
|
.delete(`/collections/${collectionId}/`)
|
|
.expectStatus(204)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot();
|
|
|
|
await agent
|
|
.get(`/collections/${collectionId}/`)
|
|
.expectStatus(404)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Cannot delete a built in collection', async function () {
|
|
const builtInCollection = await agent
|
|
.get('/collections/?filter=slug:featured')
|
|
.expectStatus(200);
|
|
|
|
assert.ok(builtInCollection.body.collections);
|
|
assert.equal(builtInCollection.body.collections.length, 1);
|
|
|
|
await agent
|
|
.delete(`/collections/${builtInCollection.body.collections[0].id}/`)
|
|
.expectStatus(405)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId,
|
|
context: anyString
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Automatic Collection Filtering', function () {
|
|
it('Creates an automatic Collection with a featured filter', async function () {
|
|
const collection = {
|
|
title: 'Test Featured Collection',
|
|
slug: 'featured-filter',
|
|
description: 'Test Collection Description',
|
|
type: 'automatic',
|
|
filter: 'featured:true'
|
|
};
|
|
|
|
await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
await agent.get(`posts/?collection=${collection.slug}`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
posts: new Array(2).fill(matchPostShallowIncludes)
|
|
});
|
|
});
|
|
|
|
it('Creates an automatic Collection with a published_at filter', async function () {
|
|
const collection = {
|
|
title: 'Test Collection with published_at filter',
|
|
slug: 'published-at-filter',
|
|
description: 'Test Collection Description with published_at filter',
|
|
type: 'automatic',
|
|
filter: 'published_at:>=2022-05-25'
|
|
};
|
|
|
|
await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
await agent.get(`posts/?collection=${collection.slug}`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
posts: new Array(9).fill(matchPostShallowIncludes)
|
|
});
|
|
});
|
|
|
|
it('Creates an automatic Collection with a tags filter', async function () {
|
|
const collection = {
|
|
title: 'Test Collection with tag filter',
|
|
slug: 'tag-filter',
|
|
description: 'BACON!',
|
|
type: 'automatic',
|
|
filter: 'tags:[\'bacon\']'
|
|
};
|
|
|
|
await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
await agent.get(`posts/?collection=${collection.slug}`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
posts: new Array(2).fill({
|
|
...matchPostShallowIncludes,
|
|
tags: new Array(2).fill(tagSnapshotMatcher)
|
|
})
|
|
});
|
|
});
|
|
|
|
it('Creates an automatic Collection with a tag filter, checking filter aliases', async function () {
|
|
const collection = {
|
|
title: 'Test Collection with tag filter alias',
|
|
slug: 'bacon-tag-expansion',
|
|
description: 'BACON!',
|
|
type: 'automatic',
|
|
filter: 'tag:[\'bacon\']'
|
|
};
|
|
|
|
await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
await agent.get(`posts/?collection=${collection.slug}`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
posts: new Array(2).fill({
|
|
...matchPostShallowIncludes,
|
|
tags: new Array(2).fill(tagSnapshotMatcher)
|
|
})
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Collection Posts updates automatically', function () {
|
|
it('Makes limited DB queries when updating due to post changes', async function () {
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
|
|
const postToAdd = {
|
|
title: 'Collection update test',
|
|
featured: false
|
|
};
|
|
|
|
let post;
|
|
|
|
{
|
|
const queries = await trackDb(async () => {
|
|
const {body: {posts: [createdPost]}} = await agent
|
|
.post('/posts/')
|
|
.body({
|
|
posts: [postToAdd]
|
|
})
|
|
.expectStatus(201);
|
|
|
|
await DomainEvents.allSettled();
|
|
|
|
post = createdPost;
|
|
}, this.skip.bind(this));
|
|
|
|
const collectionRelatedQueries = queries.filter(query => query.sql.includes('collection'));
|
|
assert.equal(collectionRelatedQueries.length, 7);
|
|
}
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
|
|
{
|
|
const queries = await trackDb(async () => {
|
|
await agent
|
|
.put(`/posts/${post.id}/`)
|
|
.body({
|
|
posts: [Object.assign({}, post, {featured: true})]
|
|
})
|
|
.expectStatus(200);
|
|
|
|
await DomainEvents.allSettled();
|
|
}, this.skip.bind(this));
|
|
|
|
const collectionRelatedQueries = queries.filter(query => query.sql.includes('collection'));
|
|
assert.equal(collectionRelatedQueries.length, 16);
|
|
}
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 3
|
|
}
|
|
}]
|
|
});
|
|
|
|
{
|
|
const queries = await trackDb(async () => {
|
|
await agent
|
|
.delete(`/posts/${post.id}/`)
|
|
.expectStatus(204);
|
|
|
|
await DomainEvents.allSettled();
|
|
}, this.skip.bind(this));
|
|
const collectionRelatedQueries = queries.filter(query => query.sql.includes('collection'));
|
|
|
|
// deletion is handled on the DB layer through Cascade Delete,
|
|
// so collections should not execute any additional queries
|
|
assert.equal(collectionRelatedQueries.length, 0);
|
|
}
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
it('Updates collections when a Post is added/edited/deleted', async function () {
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
|
|
const postToAdd = {
|
|
title: 'Collection update test',
|
|
featured: false
|
|
};
|
|
|
|
const {body: {posts: [post]}} = await agent
|
|
.post('/posts/')
|
|
.body({
|
|
posts: [postToAdd]
|
|
})
|
|
.expectStatus(201);
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
|
|
await agent
|
|
.put(`/posts/${post.id}/`)
|
|
.body({
|
|
posts: [Object.assign({}, post, {featured: true})]
|
|
})
|
|
.expectStatus(200);
|
|
|
|
await DomainEvents.allSettled();
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 3
|
|
}
|
|
}]
|
|
});
|
|
|
|
await agent
|
|
.delete(`/posts/${post.id}/`)
|
|
.expectStatus(204);
|
|
|
|
await DomainEvents.allSettled();
|
|
|
|
await agent
|
|
.get(`/collections/slug/featured/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 2
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Updates a collection with tag filter when tag is added to posts in bulk and when tag is removed', async function (){
|
|
const collection = {
|
|
title: 'Papaya madness',
|
|
type: 'automatic',
|
|
filter: 'tags:[\'papaya\']'
|
|
};
|
|
|
|
const {body: {collections: [{id: collectionId}]}} = await agent
|
|
.post('/collections/')
|
|
.body({
|
|
collections: [collection]
|
|
})
|
|
.expectStatus(201)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('collections')
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [matchCollection]
|
|
});
|
|
|
|
// should contain no posts
|
|
await agent
|
|
.get(`/collections/${collectionId}/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 0
|
|
}
|
|
}]
|
|
});
|
|
|
|
const tag = {
|
|
name: 'Papaya',
|
|
slug: 'papaya'
|
|
};
|
|
|
|
const {body: {tags: [{id: tagId}]}} = await agent
|
|
.post('/tags/')
|
|
.body({
|
|
tags: [tag]
|
|
})
|
|
.expectStatus(201);
|
|
|
|
// add papaya tag to all posts
|
|
await agent
|
|
.put('/posts/bulk/?filter=' + encodeURIComponent('status:[published]'))
|
|
.body({
|
|
bulk: {
|
|
action: 'addTag',
|
|
meta: {
|
|
tags: [
|
|
{
|
|
id: tagId
|
|
}
|
|
]
|
|
}
|
|
}
|
|
})
|
|
.expectStatus(200)
|
|
.matchBodySnapshot();
|
|
|
|
await DomainEvents.allSettled();
|
|
|
|
// should contain posts with papaya tags
|
|
await agent
|
|
.get(`/collections/${collectionId}/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 11
|
|
}
|
|
}]
|
|
});
|
|
|
|
await agent
|
|
.delete(`/tags/${tagId}/`)
|
|
.expectStatus(204);
|
|
|
|
await DomainEvents.allSettled();
|
|
|
|
// should contain ZERO posts with papaya tags
|
|
await agent
|
|
.get(`/collections/${collectionId}/?include=count.posts`)
|
|
.expectStatus(200)
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
collections: [{
|
|
...matchCollection,
|
|
count: {
|
|
posts: 0
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
});
|
|
});
|