87 lines
3.4 KiB
TypeScript
87 lines
3.4 KiB
TypeScript
import request from 'supertest';
|
|
import { buildApp } from '../src/app';
|
|
|
|
const KEY = 'key-ada';
|
|
const ADMIN = { 'x-admin-key': 'admin-dev-key' };
|
|
|
|
describe('zappier-edge operational wiring', () => {
|
|
it('GET /health is public', async () => {
|
|
const { app } = buildApp();
|
|
const res = await request(app).get('/health');
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.role).toBe('zappier-edge');
|
|
});
|
|
|
|
it('proxies timestamp to middleware when ZAPPIER_UPSTREAM is set', async () => {
|
|
process.env.ZAPPIER_UPSTREAM = 'http://upstream.test';
|
|
const orig = globalThis.fetch;
|
|
globalThis.fetch = jest.fn(async (url: string | URL) => {
|
|
expect(String(url)).toContain('/zapier/v1/timestamp');
|
|
return new Response(JSON.stringify({ jobId: 'mw-1', sha256: 'abc' }), {
|
|
status: 202,
|
|
headers: { 'content-type': 'application/json' },
|
|
});
|
|
}) as typeof fetch;
|
|
try {
|
|
const { app } = buildApp();
|
|
const res = await request(app).post('/v1/timestamp').set('x-api-key', KEY).send({ data: 'hello' });
|
|
expect(res.status).toBe(202);
|
|
expect(res.body.jobId).toBe('mw-1');
|
|
expect(res.body.quote.totalCents).toBeGreaterThanOrEqual(0);
|
|
} finally {
|
|
globalThis.fetch = orig;
|
|
delete process.env.ZAPPIER_UPSTREAM;
|
|
}
|
|
});
|
|
|
|
it('customers CS and sales can review a statement', async () => {
|
|
const { app } = buildApp();
|
|
await request(app)
|
|
.post('/admin/api/credits')
|
|
.set(ADMIN)
|
|
.send({ customerId: 'cust_1', cents: 250, reason: 'goodwill', agent: 'cs' });
|
|
const st = await request(app).get('/admin/api/statement/cust_1').set(ADMIN);
|
|
expect(st.status).toBe(200);
|
|
expect(st.body.prepaidCents).toBeGreaterThanOrEqual(250);
|
|
expect(st.body.credits.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('customer service can add prepaid credits', async () => {
|
|
const { app } = buildApp();
|
|
const add = await request(app)
|
|
.post('/admin/api/credits')
|
|
.set(ADMIN)
|
|
.send({ customerId: 'cust_1', cents: 500, reason: 'goodwill', agent: 'cs-anna' });
|
|
expect(add.status).toBe(201);
|
|
expect(add.body.cents).toBe(500);
|
|
const list = await request(app).get('/admin/api/credits?customerId=cust_1').set(ADMIN);
|
|
expect(list.body.credits[0].reason).toBe('goodwill');
|
|
});
|
|
|
|
it('sales quote returns per-customer multiplier', async () => {
|
|
const { app } = buildApp();
|
|
const res = await request(app).get('/admin/api/sales/quote/cust_2').set(ADMIN);
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.tierId).toBe('pro');
|
|
});
|
|
|
|
it('exports issued invoices as QuickBooks IIF', async () => {
|
|
const { app, usage } = buildApp();
|
|
usage.record({
|
|
customerId: 'cust_2',
|
|
endpointId: 'transform',
|
|
cents: 400,
|
|
metadataBytes: 0,
|
|
attachmentBytes: 0,
|
|
timestamp: new Date('2026-07-05T10:00:00Z'),
|
|
});
|
|
await request(app).post('/admin/api/invoices/generate').set(ADMIN).send({ period: '2026-07' });
|
|
await request(app).post('/admin/api/invoices/INV-2026-07-0001/issue').set(ADMIN);
|
|
const iif = await request(app).get('/admin/api/exports/quickbooks.iif?period=2026-07').set(ADMIN);
|
|
expect(iif.status).toBe(200);
|
|
expect(iif.text).toContain('TRNS');
|
|
expect(iif.text).toContain('INV-2026-07-0001');
|
|
const csv = await request(app).get('/admin/api/exports/accounting.csv?period=2026-07').set(ADMIN);
|
|
expect(csv.text).toContain('invoice_id');
|
|
});
|
|
});
|