215 lines
7.8 KiB
TypeScript
215 lines
7.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { isHttpError } from '@sveltejs/kit';
|
|
import { createLocals, mockUser, createFormRequest } from '$lib/test-utils';
|
|
|
|
const { sendMail } = vi.hoisted(() => ({
|
|
sendMail: vi.fn()
|
|
}));
|
|
|
|
vi.mock('$lib/server/resend', () => ({ sendMail }));
|
|
|
|
vi.mock('$lib/db', () => ({
|
|
prisma: {
|
|
user: { findUnique: vi.fn() },
|
|
profile: { findFirst: vi.fn() },
|
|
licenseKey: { findMany: vi.fn(), findUnique: vi.fn(), create: vi.fn(), delete: vi.fn() }
|
|
}
|
|
}));
|
|
|
|
import { prisma } from '$lib/db';
|
|
import { load, actions } from './+page.server';
|
|
|
|
const mockFindUnique = prisma.user.findUnique as ReturnType<typeof vi.fn>;
|
|
const mockProfileFindFirst = prisma.profile.findFirst as ReturnType<typeof vi.fn>;
|
|
const mockLicenseKeyCreate = prisma.licenseKey.create as ReturnType<typeof vi.fn>;
|
|
const mockLicenseKeyFindUnique = prisma.licenseKey.findUnique as ReturnType<typeof vi.fn>;
|
|
const mockLicenseKeyDelete = prisma.licenseKey.delete as ReturnType<typeof vi.fn>;
|
|
|
|
describe('admin license-keys createKey action', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('returns records via load', async () => {
|
|
const records = [{ id: 'k1', key: 'AAAA-BBBB-CCCC-DDDD' }];
|
|
(prisma.licenseKey.findMany as ReturnType<typeof vi.fn>).mockResolvedValue(records);
|
|
|
|
const result = await load({} as any);
|
|
|
|
expect(prisma.licenseKey.findMany).toHaveBeenCalledWith({
|
|
include: { user: true },
|
|
orderBy: { key: 'asc' }
|
|
});
|
|
expect(result).toEqual({ records });
|
|
});
|
|
|
|
it('rejects unauthenticated requests', async () => {
|
|
const locals = createLocals();
|
|
const req = createFormRequest({ email: 'jane@example.com' });
|
|
|
|
const err = await actions.createKey({ request: req, locals } as any).catch((e) => e);
|
|
expect(isHttpError(err, 403)).toBe(true);
|
|
});
|
|
|
|
it('returns error when email is missing', async () => {
|
|
const locals = createLocals(mockUser({ roleId: 3 }) as any);
|
|
const req = createFormRequest({});
|
|
|
|
const result = await actions.createKey({ request: req, locals } as any);
|
|
expect(result).toEqual({ success: false, action: 'createKey', error: 'Email is required' });
|
|
});
|
|
|
|
it('creates a key with only an email when no user exists yet', async () => {
|
|
mockFindUnique.mockResolvedValue(null);
|
|
mockProfileFindFirst.mockResolvedValue(null);
|
|
mockLicenseKeyCreate.mockResolvedValue({});
|
|
sendMail.mockResolvedValue({ id: 'email-1' });
|
|
|
|
const locals = createLocals(mockUser({ roleId: 3 }) as any);
|
|
const req = createFormRequest({ email: 'nobody@example.com' });
|
|
|
|
const result = await actions.createKey({ request: req, locals } as any);
|
|
|
|
expect(result).toEqual({ success: true, action: 'createKey' });
|
|
expect(mockLicenseKeyCreate).toHaveBeenCalledOnce();
|
|
|
|
const createCall = mockLicenseKeyCreate.mock.calls[0][0];
|
|
expect(createCall.data.active).toBe(true);
|
|
expect(createCall.data.userId).toBeUndefined();
|
|
expect(createCall.data.email).toBe('nobody@example.com');
|
|
|
|
expect(sendMail).toHaveBeenCalledOnce();
|
|
const mailCall = sendMail.mock.calls[0][0];
|
|
expect(mailCall.to).toBe('nobody@example.com');
|
|
expect(mailCall.templateId).toBe('license-key-delivery');
|
|
expect(mailCall.data.firstName).toBe('Valued Customer');
|
|
});
|
|
|
|
it('creates a license key and sends email with license_key variable', async () => {
|
|
const user = mockUser({ roleId: 3 });
|
|
const profile = { firstName: 'Jane' };
|
|
|
|
mockFindUnique.mockResolvedValue(user);
|
|
mockProfileFindFirst.mockResolvedValue(profile);
|
|
mockLicenseKeyCreate.mockResolvedValue({});
|
|
sendMail.mockResolvedValue({ id: 'email-1' });
|
|
|
|
const locals = createLocals(user as any);
|
|
const req = createFormRequest({ email: user.email });
|
|
|
|
const result = await actions.createKey({ request: req, locals } as any);
|
|
|
|
expect(result).toEqual({ success: true, action: 'createKey' });
|
|
expect(mockLicenseKeyCreate).toHaveBeenCalledOnce();
|
|
|
|
const createCall = mockLicenseKeyCreate.mock.calls[0][0];
|
|
expect(createCall.data.key).toMatch(/^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/);
|
|
expect(createCall.data.active).toBe(true);
|
|
expect(createCall.data.userId).toBe('user-1');
|
|
|
|
expect(sendMail).toHaveBeenCalledOnce();
|
|
const mailCall = sendMail.mock.calls[0][0];
|
|
expect(mailCall.to).toBe(user.email);
|
|
expect(mailCall.templateId).toBe('license-key-delivery');
|
|
expect(mailCall.data.license_key).toBeDefined();
|
|
expect(mailCall.data.license_key).toBe(createCall.data.key);
|
|
expect(mailCall.data.firstName).toBe('Jane');
|
|
});
|
|
|
|
it('sends email with license_key even when profile is missing', async () => {
|
|
const user = mockUser({ roleId: 3 });
|
|
|
|
mockFindUnique.mockResolvedValue(user);
|
|
mockProfileFindFirst.mockResolvedValue(null);
|
|
mockLicenseKeyCreate.mockResolvedValue({});
|
|
sendMail.mockResolvedValue({ id: 'email-1' });
|
|
|
|
const locals = createLocals(user as any);
|
|
const req = createFormRequest({ email: user.email });
|
|
|
|
await actions.createKey({ request: req, locals } as any);
|
|
|
|
const mailCall = sendMail.mock.calls[0][0];
|
|
expect(mailCall.templateId).toBe('license-key-delivery');
|
|
expect(mailCall.data.license_key).toBeDefined();
|
|
expect(mailCall.data.firstName).toBe('Jane Doe');
|
|
});
|
|
|
|
it('still returns success when email sending fails', async () => {
|
|
const user = mockUser({ roleId: 3 });
|
|
|
|
mockFindUnique.mockResolvedValue(user);
|
|
mockProfileFindFirst.mockResolvedValue({ firstName: 'Jane' });
|
|
mockLicenseKeyCreate.mockResolvedValue({});
|
|
sendMail.mockRejectedValue(new Error('Resend API down'));
|
|
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
const locals = createLocals(user as any);
|
|
const req = createFormRequest({ email: user.email });
|
|
|
|
const result = await actions.createKey({ request: req, locals } as any);
|
|
expect(result).toEqual({ success: true, action: 'createKey' });
|
|
expect(mockLicenseKeyCreate).toHaveBeenCalledOnce();
|
|
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('admin license-keys replace action', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('rejects unauthenticated requests', async () => {
|
|
const locals = createLocals();
|
|
const req = createFormRequest({ id: 'k1' });
|
|
|
|
const err = await actions.replace({ request: req, locals } as any).catch((e) => e);
|
|
expect(isHttpError(err, 403)).toBe(true);
|
|
});
|
|
|
|
it('returns error when id is missing', async () => {
|
|
const locals = createLocals(mockUser({ roleId: 3 }) as any);
|
|
const req = createFormRequest({});
|
|
|
|
const result = await actions.replace({ request: req, locals } as any);
|
|
expect(result).toEqual({ success: false, action: 'replace', error: 'Missing key id' });
|
|
});
|
|
|
|
it('returns error when the key does not exist', async () => {
|
|
mockLicenseKeyFindUnique.mockResolvedValue(null);
|
|
|
|
const locals = createLocals(mockUser({ roleId: 3 }) as any);
|
|
const req = createFormRequest({ id: 'missing' });
|
|
|
|
const result = await actions.replace({ request: req, locals } as any);
|
|
expect(result).toEqual({ success: false, action: 'replace', error: 'License key not found' });
|
|
});
|
|
|
|
it('deletes the old key and creates a replacement preserving the owner', async () => {
|
|
mockLicenseKeyFindUnique.mockResolvedValue({
|
|
id: 'k1',
|
|
key: 'AAAA-BBBB-CCCC-DDDD',
|
|
userId: 'user-1',
|
|
email: null
|
|
});
|
|
mockLicenseKeyDelete.mockResolvedValue({});
|
|
mockLicenseKeyCreate.mockResolvedValue({});
|
|
|
|
const locals = createLocals(mockUser({ roleId: 3 }) as any);
|
|
const req = createFormRequest({ id: 'k1' });
|
|
|
|
const result = await actions.replace({ request: req, locals } as any);
|
|
|
|
expect(result).toEqual({ success: true, action: 'replace' });
|
|
expect(mockLicenseKeyDelete).toHaveBeenCalledWith({ where: { id: 'k1' } });
|
|
expect(mockLicenseKeyCreate).toHaveBeenCalledOnce();
|
|
const createCall = mockLicenseKeyCreate.mock.calls[0][0];
|
|
expect(createCall.data.key).toMatch(/^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/);
|
|
expect(createCall.data.active).toBe(true);
|
|
expect(createCall.data.userId).toBe('user-1');
|
|
expect(createCall.data.email).toBeNull();
|
|
});
|
|
});
|