87 lines
4.0 KiB
TypeScript
87 lines
4.0 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { mkdtempSync, rmSync } from 'fs';
|
|
import { join } from 'path';
|
|
import { tmpdir } from 'os';
|
|
import { Repository } from './repository.js';
|
|
|
|
describe('Repository dashboard widgets', () => {
|
|
let tmpDir: string;
|
|
let repo: Repository;
|
|
|
|
beforeEach(() => {
|
|
tmpDir = mkdtempSync(join(tmpdir(), 'dashboard-repo-test-'));
|
|
repo = new Repository(join(tmpDir, 'test.db'));
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('creates and lists widgets scoped to user_id', async () => {
|
|
const a = await repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'Memo', content: 'hello' });
|
|
await repo.createDashboardWidget({ userId: 'u2', slug: 'memo', title: 'Memo2', content: 'other-user' });
|
|
const widgets = await repo.listDashboardWidgets('u1');
|
|
expect(widgets).toHaveLength(1);
|
|
expect(widgets[0]!.id).toBe(a.id);
|
|
expect(widgets[0]!.slug).toBe('memo');
|
|
expect(widgets[0]!.title).toBe('Memo');
|
|
expect(widgets[0]!.markdownContent).toBe('hello');
|
|
});
|
|
|
|
it('rejects duplicate slug for same user', async () => {
|
|
await repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'a', content: '' });
|
|
await expect(
|
|
repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'b', content: '' })
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('updates content and bumps updated_at', async () => {
|
|
const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: 'old' });
|
|
const originalUpdatedAt = w.updatedAt;
|
|
await new Promise(r => setTimeout(r, 1100)); // datetime('now') has 1s precision
|
|
const updated = await repo.updateDashboardWidget(w.id, 'u1', { content: 'new' });
|
|
expect(updated.markdownContent).toBe('new');
|
|
expect(updated.updatedAt).not.toBe(originalUpdatedAt);
|
|
});
|
|
|
|
it('updateDashboardWidget rejects updates from other users', async () => {
|
|
const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: 'orig' });
|
|
await expect(
|
|
repo.updateDashboardWidget(w.id, 'u2', { content: 'hack' })
|
|
).rejects.toThrow(/not found/i);
|
|
const list = await repo.listDashboardWidgets('u1');
|
|
expect(list[0]!.markdownContent).toBe('orig');
|
|
});
|
|
|
|
it('upserts by (user_id, slug): returns existing if slug already exists', async () => {
|
|
const created = await repo.upsertDashboardWidgetBySlug({ userId: 'u1', slug: 'news', title: 'News', content: 'a' });
|
|
const second = await repo.upsertDashboardWidgetBySlug({ userId: 'u1', slug: 'news', content: 'b' });
|
|
expect(second.id).toBe(created.id);
|
|
expect(second.markdownContent).toBe('b');
|
|
});
|
|
|
|
it('deletes widget by id', async () => {
|
|
const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: '' });
|
|
await repo.deleteDashboardWidget(w.id, 'u1');
|
|
const list = await repo.listDashboardWidgets('u1');
|
|
expect(list).toHaveLength(0);
|
|
});
|
|
|
|
it('reorders widgets by id list', async () => {
|
|
const a = await repo.createDashboardWidget({ userId: 'u1', slug: 'a', title: 'A', content: '' });
|
|
const b = await repo.createDashboardWidget({ userId: 'u1', slug: 'b', title: 'B', content: '' });
|
|
const c = await repo.createDashboardWidget({ userId: 'u1', slug: 'c', title: 'C', content: '' });
|
|
await repo.reorderDashboardWidgets('u1', [c.id, a.id, b.id]);
|
|
const list = await repo.listDashboardWidgets('u1');
|
|
expect(list.map(w => w.slug)).toEqual(['c', 'a', 'b']);
|
|
});
|
|
|
|
it('reorder rejects ids from other users (silent skip + leave order intact)', async () => {
|
|
const u1a = await repo.createDashboardWidget({ userId: 'u1', slug: 'a', title: 'A', content: '' });
|
|
const u2x = await repo.createDashboardWidget({ userId: 'u2', slug: 'x', title: 'X', content: '' });
|
|
await repo.reorderDashboardWidgets('u1', [u2x.id, u1a.id]);
|
|
const list = await repo.listDashboardWidgets('u1');
|
|
expect(list.map(w => w.id)).toEqual([u1a.id]); // u2x should not appear
|
|
});
|
|
});
|