import { randomUUID } from 'crypto'; import assert from 'assert'; import { range } from 'lodash'; import request from 'supertest'; import * as producer from '@spokenio/jobqueue-producer'; import { Page, Product } from '@/entities'; import app from '..'; const createPage = async (values = {}) => { const product = await Product.create({ firebaseId: randomUUID(), }).save(); return await Page.create({ firebaseId: randomUUID(), productFirebaseId: product.firebaseId, price: 100, retailer: 'amazon', url: 'test://test', urlOriginal: 'test://test', ...values, }).save(); }; /** * Waits until `fn` does not throw. Tries every 50ms. */ const waitFor = async (fn: () => void | Promise) => { return new Promise((resolve) => { const interval = setInterval(() => { Promise.resolve(fn()) .then(() => { clearInterval(interval); resolve(); }) .catch(() => { // no-op }); }, 50); }); }; describe('PUT /update', () => { it('should not add jobs for brand new pages', async () => { // create 5 pages await Promise.all( range(5).map(() => { return createPage(); }) ); const response = await request(app()).put('/update'); expect(response.status).toBe(200); expect(response.body.status).toBe('queued'); }); it('should add jobs for pages that were created a while ago', async () => { // create 5 pages await Promise.all( range(5).map(() => { return createPage({ // last scraped a year ago lastScrapedAt: new Date( new Date().getTime() - 1000 * 60 * 60 * 24 * 365 ), }); }) ); const addJobSpy = jest.spyOn(producer, 'addJob'); const response = await request(app()).put('/update'); expect(response.status).toBe(200); expect(response.body.status).toBe('queued'); await waitFor(() => { // job added expect(addJobSpy.mock.calls[0][0]).toMatchInlineSnapshot( `"BULK_FETCH_LATEST_PAGE_1"` ); assert(addJobSpy.mock.calls[0][1]); assert('pages' in addJobSpy.mock.calls[0][1]); expect(addJobSpy.mock.calls[0][1]?.pages).toHaveLength(5); expect(addJobSpy.mock.calls[0][1]?.pages).toMatchObject( range(5).map(() => expect.objectContaining({ pageId: expect.any(String), productId: expect.any(String), url: 'test://test', }) ) ); }); }); it('should add jobs for all pages if force updating', async () => { // create 5 pages await Promise.all( range(5).map(() => { return createPage(); }) ); const addJobSpy = jest.spyOn(producer, 'addJob'); const response = await request(app()).put('/update?force=1'); expect(response.status).toBe(200); expect(response.body.status).toBe('queued'); await waitFor(() => { // job added expect(addJobSpy.mock.calls[0][0]).toMatchInlineSnapshot( `"BULK_FETCH_LATEST_PAGE_1"` ); // job payload assert(addJobSpy.mock.calls[0][1]); assert('pages' in addJobSpy.mock.calls[0][1]); expect(addJobSpy.mock.calls[0][1]?.pages).toHaveLength(5); expect(addJobSpy.mock.calls[0][1]?.pages).toMatchObject( range(5).map(() => expect.objectContaining({ pageId: expect.any(String), productId: expect.any(String), url: 'test://test', }) ) ); }); }); });