test: cover publishing, authentication and storage persistence
This commit is contained in:
58
tests/content.test.ts
Normal file
58
tests/content.test.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { openDatabase, migrateDatabase } from '../src/server/db';
|
||||
import { seedDatabase } from '../src/server/seed';
|
||||
import { readContent, saveContent, resolvePublicRoute, deleteContent } from '../src/server/content';
|
||||
import { importLegacy } from '../src/server/legacy-import';
|
||||
|
||||
function setup(t: { after: (fn: () => void) => void }) {
|
||||
const directory = mkdtempSync(path.join(tmpdir(), 'portfolio-test-'));
|
||||
const connection = openDatabase(directory);
|
||||
migrateDatabase(connection); seedDatabase(connection);
|
||||
t.after(() => { connection.sqlite.close(); rmSync(directory, { recursive: true, force: true }); });
|
||||
return connection;
|
||||
}
|
||||
test('seed is idempotent and content saves are validated and immediately readable', t => {
|
||||
const connection = setup(t); const original = readContent(connection);
|
||||
const hero = original.sections.find(section => section.key === 'hero')!;
|
||||
hero.translations.en.name = 'Test owner';
|
||||
saveContent(connection, 'sections', hero);
|
||||
seedDatabase(connection);
|
||||
assert.equal(resolvePublicRoute(readContent(connection)).portfolio.messages.hero.name, 'Test owner');
|
||||
assert.throws(() => saveContent(connection, 'sections', { ...hero, translations: { en: { name: '' } } }));
|
||||
assert.equal(resolvePublicRoute(readContent(connection)).portfolio.messages.hero.name, 'Test owner');
|
||||
assert.throws(() => importLegacy(connection), /before content has been edited/);
|
||||
saveContent(connection, 'sections', { ...hero, visible: false });
|
||||
assert.ok(!JSON.stringify(resolvePublicRoute(readContent(connection)).portfolio).includes('Test owner'));
|
||||
});
|
||||
test('runtime projects and arbitrary locales resolve, hidden and missing URLs do not', t => {
|
||||
const connection = setup(t);
|
||||
saveContent(connection, 'languages', { code: 'ar', name: 'العربية', direction: 'rtl', enabled: true, messages: { 'projects.viewCaseStudy': 'دراسة الحالة' } });
|
||||
assert.equal(resolvePublicRoute(readContent(connection), ['ar']).portfolio.direction, 'rtl');
|
||||
assert.equal(resolvePublicRoute(readContent(connection), ['ar']).portfolio.messages.projects.viewCaseStudy, 'دراسة الحالة');
|
||||
const project = readContent(connection).entries.find(entry => entry.kind === 'projects')!;
|
||||
saveContent(connection, 'entries', { ...project, id: 'new-project' });
|
||||
assert.equal(resolvePublicRoute(readContent(connection), ['ar','projects','new-project']).project?.id, 'new-project');
|
||||
saveContent(connection, 'entries', { ...project, id: 'new-project', visible: false });
|
||||
assert.throws(() => resolvePublicRoute(readContent(connection), ['projects','new-project']), /not found/);
|
||||
deleteContent(connection, 'entries', project.id);
|
||||
assert.throws(() => resolvePublicRoute(readContent(connection), ['projects',project.id]), /not found/);
|
||||
for (const parts of [['en'], ['unknown'], ['ar','bad'], ['admin']]) assert.throws(() => resolvePublicRoute(readContent(connection), parts));
|
||||
assert.throws(() => saveContent(connection, 'languages', { code: 'en', name: 'English', direction: 'ltr', enabled: false, messages: {} }));
|
||||
});
|
||||
test('legacy import preserves English and Persian projects and only runs once', t => {
|
||||
const connection = setup(t); importLegacy(connection);
|
||||
const snapshot = readContent(connection);
|
||||
assert.equal(resolvePublicRoute(snapshot, ['projects','qlockify']).project?.title, 'Qlockify');
|
||||
assert.equal(resolvePublicRoute(snapshot, ['fa']).portfolio.direction, 'rtl');
|
||||
assert.ok(snapshot.entries.length > 5);
|
||||
assert.throws(() => importLegacy(connection));
|
||||
});
|
||||
test('startup rejects a database migrated by an incompatible application image', t => {
|
||||
const connection = setup(t);
|
||||
connection.sqlite.prepare('INSERT INTO __drizzle_migrations (hash, created_at) VALUES (?, ?)').run('future-migration', Date.now() + 100000);
|
||||
assert.throws(() => migrateDatabase(connection), /do not match/);
|
||||
});
|
||||
Reference in New Issue
Block a user