deckhearth/test/api/user-cards.test.js
Randall Stillwell 1cc2e28423 Migrate Deck Hearth off Vercel/Neon to homelab Dokploy stack.
Replace @vercel/postgres, Blob, and Upstash with lib/sql.js, MinIO object
storage, and CT 102 Redis rate limits. Add Dockerfile for Dokploy deploy,
homelab runbooks, Neon data-copy helper, and point CI smoke/visual at the
homelab URL instead of Vercel previews.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-15 09:32:13 -05:00

82 lines
2.1 KiB
JavaScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
vi.mock('../../lib/sql.js', () => ({ sql: vi.fn() }));
vi.mock('../../lib/permission-middleware.js', () => ({
getUserFromRequest: vi.fn(),
}));
import { sql } from '../../lib/sql.js';
import { getUserFromRequest } from '../../lib/permission-middleware.js';
import handler from '../../pages/api/user-cards.js';
function createRes() {
const res = {
statusCode: 200,
body: null,
status(code) {
res.statusCode = code;
return res;
},
json(data) {
res.body = data;
return res;
},
};
return res;
}
describe('POST /api/user-cards', () => {
beforeEach(() => {
vi.clearAllMocks();
getUserFromRequest.mockResolvedValue({ userId: 1, email: 'a@b.c', role: 'user' });
sql.mockResolvedValue({ rows: [] });
});
it('returns 400 when quantity is not a number', async () => {
const req = {
method: 'POST',
body: { cardId: 42, quantity: 'abc' },
};
const res = createRes();
await handler(req, res);
expect(res.statusCode).toBe(400);
expect(res.body.error).toBe('Quantity must be at least 1');
expect(sql).not.toHaveBeenCalled();
});
it('returns 400 when quantity is zero', async () => {
const req = {
method: 'POST',
body: { cardId: 42, quantity: 0 },
};
const res = createRes();
await handler(req, res);
expect(res.statusCode).toBe(400);
expect(res.body.error).toBe('Quantity must be at least 1');
expect(sql).not.toHaveBeenCalled();
});
it('inserts parsed quantity for a new owned card', async () => {
sql.mockResolvedValueOnce({ rows: [] });
const req = {
method: 'POST',
body: { cardId: 42, quantity: '3', condition: 'LP', is_foil: true },
};
const res = createRes();
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(sql).toHaveBeenCalledTimes(2);
const insertCall = sql.mock.calls[1];
expect(insertCall[2]).toBe(42);
expect(insertCall[3]).toBe(3);
expect(insertCall[4]).toBe('LP');
expect(insertCall[5]).toBe(true);
});
});