Initial import of zappier-edge from zapier monorepo
This commit is contained in:
commit
dd605a746c
125 changed files with 20148 additions and 0 deletions
156
tests/admin.test.ts
Normal file
156
tests/admin.test.ts
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import request from 'supertest';
|
||||
import { buildApp } from '../src/app';
|
||||
|
||||
const ADMIN = { 'x-admin-key': 'admin-dev-key' };
|
||||
const KEY = 'key-ada';
|
||||
|
||||
describe('admin API', () => {
|
||||
it('rejects calls without an admin key', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app).get('/admin/api/pricing');
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
|
||||
it('returns the current pricing', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app).get('/admin/api/pricing').set(ADMIN);
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.rateCard.endpoints.status).toEqual({ kind: 'free' });
|
||||
expect(res.body.tiers.map((t: { id: string }) => t.id)).toEqual(['free', 'pro', 'business']);
|
||||
});
|
||||
|
||||
it('rejects an invalid price rule with 400', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.put('/admin/api/endpoints/transform')
|
||||
.set(ADMIN)
|
||||
.send({ kind: 'sometimes' });
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it('reprices an endpoint live, without restart', async () => {
|
||||
const { app } = buildApp();
|
||||
await request(app)
|
||||
.put('/admin/api/endpoints/transform')
|
||||
.set(ADMIN)
|
||||
.send({ kind: 'fixed', fixedCents: 10 });
|
||||
const res = await request(app)
|
||||
.post('/v1/transform')
|
||||
.set('x-api-key', KEY)
|
||||
.send({ text: 'hi' });
|
||||
expect(res.body.quote.totalCents).toBe(10); // was 4
|
||||
});
|
||||
|
||||
it('creates a customer type live and prices calls for it', async () => {
|
||||
const { app } = buildApp();
|
||||
await request(app)
|
||||
.put('/admin/api/tiers/edu')
|
||||
.set(ADMIN)
|
||||
.send({ id: 'edu', name: 'Education', multiplier: 0.5, monthlyCreditCents: 500 });
|
||||
const created = await request(app)
|
||||
.post('/admin/api/customers')
|
||||
.set(ADMIN)
|
||||
.send({ name: 'School', tierId: 'edu' });
|
||||
expect(created.status).toBe(201);
|
||||
expect(created.body.apiKey).toMatch(/^key-/);
|
||||
const res = await request(app)
|
||||
.post('/v1/transform')
|
||||
.set('x-api-key', created.body.apiKey)
|
||||
.send({ text: 'hi' });
|
||||
expect(res.body.quote.totalCents).toBe(2); // list 4 x 0.5
|
||||
});
|
||||
|
||||
it('sets a per-customer multiplier override live', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.put('/admin/api/customers/cust_1')
|
||||
.set(ADMIN)
|
||||
.send({ multiplierOverride: 0.5 });
|
||||
expect(res.status).toBe(200);
|
||||
const call = await request(app)
|
||||
.post('/v1/transform')
|
||||
.set('x-api-key', KEY)
|
||||
.send({ text: 'hi' });
|
||||
expect(call.body.quote.totalCents).toBe(2); // was 4
|
||||
});
|
||||
|
||||
it('masks API keys in the customer list and 404s unknown customers', async () => {
|
||||
const { app } = buildApp();
|
||||
const list = await request(app).get('/admin/api/customers').set(ADMIN);
|
||||
expect(list.status).toBe(200);
|
||||
expect(JSON.stringify(list.body)).not.toContain('key-ada');
|
||||
const missing = await request(app)
|
||||
.put('/admin/api/customers/cust_nope')
|
||||
.set(ADMIN)
|
||||
.send({ tierId: 'pro' });
|
||||
expect(missing.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('admin login', () => {
|
||||
it('logs in the demo account and accepts the issued token', async () => {
|
||||
const { app } = buildApp();
|
||||
const login = await request(app)
|
||||
.post('/admin/api/login')
|
||||
.send({ username: 'demo', password: '$$$Adm1n###' });
|
||||
expect(login.status).toBe(200);
|
||||
expect(login.body.token).toMatch(/^[a-f0-9]{48}$/);
|
||||
const res = await request(app)
|
||||
.get('/admin/api/pricing')
|
||||
.set('authorization', `Bearer ${login.body.token}`);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it('logs in the primary admin account with the admin key as password', async () => {
|
||||
const { app } = buildApp();
|
||||
const login = await request(app)
|
||||
.post('/admin/api/login')
|
||||
.send({ username: 'admin', password: 'admin-dev-key' });
|
||||
expect(login.status).toBe(200);
|
||||
});
|
||||
|
||||
it('rejects bad credentials with 401 and issues no token', async () => {
|
||||
const { app } = buildApp();
|
||||
const login = await request(app)
|
||||
.post('/admin/api/login')
|
||||
.send({ username: 'demo', password: 'wrong' });
|
||||
expect(login.status).toBe(401);
|
||||
expect(login.body.token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('still accepts the legacy x-admin-key header', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app).get('/admin/api/pricing').set(ADMIN);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it('rejects unknown bearer tokens', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.get('/admin/api/pricing')
|
||||
.set('authorization', 'Bearer deadbeef');
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
|
||||
it('sets billingType and email on a customer', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.put('/admin/api/customers/cust_1')
|
||||
.set(ADMIN)
|
||||
.send({ billingType: 'purchase_order', email: 'ada@example.com' });
|
||||
expect(res.status).toBe(200);
|
||||
const list = await request(app).get('/admin/api/customers').set(ADMIN);
|
||||
const ada = list.body.customers.find((c: { id: string }) => c.id === 'cust_1');
|
||||
expect(ada.billingType).toBe('purchase_order');
|
||||
expect(ada.email).toBe('ada@example.com');
|
||||
});
|
||||
|
||||
it('rejects an invalid billingType with 400', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.put('/admin/api/customers/cust_1')
|
||||
.set(ADMIN)
|
||||
.send({ billingType: 'carrier-pigeon' });
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue