Files
hermes-ui/tests/server/db-index.test.ts
T
toor 1e9ea89d86
Build / build (push) Canceled after 0s
NPM Lockfile Check / npm ci --ignore-scripts (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s
chore: bootstrap hermes-ui skeleton from 0.6.29 snapshot
Import the client, server, skills, tests, and build scripts as the starting
point for the rebuild, then trim the surfaces this project does not ship:
Electron desktop packaging, the marketing website, and the ESP32 firmware
tree. CI keeps the web build, e2e, lockfile, release, and Docker workflows.

Rename the package and CLI entry points to hermes-ui, drop the prepare hook so
npm ci no longer triggers a build, and drop the removed tsconfig and nodemon
references. Rewrite AGENTS.md, ARCHITECTURE.md, DEVELOPMENT.md, and the READMEs
so the documented package map and hard rules match this repository.

reference_code/ is ignored: it is a read-only snapshot, not an input to the build.
2026-10-16 10:34:35 +08:00

117 lines
4.0 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest'
// Force JSON fallback by mocking isSqliteAvailable
vi.mock('../../packages/server/src/db/index', async (importOriginal) => {
const actual = await importOriginal() as any
return {
...actual,
isSqliteAvailable: () => false,
getDb: () => null,
}
})
import {
jsonGet,
jsonSet,
jsonGetAll,
jsonDelete,
} from '../../packages/server/src/db/index'
describe('JSON fallback store', () => {
it('jsonSet and jsonGet round-trip', () => {
expect(typeof jsonSet).toBe('function')
expect(typeof jsonGet).toBe('function')
expect(typeof jsonGetAll).toBe('function')
expect(typeof jsonDelete).toBe('function')
})
})
// Test ensureTable with a real in-memory SQLite (Node 22+)
describe('SQLite ensureTable', () => {
it('creates table with correct columns and handles migration', () => {
// This test requires Node 22.5+ for node:sqlite
const nodeVersion = process.versions.node.split('.').map(Number)
const isAvailable = nodeVersion[0] > 22 || (nodeVersion[0] === 22 && nodeVersion[1] >= 5)
if (!isAvailable) {
console.log('Skipping SQLite test — Node < 22.5')
return
}
const { DatabaseSync } = require('node:sqlite')
const db = new DatabaseSync(':memory:')
// Simulate ensureTable logic
function ensureTable(tableName: string, schema: Record<string, string>): void {
const colDefs = Object.entries(schema)
.map(([col, def]) => `"${col}" ${def}`)
.join(', ')
db.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (${colDefs})`)
const rows = db.prepare(`PRAGMA table_info("${tableName}")`).all() as Array<{ name: string }>
const existingCols = new Set(rows.map(r => r.name))
const expectedCols = new Set(Object.keys(schema))
for (const col of expectedCols) {
if (!existingCols.has(col)) {
db.exec(`ALTER TABLE "${tableName}" ADD COLUMN "${col}" ${schema[col]}`)
}
}
for (const col of existingCols) {
if (!expectedCols.has(col)) {
db.exec(`ALTER TABLE "${tableName}" DROP COLUMN "${col}"`)
}
}
}
// Initial schema
const schema: Record<string, string> = {
session_id: 'TEXT PRIMARY KEY',
input_tokens: 'INTEGER NOT NULL DEFAULT 0',
output_tokens: 'INTEGER NOT NULL DEFAULT 0',
updated_at: 'INTEGER NOT NULL',
}
ensureTable('session_usage', schema)
// Verify columns
const cols = db.prepare(`PRAGMA table_info("session_usage")`).all() as Array<{ name: string }>
const colNames = cols.map(c => c.name)
expect(colNames).toContain('session_id')
expect(colNames).toContain('input_tokens')
expect(colNames).toContain('output_tokens')
expect(colNames).toContain('updated_at')
// Add a column
schema['cost_usd'] = 'REAL DEFAULT 0'
ensureTable('session_usage', schema)
const cols2 = db.prepare(`PRAGMA table_info("session_usage")`).all() as Array<{ name: string }>
const colNames2 = cols2.map(c => c.name)
expect(colNames2).toContain('cost_usd')
// Remove a column
delete schema['cost_usd']
ensureTable('session_usage', schema)
const cols3 = db.prepare(`PRAGMA table_info("session_usage")`).all() as Array<{ name: string }>
const colNames3 = cols3.map(c => c.name)
expect(colNames3).not.toContain('cost_usd')
// Verify INSERT works
db.prepare(
`INSERT INTO session_usage (session_id, input_tokens, output_tokens, updated_at)
VALUES (?, ?, ?, ?)`,
).run('test-session', 100, 50, Date.now())
const row = db.prepare('SELECT * FROM session_usage WHERE session_id = ?').get('test-session') as any
expect(row.session_id).toBe('test-session')
expect(row.input_tokens).toBe(100)
expect(row.output_tokens).toBe(50)
// Verify DELETE works
db.prepare('DELETE FROM session_usage WHERE session_id = ?').run('test-session')
const deleted = db.prepare('SELECT * FROM session_usage WHERE session_id = ?').get('test-session')
expect(deleted).toBeUndefined()
db.close()
})
})