import request from 'supertest'; import app from '../../src/app'; import { pool } from '../../src/db'; import { resetDb, closeDb } from './setup/testDb'; beforeEach(async () => { await resetDb(); }); afterAll(async () => { await pool.end(); await closeDb(); }); const PNG = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==', 'base64' ); /** * Nothing exists, so every id below is absent. 999999 is well-formed and * missing; 'abc' is not a number at all. Before #207 the first answered 200 * with an empty body and the second answered 500, because the raw string * reached Postgres and raised 22P02. */ const ABSENT = 999999; describe('admin item routes for an id that does not exist', () => { it('PUT answers 404 rather than 200 with an empty body', async () => { const res = await request(app) .put(`/api/admin/items/${ABSENT}`) .field('name', 'renamed') .field('price', '10.00'); expect(res.status).toBe(404); expect(res.body).toEqual({ error: 'not found' }); }); it('mark-sold answers 404', async () => { const res = await request(app).post(`/api/admin/items/${ABSENT}/mark-sold`); expect(res.status).toBe(404); }); it('mark-available answers 404', async () => { const res = await request(app).post(`/api/admin/items/${ABSENT}/mark-available`); expect(res.status).toBe(404); }); // A garbage id used to reach Postgres and raise 22P02, which the catch turned // into a 500. From the caller's side "/items/abc" identifies no item, exactly // like "/items/999999" does. it.each(['abc', '1.5', '-1', ''])('PUT answers 404 for the id %p', async (id) => { const res = await request(app) .put(`/api/admin/items/${id}`) .field('name', 'renamed') .field('price', '10.00'); expect(res.status).toBe(404); }); it('mark-available answers 404 for a non-numeric id', async () => { const res = await request(app).post('/api/admin/items/abc/mark-available'); expect(res.status).toBe(404); }); }); describe('admin item routes for an id that does exist', () => { async function makeItem(): Promise { const res = await request(app) .post('/api/admin/items') .field('name', 'a real item') .field('price', '12.00') .attach('images', PNG, 'a.png'); return res.body.id; } // The point of the change is to stop lying about misses, not to start // refusing hits. it('PUT still updates and answers with the item', async () => { const id = await makeItem(); const res = await request(app) .put(`/api/admin/items/${id}`) .field('name', 'renamed') .field('price', '15.00'); expect(res.status).toBe(200); expect(res.body.name).toBe('renamed'); expect(res.body.price_cents).toBe(1500); }); it('mark-available still publishes', async () => { const id = await makeItem(); const res = await request(app).post(`/api/admin/items/${id}/mark-available`); expect(res.status).toBe(200); expect(res.body.status).toBe('available'); }); }); describe('a non-numeric id on every admin item route', () => { // Each of these used to reach Postgres, raise 22P02 and surface as a 500. it.each([ ['mark-sold', '/api/admin/items/abc/mark-sold'], ['mark-available', '/api/admin/items/abc/mark-available'] ])('%s answers 404', async (_name, path) => { expect((await request(app).post(path)).status).toBe(404); }); });