Build API v2
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { isHttpError } from '@sveltejs/kit';
|
||||
|
||||
vi.mock('$lib/db', () => ({
|
||||
prisma: {
|
||||
proclamation: { findMany: vi.fn() },
|
||||
licenseKey: { findUnique: vi.fn() },
|
||||
user: { findUnique: vi.fn() },
|
||||
userProclamations: { findMany: vi.fn() },
|
||||
colorPalette: { findMany: vi.fn() }
|
||||
}
|
||||
}));
|
||||
|
||||
import { prisma } from '$lib/db';
|
||||
import { GET } from './+server';
|
||||
|
||||
type GETEvent = Parameters<typeof GET>[0];
|
||||
|
||||
const mockProclamationFindMany = prisma.proclamation.findMany as ReturnType<typeof vi.fn>;
|
||||
const mockLicenseKey = prisma.licenseKey.findUnique as ReturnType<typeof vi.fn>;
|
||||
const mockUser = prisma.user.findUnique as ReturnType<typeof vi.fn>;
|
||||
const mockUserProclamations = prisma.userProclamations.findMany as ReturnType<typeof vi.fn>;
|
||||
const mockColorPalette = prisma.colorPalette.findMany as ReturnType<typeof vi.fn>;
|
||||
|
||||
const palettes = [
|
||||
{
|
||||
solfeggioFrequencyId: 5,
|
||||
colors: ['#32CD32', '#3CB371', '#90EE90', '#98FB98', '#ADFFA9', '#C8FFD2', '#F0FFF0']
|
||||
},
|
||||
{
|
||||
solfeggioFrequencyId: 7,
|
||||
colors: ['#00BFFF', '#1E90FF', '#4169E1', '#6495ED', '#87CEEB', '#ADD8E6', '#F0F8FF']
|
||||
}
|
||||
];
|
||||
|
||||
const peaceProclamation = {
|
||||
id: 'b40fdcb9-703c-420e-af32-a081964c6f08',
|
||||
name: 'Peace & Relaxation',
|
||||
content: '<p>The text content</p>',
|
||||
categoryId: 5,
|
||||
subscriptionLevelId: 1,
|
||||
solfeggioFrequencyId: 5,
|
||||
solfeggioFrequency: { id: 5, name: 'Solar Plexus', value: 528 }
|
||||
};
|
||||
|
||||
const crown936 = {
|
||||
id: '936-hz-proclamation',
|
||||
name: 'Crown 936',
|
||||
content: '<p>no canonical id</p>',
|
||||
categoryId: 4,
|
||||
subscriptionLevelId: 1,
|
||||
solfeggioFrequencyId: 1,
|
||||
solfeggioFrequency: { id: 1, name: 'Crown', value: 936 }
|
||||
};
|
||||
|
||||
function getRequest(headers: Record<string, string> = {}): Request {
|
||||
return new Request('http://localhost/api/v2/proclamations', { headers });
|
||||
}
|
||||
|
||||
async function expectHttpError(promise: unknown, status: number, message: string) {
|
||||
try {
|
||||
await promise;
|
||||
} catch (e) {
|
||||
expect(isHttpError(e)).toBe(true);
|
||||
const err = e as { status: number; body: { message: string } };
|
||||
expect(err.status).toBe(status);
|
||||
expect(err.body.message).toBe(message);
|
||||
return;
|
||||
}
|
||||
throw new Error('expected handler to throw an HttpError');
|
||||
}
|
||||
|
||||
describe('GET /api/v2/proclamations', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns full proclamation records with canonical ids and embedded palettes', async () => {
|
||||
mockProclamationFindMany.mockResolvedValue([peaceProclamation]);
|
||||
mockColorPalette.mockResolvedValue(palettes);
|
||||
|
||||
const res = await GET({ request: getRequest() } as GETEvent);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual([
|
||||
{
|
||||
id: peaceProclamation.id,
|
||||
name: peaceProclamation.name,
|
||||
content: peaceProclamation.content,
|
||||
categoryId: 5,
|
||||
solfeggioFrequencyId: 5,
|
||||
subscriptionLevelId: 1,
|
||||
colorPalette: palettes[0].colors
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('drops proclamations whose frequency has no canonical id (936 Hz)', async () => {
|
||||
mockProclamationFindMany.mockResolvedValue([peaceProclamation, crown936]);
|
||||
mockColorPalette.mockResolvedValue(palettes);
|
||||
|
||||
const res = await GET({ request: getRequest() } as GETEvent);
|
||||
const body = (await res.json()) as { id: string }[];
|
||||
|
||||
expect(body).toHaveLength(1);
|
||||
expect(body[0].id).toBe(peaceProclamation.id);
|
||||
});
|
||||
|
||||
it('returns the entitled proclamations as full records when headers are supplied', async () => {
|
||||
mockLicenseKey.mockResolvedValue({ id: 'key-1', key: 'ABCD-EFGH-IJKL-MNOP' });
|
||||
mockUser.mockResolvedValue({
|
||||
id: 'user-1',
|
||||
email: 'user@example.com',
|
||||
licenseKeys: [{ id: 'key-1', key: 'ABCD-EFGH-IJKL-MNOP' }]
|
||||
});
|
||||
mockUserProclamations.mockResolvedValue([
|
||||
{ userId: 'user-1', proclamationId: peaceProclamation.id, proclamation: peaceProclamation }
|
||||
]);
|
||||
mockColorPalette.mockResolvedValue(palettes);
|
||||
|
||||
const res = await GET({
|
||||
request: getRequest({
|
||||
'x-license-key': 'ABCD-EFGH-IJKL-MNOP',
|
||||
'x-email': 'user@example.com'
|
||||
})
|
||||
} as GETEvent);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as { id: string }[];
|
||||
expect(body).toHaveLength(1);
|
||||
expect(body[0].id).toBe(peaceProclamation.id);
|
||||
expect(mockUserProclamations).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ where: { userId: 'user-1' } })
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects when only one entitlement header is supplied', async () => {
|
||||
await expectHttpError(
|
||||
GET({ request: getRequest({ 'x-license-key': 'ABCD-EFGH-IJKL-MNOP' }) } as GETEvent),
|
||||
400,
|
||||
'not-authorized'
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects an unknown license key', async () => {
|
||||
mockLicenseKey.mockResolvedValue(null);
|
||||
await expectHttpError(
|
||||
GET({
|
||||
request: getRequest({
|
||||
'x-license-key': 'UNKNOWN-KEY',
|
||||
'x-email': 'user@example.com'
|
||||
})
|
||||
} as GETEvent),
|
||||
400,
|
||||
'not-authorized'
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects a key that does not belong to the user', async () => {
|
||||
mockLicenseKey.mockResolvedValue({ id: 'key-2', key: 'OTHER-KEY' });
|
||||
mockUser.mockResolvedValue({
|
||||
id: 'user-1',
|
||||
email: 'user@example.com',
|
||||
licenseKeys: [{ id: 'key-1', key: 'ABCD-EFGH-IJKL-MNOP' }]
|
||||
});
|
||||
await expectHttpError(
|
||||
GET({
|
||||
request: getRequest({
|
||||
'x-license-key': 'OTHER-KEY',
|
||||
'x-email': 'user@example.com'
|
||||
})
|
||||
} as GETEvent),
|
||||
400,
|
||||
"this key doesn't appear to belong to you"
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user