Fixed flaky test behavior for bulk actions
refs https://ghost.slack.com/archives/C02G9E68C/p1692816097875899 - With introduction of extra e2e test coverage for Collections some tests started to fail at random. The root issue here was the transaction processing collections was started before the original bulk action (bulk edit, bulk publish/unpublish, etc.) was fully committed. The full transaction commit happens with the bulkAction method return inside of `if (!options.transacting) {` block.
This commit is contained in:
parent
08d6425a53
commit
46f8c15448
@ -352,6 +352,10 @@ describe('Posts Bulk API', function () {
|
||||
// Check if all posts were deleted
|
||||
const posts = await models.Post.findPage({filter, status: 'all'});
|
||||
assert.equal(posts.meta.pagination.total, 0, `Expect all matching posts (${amount}) to be deleted`);
|
||||
|
||||
let latestCollection = await models.Collection.findPage({filter: 'slug:latest', limit: 1, withRelated: ['posts']});
|
||||
latestCollection = latestCollection.data[0].toJSON().posts.length;
|
||||
assert.equal(latestCollection, 0, 'Expect to have no collection posts');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -224,13 +224,22 @@ class PostsService {
|
||||
|
||||
async bulkEdit(data, options) {
|
||||
if (data.action === 'unpublish') {
|
||||
return await this.#updatePosts({status: 'draft'}, {filter: this.#mergeFilters('status:published', options.filter), context: options.context, actionName: 'unpublished'});
|
||||
const updateResult = await this.#updatePosts({status: 'draft'}, {filter: this.#mergeFilters('status:published', options.filter), context: options.context, actionName: 'unpublished'});
|
||||
DomainEvents.dispatch(PostsBulkUnpublishedEvent.create(updateResult.editIds));
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
if (data.action === 'feature') {
|
||||
return await this.#updatePosts({featured: true}, {filter: options.filter, context: options.context, actionName: 'featured'});
|
||||
const updateResult = await this.#updatePosts({featured: true}, {filter: options.filter, context: options.context, actionName: 'featured'});
|
||||
DomainEvents.dispatch(PostsBulkFeaturedEvent.create(updateResult.editIds));
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
if (data.action === 'unfeature') {
|
||||
return await this.#updatePosts({featured: false}, {filter: options.filter, context: options.context, actionName: 'unfeatured'});
|
||||
const updateResult = await this.#updatePosts({featured: false}, {filter: options.filter, context: options.context, actionName: 'unfeatured'});
|
||||
DomainEvents.dispatch(PostsBulkUnfeaturedEvent.create(updateResult.editIds));
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
if (data.action === 'access') {
|
||||
if (!['public', 'members', 'paid', 'tiers'].includes(data.meta.visibility)) {
|
||||
@ -267,7 +276,11 @@ class PostsService {
|
||||
});
|
||||
}
|
||||
}
|
||||
return await this.#bulkAddTags({tags: data.meta.tags}, {filter: options.filter, context: options.context});
|
||||
|
||||
const bulkResult = await this.#bulkAddTags({tags: data.meta.tags}, {filter: options.filter, context: options.context});
|
||||
DomainEvents.dispatch(PostsBulkAddTagsEvent.create(bulkResult.editIds));
|
||||
|
||||
return bulkResult;
|
||||
}
|
||||
throw new errors.IncorrectUsageError({
|
||||
message: tpl(messages.unsupportedBulkAction)
|
||||
@ -281,6 +294,7 @@ class PostsService {
|
||||
* @param {string} options.filter - An NQL Filter
|
||||
* @param {object} options.context
|
||||
* @param {object} [options.transacting]
|
||||
* @returns {Promise<{successful: number, unsuccessful: number, editIds: string[]}>}
|
||||
*/
|
||||
async #bulkAddTags(data, options) {
|
||||
if (!options.transacting) {
|
||||
@ -320,16 +334,19 @@ class PostsService {
|
||||
await options.transacting('posts_tags').insert(postTags);
|
||||
await this.models.Post.addActions('edited', postRows.map(p => p.id), options);
|
||||
|
||||
const event = PostsBulkAddTagsEvent.create(postTags.map(pt => pt.post_id));
|
||||
DomainEvents.dispatch(event);
|
||||
|
||||
return {
|
||||
editIds: postRows.map(p => p.id),
|
||||
successful: postRows.length,
|
||||
unsuccessful: 0
|
||||
};
|
||||
}
|
||||
|
||||
async bulkDestroy(options) {
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns Promise<{successful: number, unsuccessful: number, deleteIds: string[]}>
|
||||
*/
|
||||
async #bulkDestroy(options) {
|
||||
if (!options.transacting) {
|
||||
return await this.models.Post.transaction(async (transacting) => {
|
||||
return await this.bulkDestroy({
|
||||
@ -398,8 +415,14 @@ class PostsService {
|
||||
await this.models.Post.bulkDestroy(deleteEmailIds, 'emails', {transacting: options.transacting, throwErrors: true});
|
||||
const result = await this.models.Post.bulkDestroy(deleteIds, 'posts', {...options, throwErrors: true});
|
||||
|
||||
const event = PostsBulkDestroyedEvent.create(deleteIds);
|
||||
DomainEvents.dispatch(event);
|
||||
result.deleteIds = deleteIds;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async bulkDestroy(options) {
|
||||
const result = await this.#bulkDestroy(options);
|
||||
DomainEvents.dispatch(PostsBulkDestroyedEvent.create(result.deleteIds));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -467,22 +490,7 @@ class PostsService {
|
||||
});
|
||||
}
|
||||
|
||||
if (options.actionName) {
|
||||
let bulkActionEvent;
|
||||
switch (options.actionName) {
|
||||
case 'unpublished':
|
||||
bulkActionEvent = PostsBulkUnpublishedEvent.create(editIds);
|
||||
break;
|
||||
case 'featured':
|
||||
bulkActionEvent = PostsBulkFeaturedEvent.create(editIds);
|
||||
break;
|
||||
case 'unfeatured':
|
||||
bulkActionEvent = PostsBulkUnfeaturedEvent.create(editIds);
|
||||
break;
|
||||
}
|
||||
|
||||
DomainEvents.dispatch(bulkActionEvent);
|
||||
}
|
||||
result.editIds = editIds;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user