UNPKG

@accounter/scraper-app

Version:
134 lines (116 loc) 3.88 kB
import { randomBytes } from 'node:crypto'; import { rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import Fastify, { type FastifyInstance } from 'fastify'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { defaultVault, saveVaultFile } from '../vault.js'; import { lockVault } from '../vault-store.js'; import { registerVaultRoutes } from '../vault-routes.js'; const PASSWORD = 'test-password-123'; let vaultPath: string; let app: FastifyInstance; beforeEach(async () => { vaultPath = join(tmpdir(), `vault-test-${randomBytes(4).toString('hex')}.vault`); process.env['VAULT_PATH'] = vaultPath; const vault = defaultVault(); vault.accountRecords.push({ id: 'acc-1', sourceId: 'src-a', sourceType: 'poalim', accountNumber: '123456', branchNumber: '700', status: 'pending', }); await saveVaultFile(vaultPath, vault, PASSWORD); app = Fastify(); await registerVaultRoutes(app); await app.ready(); await app.inject({ method: 'POST', url: '/api/vault/unlock', payload: { password: PASSWORD }, }); }); afterEach(async () => { lockVault(); await app.close(); await rm(vaultPath, { force: true }); delete process.env['VAULT_PATH']; }); describe('GET /api/vault/accounts', () => { it('returns the pre-seeded account', async () => { const res = await app.inject({ method: 'GET', url: '/api/vault/accounts' }); expect(res.statusCode).toBe(200); const list = res.json() as Array<{ id: string; status: string }>; expect(list).toHaveLength(1); expect(list[0].id).toBe('acc-1'); expect(list[0].status).toBe('pending'); }); it('returns 401 when vault is locked', async () => { lockVault(); const res = await app.inject({ method: 'GET', url: '/api/vault/accounts' }); expect(res.statusCode).toBe(401); }); }); describe('PUT /api/vault/accounts/:id', () => { it('sets status to accepted and returns updated list', async () => { const res = await app.inject({ method: 'PUT', url: '/api/vault/accounts/acc-1', payload: { status: 'accepted' }, }); expect(res.statusCode).toBe(200); const list = res.json() as Array<{ id: string; status: string }>; expect(list[0].status).toBe('accepted'); }); it('sets status to ignored', async () => { const res = await app.inject({ method: 'PUT', url: '/api/vault/accounts/acc-1', payload: { status: 'ignored' }, }); expect(res.statusCode).toBe(200); expect((res.json() as Array<{ status: string }>)[0].status).toBe('ignored'); }); it('persists across re-lock/unlock', async () => { await app.inject({ method: 'PUT', url: '/api/vault/accounts/acc-1', payload: { status: 'accepted' }, }); lockVault(); await app.inject({ method: 'POST', url: '/api/vault/unlock', payload: { password: PASSWORD }, }); const res = await app.inject({ method: 'GET', url: '/api/vault/accounts' }); expect((res.json() as Array<{ status: string }>)[0].status).toBe('accepted'); }); it('returns 404 for unknown id', async () => { const res = await app.inject({ method: 'PUT', url: '/api/vault/accounts/does-not-exist', payload: { status: 'accepted' }, }); expect(res.statusCode).toBe(404); }); it('returns 400 for invalid status value', async () => { const res = await app.inject({ method: 'PUT', url: '/api/vault/accounts/acc-1', payload: { status: 'pending' }, }); expect(res.statusCode).toBe(400); }); it('returns 401 when vault is locked', async () => { lockVault(); const res = await app.inject({ method: 'PUT', url: '/api/vault/accounts/acc-1', payload: { status: 'accepted' }, }); expect(res.statusCode).toBe(401); }); });