import { suite } from '../lib/context.js' // Helper: create a tiny 1x1 JPEG for testing uploads const TINY_JPEG = Buffer.from( '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB' + 'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEB' + 'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAEDASIA' + 'AhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEA' + 'AAAAAAAAAAAAAAAAAAAB/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AJgA//9k=', 'base64', ) suite('Files', { tags: ['files', 'storage'] }, (t) => { t.test('uploads an image file', { tags: ['upload'] }, async () => { const acct = await t.api.post('/v1/accounts', { name: 'File Test' }) const member = await t.api.post(`/v1/accounts/${acct.data.id}/members`, { firstName: 'File', lastName: 'Test', }) // Upload via multipart const formData = new FormData() formData.append('file', new Blob([TINY_JPEG], { type: 'image/jpeg' }), 'test.jpg') formData.append('entityType', 'member_identifier') formData.append('entityId', member.data.id) formData.append('category', 'front') const res = await fetch(`${t.baseUrl}/v1/files`, { method: 'POST', headers: { Authorization: `Bearer ${t.token}` }, body: formData, }) const data = await res.json() t.assert.equal(res.status, 201) t.assert.ok(data.id) t.assert.equal(data.contentType, 'image/jpeg') t.assert.equal(data.entityType, 'member_identifier') t.assert.equal(data.category, 'front') t.assert.ok(data.url) }) t.test('lists files for an entity', { tags: ['read'] }, async () => { const acct = await t.api.post('/v1/accounts', { name: 'File List Test' }) const member = await t.api.post(`/v1/accounts/${acct.data.id}/members`, { firstName: 'List', lastName: 'Files', }) // Upload a file first const formData = new FormData() formData.append('file', new Blob([TINY_JPEG], { type: 'image/jpeg' }), 'list-test.jpg') formData.append('entityType', 'member_identifier') formData.append('entityId', member.data.id) formData.append('category', 'back') await fetch(`${t.baseUrl}/v1/files`, { method: 'POST', headers: { Authorization: `Bearer ${t.token}` }, body: formData, }) const res = await t.api.get('/v1/files', { entityType: 'member_identifier', entityId: member.data.id, }) t.assert.status(res, 200) t.assert.greaterThan(res.data.data.length, 0) t.assert.ok(res.data.data[0].url) }) t.test('gets file metadata by id', { tags: ['read'] }, async () => { const acct = await t.api.post('/v1/accounts', { name: 'File Get Test' }) const member = await t.api.post(`/v1/accounts/${acct.data.id}/members`, { firstName: 'Get', lastName: 'File', }) const formData = new FormData() formData.append('file', new Blob([TINY_JPEG], { type: 'image/jpeg' }), 'get-test.jpg') formData.append('entityType', 'member_identifier') formData.append('entityId', member.data.id) formData.append('category', 'front') const uploadRes = await fetch(`${t.baseUrl}/v1/files`, { method: 'POST', headers: { Authorization: `Bearer ${t.token}` }, body: formData, }) const uploaded = await uploadRes.json() const res = await t.api.get(`/v1/files/${uploaded.id}`) t.assert.status(res, 200) t.assert.equal(res.data.id, uploaded.id) t.assert.equal(res.data.filename, 'get-test.jpg') }) t.test('deletes a file', { tags: ['delete'] }, async () => { const acct = await t.api.post('/v1/accounts', { name: 'File Delete Test' }) const member = await t.api.post(`/v1/accounts/${acct.data.id}/members`, { firstName: 'Delete', lastName: 'File', }) const formData = new FormData() formData.append('file', new Blob([TINY_JPEG], { type: 'image/jpeg' }), 'delete-test.jpg') formData.append('entityType', 'member_identifier') formData.append('entityId', member.data.id) formData.append('category', 'front') const uploadRes = await fetch(`${t.baseUrl}/v1/files`, { method: 'POST', headers: { Authorization: `Bearer ${t.token}` }, body: formData, }) const uploaded = await uploadRes.json() const res = await t.api.del(`/v1/files/${uploaded.id}`) t.assert.status(res, 200) const check = await t.api.get(`/v1/files/${uploaded.id}`) t.assert.status(check, 404) }) t.test('rejects unsupported file types', { tags: ['validation'] }, async () => { const acct = await t.api.post('/v1/accounts', { name: 'File Reject Test' }) const formData = new FormData() formData.append('file', new Blob(['not an image'], { type: 'text/plain' }), 'test.txt') formData.append('entityType', 'member_identifier') formData.append('entityId', acct.data.id) formData.append('category', 'front') const res = await fetch(`${t.baseUrl}/v1/files`, { method: 'POST', headers: { Authorization: `Bearer ${t.token}` }, body: formData, }) t.assert.equal(res.status, 400) }) t.test('returns 404 for missing file', { tags: ['read'] }, async () => { const res = await t.api.get('/v1/files/a0000000-0000-0000-0000-999999999999') t.assert.status(res, 404) }) })