288 lines
10 KiB
TypeScript
288 lines
10 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import {
|
|
SPONSOR_STATUSES,
|
|
STATUS_LABELS,
|
|
STATUS_COLORS,
|
|
fetchSponsorTiers,
|
|
createSponsorTier,
|
|
updateSponsorTier,
|
|
deleteSponsorTier,
|
|
fetchSponsors,
|
|
createSponsor,
|
|
updateSponsor,
|
|
deleteSponsor,
|
|
fetchDeliverables,
|
|
fetchAllDeliverables,
|
|
createDeliverable,
|
|
updateDeliverable,
|
|
deleteDeliverable,
|
|
} from './sponsors';
|
|
|
|
// ── Supabase mock builder ────────────────────────────────────────────────────
|
|
|
|
function mockChain(resolvedValue: { data: any; error: any }) {
|
|
const chain: any = {};
|
|
const methods = ['from', 'select', 'insert', 'update', 'delete', 'eq', 'in', 'order', 'single'];
|
|
for (const m of methods) {
|
|
chain[m] = vi.fn(() => chain);
|
|
}
|
|
chain.single = vi.fn(() => Promise.resolve(resolvedValue));
|
|
chain.then = (resolve: any) => resolve(resolvedValue);
|
|
return chain;
|
|
}
|
|
|
|
function mockSupabase(resolvedValue: { data: any; error: any }) {
|
|
const chain = mockChain(resolvedValue);
|
|
return { from: vi.fn(() => chain), _chain: chain } as any;
|
|
}
|
|
|
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
|
|
describe('sponsor constants', () => {
|
|
it('SPONSOR_STATUSES has expected entries', () => {
|
|
expect(SPONSOR_STATUSES).toContain('prospect');
|
|
expect(SPONSOR_STATUSES).toContain('confirmed');
|
|
expect(SPONSOR_STATUSES).toContain('declined');
|
|
expect(SPONSOR_STATUSES).toContain('active');
|
|
expect(SPONSOR_STATUSES.length).toBe(5);
|
|
});
|
|
|
|
it('STATUS_LABELS has a label for every status', () => {
|
|
for (const s of SPONSOR_STATUSES) {
|
|
expect(STATUS_LABELS[s]).toBeDefined();
|
|
expect(typeof STATUS_LABELS[s]).toBe('string');
|
|
}
|
|
});
|
|
|
|
it('STATUS_COLORS has a color for every status', () => {
|
|
for (const s of SPONSOR_STATUSES) {
|
|
expect(STATUS_COLORS[s]).toBeDefined();
|
|
expect(STATUS_COLORS[s]).toMatch(/^#/);
|
|
}
|
|
});
|
|
});
|
|
|
|
// ── Sponsor Tiers ────────────────────────────────────────────────────────────
|
|
|
|
describe('fetchSponsorTiers', () => {
|
|
it('returns tiers for a department', async () => {
|
|
const tiers = [{ id: 't1', name: 'Gold', department_id: 'd1' }];
|
|
const sb = mockSupabase({ data: tiers, error: null });
|
|
expect(await fetchSponsorTiers(sb, 'd1')).toEqual(tiers);
|
|
});
|
|
|
|
it('returns empty array when null', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
expect(await fetchSponsorTiers(sb, 'd1')).toEqual([]);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(fetchSponsorTiers(sb, 'd1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('createSponsorTier', () => {
|
|
it('creates with default color', async () => {
|
|
const tier = { id: 't1', name: 'Silver', amount: 0, color: '#F59E0B' };
|
|
const sb = mockSupabase({ data: tier, error: null });
|
|
expect(await createSponsorTier(sb, 'd1', 'Silver')).toEqual(tier);
|
|
});
|
|
|
|
it('creates with custom amount and color', async () => {
|
|
const tier = { id: 't2', name: 'Platinum', amount: 10000, color: '#00ff00' };
|
|
const sb = mockSupabase({ data: tier, error: null });
|
|
expect(await createSponsorTier(sb, 'd1', 'Platinum', 10000, '#00ff00')).toEqual(tier);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(createSponsorTier(sb, 'd1', 'X')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('updateSponsorTier', () => {
|
|
it('updates and returns tier', async () => {
|
|
const tier = { id: 't1', name: 'Updated' };
|
|
const sb = mockSupabase({ data: tier, error: null });
|
|
expect(await updateSponsorTier(sb, 't1', { name: 'Updated' })).toEqual(tier);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(updateSponsorTier(sb, 't1', { name: 'X' })).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('deleteSponsorTier', () => {
|
|
it('deletes without error', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
await expect(deleteSponsorTier(sb, 't1')).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(deleteSponsorTier(sb, 't1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
// ── Sponsors ─────────────────────────────────────────────────────────────────
|
|
|
|
describe('fetchSponsors', () => {
|
|
it('returns sponsors for a department', async () => {
|
|
const sponsors = [{ id: 's1', name: 'Acme', department_id: 'd1' }];
|
|
const sb = mockSupabase({ data: sponsors, error: null });
|
|
expect(await fetchSponsors(sb, 'd1')).toEqual(sponsors);
|
|
});
|
|
|
|
it('returns empty array when null', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
expect(await fetchSponsors(sb, 'd1')).toEqual([]);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(fetchSponsors(sb, 'd1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('createSponsor', () => {
|
|
it('creates with minimal params', async () => {
|
|
const sponsor = { id: 's1', name: 'Acme', status: 'prospect', amount: 0 };
|
|
const sb = mockSupabase({ data: sponsor, error: null });
|
|
expect(await createSponsor(sb, 'd1', { name: 'Acme' })).toEqual(sponsor);
|
|
});
|
|
|
|
it('creates with all params', async () => {
|
|
const sponsor = { id: 's2', name: 'BigCo', status: 'confirmed', amount: 5000 };
|
|
const sb = mockSupabase({ data: sponsor, error: null });
|
|
expect(await createSponsor(sb, 'd1', {
|
|
name: 'BigCo',
|
|
tier_id: 't1',
|
|
contact_name: 'John',
|
|
contact_email: 'john@bigco.com',
|
|
contact_phone: '+1234',
|
|
website: 'https://bigco.com',
|
|
logo_url: 'https://bigco.com/logo.png',
|
|
status: 'confirmed',
|
|
amount: 5000,
|
|
notes: 'VIP sponsor',
|
|
})).toEqual(sponsor);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(createSponsor(sb, 'd1', { name: 'X' })).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('updateSponsor', () => {
|
|
it('updates and returns sponsor', async () => {
|
|
const sponsor = { id: 's1', name: 'Updated' };
|
|
const sb = mockSupabase({ data: sponsor, error: null });
|
|
expect(await updateSponsor(sb, 's1', { name: 'Updated' })).toEqual(sponsor);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(updateSponsor(sb, 's1', { name: 'X' })).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('deleteSponsor', () => {
|
|
it('deletes without error', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
await expect(deleteSponsor(sb, 's1')).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(deleteSponsor(sb, 's1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
// ── Deliverables ─────────────────────────────────────────────────────────────
|
|
|
|
describe('fetchDeliverables', () => {
|
|
it('returns deliverables for a sponsor', async () => {
|
|
const delivs = [{ id: 'dl1', description: 'Logo placement', sponsor_id: 's1' }];
|
|
const sb = mockSupabase({ data: delivs, error: null });
|
|
expect(await fetchDeliverables(sb, 's1')).toEqual(delivs);
|
|
});
|
|
|
|
it('returns empty array when null', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
expect(await fetchDeliverables(sb, 's1')).toEqual([]);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(fetchDeliverables(sb, 's1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('fetchAllDeliverables', () => {
|
|
it('returns empty array for empty sponsor list', async () => {
|
|
const sb = mockSupabase({ data: [], error: null });
|
|
expect(await fetchAllDeliverables(sb, [])).toEqual([]);
|
|
});
|
|
|
|
it('returns deliverables for multiple sponsors', async () => {
|
|
const delivs = [
|
|
{ id: 'dl1', sponsor_id: 's1' },
|
|
{ id: 'dl2', sponsor_id: 's2' },
|
|
];
|
|
const sb = mockSupabase({ data: delivs, error: null });
|
|
expect(await fetchAllDeliverables(sb, ['s1', 's2'])).toEqual(delivs);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(fetchAllDeliverables(sb, ['s1'])).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('createDeliverable', () => {
|
|
it('creates with description only', async () => {
|
|
const deliv = { id: 'dl1', description: 'Banner', sponsor_id: 's1' };
|
|
const sb = mockSupabase({ data: deliv, error: null });
|
|
expect(await createDeliverable(sb, 's1', 'Banner')).toEqual(deliv);
|
|
});
|
|
|
|
it('creates with due date', async () => {
|
|
const deliv = { id: 'dl2', description: 'Video', sponsor_id: 's1', due_date: '2025-06-01' };
|
|
const sb = mockSupabase({ data: deliv, error: null });
|
|
expect(await createDeliverable(sb, 's1', 'Video', '2025-06-01')).toEqual(deliv);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(createDeliverable(sb, 's1', 'X')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('updateDeliverable', () => {
|
|
it('updates and returns deliverable', async () => {
|
|
const deliv = { id: 'dl1', description: 'Updated' };
|
|
const sb = mockSupabase({ data: deliv, error: null });
|
|
expect(await updateDeliverable(sb, 'dl1', { description: 'Updated' })).toEqual(deliv);
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(updateDeliverable(sb, 'dl1', { description: 'X' })).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|
|
|
|
describe('deleteDeliverable', () => {
|
|
it('deletes without error', async () => {
|
|
const sb = mockSupabase({ data: null, error: null });
|
|
await expect(deleteDeliverable(sb, 'dl1')).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('throws on error', async () => {
|
|
const sb = mockSupabase({ data: null, error: { message: 'fail' } });
|
|
await expect(deleteDeliverable(sb, 'dl1')).rejects.toEqual({ message: 'fail' });
|
|
});
|
|
});
|