AI Implementation feature(820): Project Scaffold and Platform Foundations (#1)
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import * as path from 'path';
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
import { InitSchema1700000000000 } from '../../backend/src/database/migrations/1700000000000-InitSchema';
|
||||
import { SeedSystemData1700000000100 } from '../../backend/src/database/migrations/1700000000100-SeedSystemData';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { UserEntity } from '../../backend/src/database/entities/user.entity';
|
||||
import { SettingEntity } from '../../backend/src/database/entities/setting.entity';
|
||||
import { CategoryEntity } from '../../backend/src/database/entities/category.entity';
|
||||
import { ChallengeEntity } from '../../backend/src/database/entities/challenge.entity';
|
||||
import { ChallengeFileEntity } from '../../backend/src/database/entities/challenge-file.entity';
|
||||
import { SolveEntity } from '../../backend/src/database/entities/solve.entity';
|
||||
import { RefreshTokenEntity } from '../../backend/src/database/entities/refresh-token.entity';
|
||||
import { BlogPostEntity } from '../../backend/src/database/entities/blog-post.entity';
|
||||
|
||||
describe('Migrations', () => {
|
||||
let dataSource: DataSource;
|
||||
|
||||
beforeAll(async () => {
|
||||
dataSource = new DataSource({
|
||||
type: 'better-sqlite3',
|
||||
database: ':memory:',
|
||||
entities: [UserEntity, SettingEntity, CategoryEntity, ChallengeEntity, ChallengeFileEntity, SolveEntity, RefreshTokenEntity, BlogPostEntity],
|
||||
migrations: [InitSchema1700000000000, SeedSystemData1700000000100],
|
||||
migrationsRun: true,
|
||||
synchronize: false,
|
||||
logging: false,
|
||||
});
|
||||
await dataSource.initialize();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await dataSource.destroy();
|
||||
});
|
||||
|
||||
it('creates all required tables', async () => {
|
||||
const tables = await dataSource.query("SELECT name FROM sqlite_master WHERE type='table'");
|
||||
const names = tables.map((t: any) => t.name);
|
||||
expect(names).toEqual(expect.arrayContaining([
|
||||
'user', 'setting', 'category', 'challenge', 'challenge_file',
|
||||
'solve', 'refresh_token', 'blog_post',
|
||||
]));
|
||||
});
|
||||
|
||||
it('seeds 6 system categories with unique system_keys', async () => {
|
||||
const cats = await dataSource.getRepository(CategoryEntity).find();
|
||||
const systemCats = cats.filter((c) => c.systemKey);
|
||||
expect(systemCats.length).toBeGreaterThanOrEqual(6);
|
||||
const keys = systemCats.map((c) => c.systemKey);
|
||||
expect(new Set(keys).size).toBe(keys.length);
|
||||
});
|
||||
|
||||
it('seeds default settings', async () => {
|
||||
const settings = await dataSource.getRepository(SettingEntity).find();
|
||||
const keys = settings.map((s) => s.key);
|
||||
expect(keys).toEqual(expect.arrayContaining(['pageTitle', 'themeKey', 'eventStartUtc', 'eventEndUtc']));
|
||||
});
|
||||
|
||||
it('enforces UNIQUE(challengeId, userId) on solve', async () => {
|
||||
const indexes = await dataSource.query("SELECT name, sql FROM sqlite_master WHERE type='index' AND tbl_name='solve'");
|
||||
const uq = indexes.find((i: any) => /UNIQUE.*challenge_id.*user_id/i.test(i.sql || ''));
|
||||
expect(uq).toBeDefined();
|
||||
});
|
||||
|
||||
it('enforces ON DELETE RESTRICT FK on solve', async () => {
|
||||
const fks = await dataSource.query("PRAGMA foreign_key_list('solve')");
|
||||
const restrict = fks.filter((f: any) => f.on_delete === 'RESTRICT');
|
||||
expect(restrict.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user