UNPKG

payload-plugin-scheduler

Version:
280 lines (244 loc) 7.34 kB
import { addMinutes } from 'date-fns' import { type Payload } from 'payload' import { INTERVAL } from '../src/payload.base.config' const waitFor = (time: number): Promise<void> => new Promise(resolve => setTimeout(resolve, time)) describe('Plugin tests', () => { const payload = globalThis.payloadClient as Payload // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const findSchedule = (id: string | number) => payload.find({ collection: 'scheduled_posts', where: { and: [ { 'post.value': { equals: id, }, }, { 'post.relationTo': { equals: 'posts', }, }, ], }, }) it('schedules collection docs', async () => { const pubDate = addMinutes(new Date(), 2).toISOString() const doc = await payload.create({ collection: 'posts', data: { title: 'hello', content: 'world', publish_date: pubDate, }, }) expect(doc.id).toBeTruthy() expect(doc.publish_date).toBe(pubDate) const { totalDocs, docs: [schedule], } = await findSchedule(doc.id) expect(totalDocs).toBe(1) expect(schedule.date).toBe(doc.publish_date) expect(schedule.status).toBe('queued') }) it('schedules global docs', async () => { const pubDate = addMinutes(new Date(), 2).toISOString() const doc = await payload.updateGlobal({ slug: 'home', data: { title: 'hello world', publish_date: pubDate, _status: 'draft', }, }) expect(doc.publish_date).toBe(pubDate) expect(doc._status).toBe('draft') const { totalDocs, docs: [schedule], } = await payload.find({ collection: 'scheduled_posts', where: { global: { equals: 'home' } } }) expect(totalDocs).toBe(1) expect(schedule.date).toBe(doc.publish_date) expect(schedule.status).toBe('queued') }) it('bounds publish_date', async () => { const now = new Date() const futureDate = addMinutes(now, 10) const doc = await payload.create({ collection: 'posts', data: { title: 'hello', content: 'world', publish_date: futureDate.toISOString(), _status: 'published', }, }) // if `publish_date` is in the future at publish time, should be reset to now const actualPublishDate = new Date(doc.publish_date as string) expect(actualPublishDate.getMinutes()).toBe(now.getMinutes()) // shouldn't be scheduled either const { totalDocs } = await findSchedule(doc.id) expect(totalDocs).toBe(0) }) it( 'publishes scheduled posts', async () => { const now = new Date() const pubDate = addMinutes(now, INTERVAL) const draft = await payload.create({ collection: 'posts', data: { title: 'hello', publish_date: pubDate.toISOString(), }, }) const { totalDocs } = await findSchedule(draft.id) expect(totalDocs).toBe(1) // wait for the interval + extra await waitFor(1000 * 60 * INTERVAL + 5000) const publishedDraft = await payload.findByID({ collection: 'posts', id: draft.id, }) // eslint-disable-next-line no-underscore-dangle expect(publishedDraft._status).toBe('published') const { totalDocs: updatedTotalDocs } = await findSchedule(draft.id) expect(updatedTotalDocs).toBe(0) }, // timeout = interval + 1 min 1000 * 60 * (INTERVAL + 1), ) it('handles subsequent draft updates to pending posts', async () => { const now = new Date() const pubDate = addMinutes(now, 5) const draft = await payload.create({ collection: 'posts', data: { title: 'hello world', publish_date: pubDate.toISOString(), }, }) expect(draft.id).toBeTruthy() const { totalDocs, docs } = await findSchedule(draft.id) expect(totalDocs).toBe(1) expect(docs[0].date).toBe(pubDate.toISOString()) const updatedPubDate = addMinutes(pubDate, 5).toISOString() await payload.update({ collection: 'posts', data: { publish_date: updatedPubDate, }, where: { id: { equals: draft.id, }, }, }) const updatedSchedules = await findSchedule(draft.id) expect(updatedSchedules.totalDocs).toBe(1) expect(updatedSchedules.docs[0].date).toBe(updatedPubDate) }) it('cancels pending schedules', async () => { const now = new Date() const pubDate = addMinutes(now, 5) const draft = await payload.create({ collection: 'posts', data: { title: 'hello world', publish_date: pubDate.toISOString(), }, }) const { totalDocs, docs } = await findSchedule(draft.id) expect(totalDocs).toBe(1) expect(docs[0].date).toBe(pubDate.toISOString()) const updated = await payload.update({ collection: 'posts', where: { id: { equals: draft.id, }, }, data: { // @ts-expect-error publish_date: null, }, }) expect(updated.docs[0].publish_date).toBeNull() const updatedSchedule = await findSchedule(draft.id) expect(updatedSchedule.totalDocs).toBe(0) }) it('handles delete docs', async () => { const now = new Date() const pubDate = addMinutes(now, 5) const draft = await payload.create({ collection: 'posts', data: { title: 'hello world', publish_date: pubDate.toISOString(), }, }) const { totalDocs } = await findSchedule(draft.id) expect(totalDocs).toBe(1) payload.delete({ collection: 'posts', id: draft.id, }) await waitFor(2000) const updatedSchedules = await findSchedule(draft.id) expect(updatedSchedules.totalDocs).toBe(0) }, 9000) it('handles peer hook errors', async () => { const now = new Date() const pubDate = addMinutes(now, INTERVAL) const [draft, badDraft, badDraft2] = await Promise.all([ payload.create({ collection: 'pageswithextrahooks', data: { title: 'hello world', publish_date: pubDate.toISOString(), } }), payload.create({ collection: 'pageswithextrahooks', data: { title: 'throw', publish_date: pubDate.toISOString(), } }), payload.create({ collection: 'pageswithextrahooks', data: { title: 'commit-and-throw', publish_date: pubDate.toISOString(), } }), ]) await waitFor(1000 * 60 * INTERVAL + 2000) const [updatedDraft, updatedBadDraft, updatedBadDraft2] = await Promise.all([ payload.findByID({ collection: 'pageswithextrahooks', id: draft.id, }), payload.findByID({ collection: 'pageswithextrahooks', id: badDraft.id, }), payload.findByID({ collection: 'pageswithextrahooks', id: badDraft2.id, }), ]) expect(updatedDraft._status).toBe('published') expect(updatedBadDraft._status).toBe('draft') expect(updatedBadDraft2._status).toBe('published') }, 1000 * 60 * INTERVAL + 5000) })