test(core): fix more tests

This commit is contained in:
Elian Doran
2026-04-09 17:41:47 +03:00
parent 3a7ce0c284
commit f40de0a017
10 changed files with 61 additions and 14 deletions

View File

@@ -20,12 +20,13 @@ process.env.TRILIUM_PUBLIC_SERVER = "http://localhost:4200";
beforeAll(async () => {
// Load the integration test database into memory. The fixture at
// spec/db/document.db is pre-seeded with the schema, demo content, and
// a known password ("demo1234") that the ETAPI tests log in with. Each
// test file runs in its own vitest fork (pool: "forks"), so each gets a
// fresh in-memory copy and mutations don't leak across files.
// packages/trilium-core/src/test/fixtures/document.db is pre-seeded with
// the schema, demo content, and a known password ("demo1234") that the
// ETAPI tests log in with. Each test file runs in its own vitest fork
// (pool: "forks"), so each gets a fresh in-memory copy and mutations
// don't leak across files.
const dbProvider = new BetterSqlite3Provider();
dbProvider.loadFromBuffer(readFileSync(join(__dirname, "db", "document.db")));
dbProvider.loadFromBuffer(readFileSync(require.resolve("@triliumnext/core/src/test/fixtures/document.db")));
await initializeCore({
dbConfig: {

View File

@@ -8,6 +8,17 @@ let dbConnection!: Database.Database;
let dbConnectionReady = false;
sql_init.dbReady.then(() => {
// The share module opens its own read-only connection to the on-disk
// database for isolation from the main read/write connection. In
// integration test mode the database is in-memory (loaded from a
// fixture buffer) and no file exists on disk, so opening one would
// throw SQLITE_CANTOPEN. Tests that exercise share functionality
// would need a different approach; skipping here keeps unrelated
// test files from failing on an unhandled rejection.
if (process.env.TRILIUM_INTEGRATION_TEST) {
return;
}
dbConnection = new Database(dataDir.DOCUMENT_PATH, {
readonly: true,
nativeBinding: process.env.BETTERSQLITE3_NATIVE_PATH || undefined

View File

@@ -31,6 +31,10 @@ export default class BetterSqlite3Provider implements DatabaseProvider {
}
loadFromBuffer(buffer: NonSharedBuffer) {
// Close any existing connection so its file handles are released
// before we replace it. Important for repeated rebuilds in tests
// (each call would otherwise leak the previous handle).
this.dbConnection?.close();
this.dbConnection = new Database(buffer, dbOpts);
}

View File

@@ -1,10 +1,19 @@
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it, beforeEach } from "vitest";
import * as cls from "../services/context.js";
import { getSql, rebuildIntegrationTestDatabase } from "../services/sql/index.js";
import { getSql } from "../services/sql/index.js";
import becca from "../becca/becca.js";
import becca_loader from "../becca/becca_loader.js";
import migration from "./0233__migrate_geo_map_to_collection.js";
// Resolve fixture path relative to this spec file. Spec files only ever run
// under vitest (which uses ESM via Vite), so import.meta.url is available;
// the CLAUDE.md restriction against import.meta.url applies to production
// code that gets bundled to CJS, not to test files.
const __dirname = dirname(fileURLToPath(import.meta.url));
/**
* Test suite for migration 0233 which converts geoMap notes to book type with viewConfig attachments.
*
@@ -29,8 +38,10 @@ describe("Migration 0233: Migrate geoMap to collection", () => {
// beforeAll hooks fire.
sql = getSql();
// Set up a clean in-memory database for each test
rebuildIntegrationTestDatabase();
// Reload the integration test database from the fixture for each test
// so mutations from one test don't leak into the next.
const dbBytes = readFileSync(join(__dirname, "../test/fixtures/document.db"));
sql.rebuildFromBuffer(dbBytes);
await new Promise<void>((resolve) => {
cls.getContext().init(() => {

View File

@@ -1,12 +1,22 @@
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { getContext } from "./context.js";
import { getSql } from "./sql/index.js";
// Resolve fixture path relative to this spec file. Spec files only ever run
// under vitest (which uses ESM via Vite), so import.meta.url is available;
// the CLAUDE.md restriction against import.meta.url applies to production
// code that gets bundled to CJS, not to test files.
const __dirname = dirname(fileURLToPath(import.meta.url));
describe("Migration", () => {
it("migrates from v214", async () => {
await new Promise<void>((resolve) => {
getContext().init(async () => {
const { getSql, rebuildIntegrationTestDatabase } = (await (import("./sql/index.js")));
rebuildIntegrationTestDatabase("spec/db/document_v214.db");
const dbBytes = readFileSync(join(__dirname, "../test/fixtures/document_v214.db"));
getSql().rebuildFromBuffer(dbBytes);
const migration = (await import("./migration.js")).default;
await migration.migrateIfNecessary();

View File

@@ -13,7 +13,3 @@ export function getSql(): SqlService {
if (!sql) throw new Error("SQL not initialized");
return sql;
}
export function rebuildIntegrationTestDatabase(path?: string) {
throw new Error("Not implemented");
}

View File

@@ -27,6 +27,20 @@ export class SqlService {
this.params = restParams;
}
/**
* Replace the underlying database with a fresh in-memory copy of the
* given buffer. Used by integration tests that need a clean DB per test.
*
* Clears the prepared-statement cache because cached statements are
* bound to the previous connection and become invalid after the swap.
*
* Not safe to call inside a transaction.
*/
rebuildFromBuffer(buffer: Uint8Array) {
this.statementCache = {};
this.dbConnection.loadFromBuffer(buffer);
}
insert<T extends {}>(tableName: string, rec: T, replace = false) {
const keys = Object.keys(rec || {});
if (keys.length === 0) {