168 lines
4.9 KiB
TypeScript
168 lines
4.9 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { isHttpError } from '@sveltejs/kit';
|
|
import { _clearRateLimits } from '$lib/server/v2-rate-limit';
|
|
|
|
vi.mock('$lib/db', () => ({
|
|
prisma: {
|
|
licenseKey: { findFirst: vi.fn() },
|
|
user: { findUnique: vi.fn() },
|
|
subscriptionLevel: { findFirst: vi.fn() }
|
|
}
|
|
}));
|
|
|
|
import { prisma } from '$lib/db';
|
|
import { POST } from './+server';
|
|
|
|
type POSTEvent = Parameters<typeof POST>[0];
|
|
|
|
const mockKeyFindFirst = prisma.licenseKey.findFirst as ReturnType<typeof vi.fn>;
|
|
const mockUserFindUnique = prisma.user.findUnique as ReturnType<typeof vi.fn>;
|
|
const mockLevelFindFirst = prisma.subscriptionLevel.findFirst as ReturnType<typeof vi.fn>;
|
|
|
|
function licenseRequest(body: unknown): Request {
|
|
return new Request('http://localhost/api/v2/license', {
|
|
method: 'POST',
|
|
headers: { 'content-type': 'application/json' },
|
|
body: JSON.stringify(body)
|
|
});
|
|
}
|
|
|
|
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');
|
|
}
|
|
|
|
const storedKey = {
|
|
id: 'key-1',
|
|
key: 'ABCD-EFGH-IJKL-MNOP',
|
|
active: true,
|
|
level: 'Advanced',
|
|
userId: 'user-1'
|
|
};
|
|
|
|
describe('POST /api/v2/license', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
_clearRateLimits();
|
|
});
|
|
|
|
it('returns the subscription_level object for a valid key', async () => {
|
|
mockKeyFindFirst.mockResolvedValue(storedKey);
|
|
mockUserFindUnique.mockResolvedValue({ id: 'user-1', email: 'user@example.com' });
|
|
mockLevelFindFirst.mockResolvedValue({
|
|
id: 2,
|
|
name: 'Advanced',
|
|
description: 'General + Specific'
|
|
});
|
|
|
|
const res = await POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'user@example.com' })
|
|
} as POSTEvent);
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(await res.json()).toEqual({
|
|
key: storedKey.key,
|
|
email_address: 'user@example.com',
|
|
subscription_level: { id: 2, name: 'Advanced', description: 'General + Specific' }
|
|
});
|
|
});
|
|
|
|
it('falls back to a structurally consistent subscription_level for an unknown level name', async () => {
|
|
mockKeyFindFirst.mockResolvedValue({ ...storedKey, level: 'SomeCustomLevel' });
|
|
mockUserFindUnique.mockResolvedValue({ id: 'user-1', email: 'user@example.com' });
|
|
mockLevelFindFirst.mockResolvedValue(null);
|
|
|
|
const res = await POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'user@example.com' })
|
|
} as POSTEvent);
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(await res.json()).toEqual({
|
|
key: storedKey.key,
|
|
email_address: 'user@example.com',
|
|
subscription_level: { id: null, name: 'SomeCustomLevel', description: null }
|
|
});
|
|
});
|
|
|
|
it('rejects a missing license_key', async () => {
|
|
await expectHttpError(
|
|
POST({ request: licenseRequest({ email_address: 'user@example.com' }) } as POSTEvent),
|
|
400,
|
|
'license_key is required'
|
|
);
|
|
});
|
|
|
|
it('rejects a missing email_address', async () => {
|
|
await expectHttpError(
|
|
POST({ request: licenseRequest({ license_key: storedKey.key }) } as POSTEvent),
|
|
400,
|
|
'email_address is required'
|
|
);
|
|
});
|
|
|
|
it('rejects an unknown key', async () => {
|
|
mockKeyFindFirst.mockResolvedValue(null);
|
|
await expectHttpError(
|
|
POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'user@example.com' })
|
|
} as POSTEvent),
|
|
400,
|
|
'license key not found'
|
|
);
|
|
});
|
|
|
|
it('rejects an inactive key', async () => {
|
|
mockKeyFindFirst.mockResolvedValue({ ...storedKey, active: false });
|
|
await expectHttpError(
|
|
POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'user@example.com' })
|
|
} as POSTEvent),
|
|
400,
|
|
'license key is not active'
|
|
);
|
|
});
|
|
|
|
it('rejects a nonexistent user', async () => {
|
|
mockKeyFindFirst.mockResolvedValue(storedKey);
|
|
mockUserFindUnique.mockResolvedValue(null);
|
|
await expectHttpError(
|
|
POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'nobody@example.com' })
|
|
} as POSTEvent),
|
|
400,
|
|
'user does not exist'
|
|
);
|
|
});
|
|
|
|
it('rejects a key owned by a different user', async () => {
|
|
mockKeyFindFirst.mockResolvedValue(storedKey);
|
|
mockUserFindUnique.mockResolvedValue({ id: 'user-2', email: 'other@example.com' });
|
|
await expectHttpError(
|
|
POST({
|
|
request: licenseRequest({ license_key: storedKey.key, email_address: 'other@example.com' })
|
|
} as POSTEvent),
|
|
400,
|
|
'key does not belong to specified user'
|
|
);
|
|
});
|
|
|
|
it('rejects a malformed license key format', async () => {
|
|
await expectHttpError(
|
|
POST({
|
|
request: licenseRequest({ license_key: 'not-a-key', email_address: 'user@example.com' })
|
|
} as POSTEvent),
|
|
400,
|
|
'license key not found'
|
|
);
|
|
expect(mockKeyFindFirst).not.toHaveBeenCalled();
|
|
});
|
|
});
|