inspiration:
- db test with in-memory postgres
- separate tests
- (https://svelte.dev/docs/svelte/testing)
- (https://vitest.dev/api/vi.html#vi-mock)
//vitest.workspace.ts
import { defineWorkspace } from 'vitest/config'
import tsconfigPaths from "vite-tsconfig-paths"
import { sveltekit } from '@sveltejs/kit/vite';
export default defineWorkspace([
{
test: {
name: 'unit',
include: ['**/*.spec.ts'],
exclude: [
'**/*architecture.spec.ts',
'**/*.spec.svelte.ts',
'**/**.db.spec.ts'
],
},
},
{
plugins: [sveltekit()],
test: {
name: 'svelte unit',
include: ['**/*.spec.svelte.ts'],
},
},
{
test: {
name: 'architecture',
include: ['**/architecture.spec.ts'],
// More integration test related setup here...
},
},
{
plugins: [tsconfigPaths({ root: "./" })],
test: {
name: 'db integration',
globals: true,
environment: "node",
setupFiles: "./vitest.setup.ts",
include: ['**/**.db.spec.ts'],
},
},
]);
//vitest.setup.ts
import { vi } from 'vitest';
import * as schema from './src/lib/server/db/schema';
import { PGlite } from "@electric-sql/pglite";
import {drizzle} from "drizzle-orm/pglite"
import { users } from './src/lib/server/db/schema';
// vi.mock("$env/static/private", async () => {
// return {
// DATABASE_URL: "foo"
// }
// })
async function MOCK_DB() {
// use require to defeat dynamic require error
// (https://github.com/drizzle-team/drizzle-orm/issues/2853#issuecomment-2668459509) const { createRequire } =
await vi.importActual<typeof import("node:module")>("node:module")
const require = createRequire(import.meta.url)
const { pushSchema } =
require("drizzle-kit/api") as typeof import("drizzle-kit/api")
const client = new PGlite()
const db = drizzle(client, { schema })
// apply schema to db
const { apply } = await pushSchema(schema, db as any)
await apply()
// seed test data
await seed(db)
return { db, ...schema }
}
async function seed(db) {
await db
.insert(users)
.values({ email: "email@email.email", id: "aaa" })
}
// // seems to work but actually does not, still loading original file
// vi.mock("$lib/server/db", MOCK_DB)
vi.mock("./src/lib/server/db", MOCK_DB)
//vite.config.ts
import { defineConfig } from 'vitest/config';
import { sveltekit } from '@sveltejs/kit/vite';
export default defineConfig({
plugins: [sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
});
//integration.db.spec.ts
import { describe, it, expect } from 'vitest';
import { db, users } from '$lib/server/db';
import type { UserTable } from '$lib/server/db/types';
describe('db', () => {
it('users has been seede', async () => {
const myUsers: UserTable[] = await db.select().from(users);
const expected: UserTable[] = [{
id: 'aaa',
email: 'email@email.email',
name: null,
emailVerified: null,
image: null
}]
expect(myUsers).toEqual(expected);
});
});
//architecture.spec.ts
import { describe, expect, it } from 'vitest';
import { verifyArchitecture, clickableErrorMessage } from 'ts-arch-test';
describe('Architecture test', () => {
const folders: Record<string, string> = {
db: 'src/lib/server/db',
repositories: 'src/lib/server/repositories',
services: 'src/lib/server/services',
usecases: 'src/lib/server/usecases',
routes: 'src/routes'
};
const cases = [
{
filesFromFolderKey: 'db', notDependOnFolderKeys: [
// 'db',
'repositories',
'services',
'usecases',
'routes'
]
},
{
filesFromFolderKey: 'repositories', notDependOnFolderKeys: [
// 'db',
// 'repositories', // currently used for (yagni?) access checks with meaningful names 'services',
'usecases',
'routes'
]
},
{
filesFromFolderKey: 'services', notDependOnFolderKeys: [
// 'db', //todo: remove dependency services->db
// 'repositories',
'services',
'usecases',
'routes'
]
},
{
filesFromFolderKey: 'usecases', notDependOnFolderKeys: [
// 'db', //todo: remove dependency usecases->db
// 'repositories',
// 'services', // todo?: should we try and remove all services?
'usecases',
'routes'
]
},
{
filesFromFolderKey: 'routes', notDependOnFolderKeys: [
'db',
'repositories',
'services'
// 'usecases',
// 'routes', ]
}
];
cases.forEach(({ filesFromFolderKey, notDependOnFolderKeys }) => {
describe(filesFromFolderKey, () => {
notDependOnFolderKeys.forEach(notDependOnFolderKey => {
it(`${filesFromFolderKey} should not depend on ${notDependOnFolderKey}`, async () => {
const spec = {
filesFromFolder: folders[filesFromFolderKey],
notDependOnFolder: folders[notDependOnFolderKey]
};
const violations = await verifyArchitecture(spec, 'tsconfig.json');
const msg = clickableErrorMessage(spec, violations);
expect(violations, msg).toEqual([]);
});
});
});
});
});