Files
shorty/qr-api/src/db.test.ts

182 lines
5.7 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import fs from 'fs';
import path from 'path';
import os from 'os';
import Database from 'better-sqlite3';
import {
initDb,
createProject,
listProjects,
getProject,
updateProject,
deleteProject,
listFolders,
createFolder,
getFolder,
updateFolder,
deleteFolder,
} from './db.js';
const testEnv = {
DB_PATH: ':memory:',
UPLOADS_PATH: '/tmp',
PORT: 8080,
KUTT_BASE_URL: 'http://kutt:3000',
SHORT_DOMAIN: 'https://mifi.me',
};
describe('db', () => {
let db: Database.Database;
beforeEach(() => {
db = initDb(testEnv as Parameters<typeof initDb>[0]);
});
it('creates and gets a project', () => {
const p = createProject(db, {
name: 'Test',
originalUrl: 'https://example.com',
});
expect(p.id).toBeDefined();
expect(p.name).toBe('Test');
expect(p.originalUrl).toBe('https://example.com');
const got = getProject(db, p.id);
expect(got?.name).toBe('Test');
});
it('lists projects by updatedAt desc', async () => {
createProject(db, { name: 'A' });
await new Promise((r) => setTimeout(r, 2));
createProject(db, { name: 'B' });
const list = listProjects(db);
expect(list.length).toBe(2);
expect(list[0].name).toBe('B');
expect(list[1].name).toBe('A');
});
it('updates a project', () => {
const p = createProject(db, { name: 'Old' });
const updated = updateProject(db, p.id, {
name: 'New',
recipeJson: '{"x":1}',
});
expect(updated?.name).toBe('New');
expect(updated?.recipeJson).toBe('{"x":1}');
});
it('deletes a project', () => {
const p = createProject(db, { name: 'Del' });
const deleted = deleteProject(db, p.id);
expect(deleted).toBe(true);
expect(getProject(db, p.id)).toBeNull();
});
it('returns null for missing project', () => {
expect(
getProject(db, '00000000-0000-0000-0000-000000000000'),
).toBeNull();
expect(
updateProject(db, '00000000-0000-0000-0000-000000000000', {
name: 'X',
}),
).toBeNull();
expect(deleteProject(db, '00000000-0000-0000-0000-000000000000')).toBe(
false,
);
});
it('updateProject preserves shortUrl, logoFilename, folderId when not provided', () => {
const p = createProject(db, {
name: 'P',
shortUrl: 'https://mifi.me/x',
logoFilename: 'logo.png',
folderId: null,
});
const f = createFolder(db, { name: 'F' });
updateProject(db, p.id, { folderId: f.id });
const updated = getProject(db, p.id)!;
expect(updated.shortUrl).toBe('https://mifi.me/x');
expect(updated.logoFilename).toBe('logo.png');
expect(updated.folderId).toBe(f.id);
});
it('updateProject with explicit logoFilename', () => {
const p = createProject(db, { name: 'P', logoFilename: 'old.png' });
updateProject(db, p.id, { logoFilename: null });
expect(getProject(db, p.id)!.logoFilename).toBeNull();
updateProject(db, p.id, { logoFilename: 'new.png' });
expect(getProject(db, p.id)!.logoFilename).toBe('new.png');
});
it('listFolders returns empty then folders in sort order', () => {
expect(listFolders(db)).toEqual([]);
createFolder(db, { name: 'B', sortOrder: 1 });
createFolder(db, { name: 'A', sortOrder: 0 });
const list = listFolders(db);
expect(list.length).toBe(2);
expect(list[0].name).toBe('A');
expect(list[1].name).toBe('B');
});
it('createFolder defaults name and sortOrder', () => {
const f = createFolder(db, {});
expect(f.id).toBeDefined();
expect(f.name).toBe('Folder');
expect(f.sortOrder).toBe(0);
});
it('getFolder returns folder or null', () => {
const f = createFolder(db, { name: 'X' });
expect(getFolder(db, f.id)?.name).toBe('X');
expect(
getFolder(db, '00000000-0000-0000-0000-000000000000'),
).toBeNull();
});
it('updateFolder and deleteFolder', () => {
const f = createFolder(db, { name: 'Old' });
const updated = updateFolder(db, f.id, { name: 'New', sortOrder: 5 });
expect(updated?.name).toBe('New');
expect(updated?.sortOrder).toBe(5);
expect(
updateFolder(db, '00000000-0000-0000-0000-000000000000', {
name: 'X',
}),
).toBeNull();
const deleted = deleteFolder(db, f.id);
expect(deleted).toBe(true);
expect(getFolder(db, f.id)).toBeNull();
expect(deleteFolder(db, '00000000-0000-0000-0000-000000000000')).toBe(
false,
);
});
it('deleteFolder nulls project folderId', () => {
const folder = createFolder(db, { name: 'F' });
const p = createProject(db, { name: 'P', folderId: folder.id });
deleteFolder(db, folder.id);
expect(getProject(db, p.id)!.folderId).toBeNull();
});
it('initDb tolerates existing folderId column', () => {
const tmp = path.join(os.tmpdir(), `qr-db-${Date.now()}.sqlite`);
try {
const env = { ...testEnv, DB_PATH: tmp } as Parameters<
typeof initDb
>[0];
const db1 = initDb(env);
db1.close();
const db2 = initDb(env);
const list = listFolders(db2);
expect(list).toEqual([]);
db2.close();
} finally {
try {
fs.unlinkSync(tmp);
} catch {
/* ignore */
}
}
});
});