test(platform-service): add referrals route-level tests
This commit is contained in:
parent
783b9792df
commit
dc0cf6d8b4
191
services/platform-service/src/modules/referrals/routes.test.ts
Normal file
191
services/platform-service/src/modules/referrals/routes.test.ts
Normal file
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Route-level tests for referrals module — Fastify inject.
|
||||
*/
|
||||
|
||||
import Fastify from 'fastify';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const repoMock = {
|
||||
listAll: vi.fn(),
|
||||
countReferrals: vi.fn(),
|
||||
getByReferrer: vi.fn(),
|
||||
getByReferredEmail: vi.fn(),
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
};
|
||||
|
||||
const webhookMock = {
|
||||
dispatchReferralStatusChanged: vi.fn(),
|
||||
};
|
||||
|
||||
vi.mock('./repository.js', () => repoMock);
|
||||
vi.mock('../../lib/webhooks.js', () => webhookMock);
|
||||
vi.mock('../../lib/request-context.js', () => ({
|
||||
getRequestProductId: () => 'lysnrai',
|
||||
}));
|
||||
|
||||
const baseReferral = {
|
||||
id: 'ref_1',
|
||||
productId: 'lysnrai',
|
||||
referrerId: 'user_1',
|
||||
referrerEmail: 'referrer@example.com',
|
||||
referredUserId: null,
|
||||
referredEmail: 'friend@example.com',
|
||||
status: 'pending',
|
||||
referrerRewardTokens: 1000,
|
||||
referredRewardTokens: 500,
|
||||
referrerRewarded: false,
|
||||
referredRewarded: false,
|
||||
createdAt: '2026-02-16T00:00:00Z',
|
||||
completedAt: null,
|
||||
};
|
||||
|
||||
describe('referralRoutes', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('GET /referrals lists referrals', async () => {
|
||||
repoMock.listAll.mockResolvedValue([baseReferral]);
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({ method: 'GET', url: '/api/referrals?limit=10&offset=0' });
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
const data = JSON.parse(res.body);
|
||||
expect(data.referrals).toHaveLength(1);
|
||||
expect(data.count).toBe(1);
|
||||
});
|
||||
|
||||
it('GET /referrals/stats returns counters', async () => {
|
||||
repoMock.countReferrals.mockResolvedValue({ total: 10, completed: 4, rewarded: 2 });
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({ method: 'GET', url: '/api/referrals/stats' });
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
const data = JSON.parse(res.body);
|
||||
expect(data.total).toBe(10);
|
||||
});
|
||||
|
||||
it('GET /referrals/by-email/:email returns 404 when missing', async () => {
|
||||
repoMock.getByReferredEmail.mockResolvedValue(null);
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({ method: 'GET', url: '/api/referrals/by-email/missing@example.com' });
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
});
|
||||
|
||||
it('POST /referrals creates referral when email not existing', async () => {
|
||||
repoMock.getByReferredEmail.mockResolvedValue(null);
|
||||
repoMock.create.mockResolvedValue(baseReferral);
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/referrals',
|
||||
payload: {
|
||||
referrerId: 'user_1',
|
||||
referrerEmail: 'referrer@example.com',
|
||||
referredEmail: 'friend@example.com',
|
||||
referrerRewardTokens: 1000,
|
||||
referredRewardTokens: 500,
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(201);
|
||||
const data = JSON.parse(res.body);
|
||||
expect(data.id).toBe('ref_1');
|
||||
});
|
||||
|
||||
it('POST /referrals returns 400 for duplicate referred email', async () => {
|
||||
repoMock.getByReferredEmail.mockResolvedValue(baseReferral);
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/referrals',
|
||||
payload: {
|
||||
referrerId: 'user_1',
|
||||
referrerEmail: 'referrer@example.com',
|
||||
referredEmail: 'friend@example.com',
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it('PUT /referrals/:id requires referrerId query param', async () => {
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/referrals/ref_1',
|
||||
payload: { status: 'signed_up' },
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it('PUT /referrals/:id updates referral and dispatches webhook', async () => {
|
||||
repoMock.update.mockResolvedValue({
|
||||
...baseReferral,
|
||||
status: 'signed_up',
|
||||
referredUserId: 'user_2',
|
||||
completedAt: '2026-02-16T01:00:00Z',
|
||||
});
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/referrals/ref_1?referrerId=user_1',
|
||||
payload: { status: 'signed_up', referredUserId: 'user_2' },
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
const data = JSON.parse(res.body);
|
||||
expect(data.status).toBe('signed_up');
|
||||
expect(webhookMock.dispatchReferralStatusChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('PUT /referrals/:id returns 404 when update returns null', async () => {
|
||||
repoMock.update.mockResolvedValue(null);
|
||||
|
||||
const { referralRoutes } = await import('./routes.js');
|
||||
const app = Fastify({ logger: false });
|
||||
await app.register(referralRoutes, { prefix: '/api' });
|
||||
|
||||
const res = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/referrals/ref_1?referrerId=user_1',
|
||||
payload: { status: 'signed_up' },
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user