Skip to content

Commit c9de75b

Browse files
committed
test: cover real knex and pino integrations
1 parent 585ba1f commit c9de75b

10 files changed

Lines changed: 432 additions & 230 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- Keep this a dual package: ESM and CommonJS must both work.
1818
- Keep TypeScript declarations valid for both ESM and CJS consumers.
1919
- Keep `sideEffects: false` unless a real package-level side effect is introduced.
20+
- Mark safe top-level helper initializers with pure pragmas, for example `/* @__PURE__ */`, so `sideEffects: false` stays effective for bundlers.
2021
- Keep source unit tests independent from `dist`.
2122

2223
## API Shape

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"@biomejs/biome": "^2.4.13",
9292
"@types/node": "^24",
9393
"knex": "^3.1.0",
94+
"pino": "^10.3.1",
9495
"sqlite3": "^6.0.1",
9596
"typescript": "^5.9.0",
9697
"unbuild": "^3.6.1"

pnpm-lock.yaml

Lines changed: 93 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import assert from 'node:assert/strict'
2+
import test from 'node:test'
3+
import { createFakeKnex } from '../test/helpers/fake-knex.ts'
4+
import knexTinyLogger from './index.ts'
5+
6+
test('knexTinyLogger wires logger start hooks', () => {
7+
const knex = createFakeKnex()
8+
const startEvents: unknown[] = []
9+
10+
knexTinyLogger(knex, {
11+
logger: {
12+
onStart(event) {
13+
startEvents.push(event)
14+
},
15+
},
16+
})
17+
18+
knex.emit('query', { __knexQueryUid: 'query-1', sql: 'select ?', bindings: [1] })
19+
20+
assert.equal(startEvents.length, 1)
21+
})
22+
23+
test('knexTinyLogger reports logger errors', () => {
24+
const knex = createFakeKnex()
25+
const loggerError = new Error('logger failed')
26+
const loggerErrors: unknown[] = []
27+
28+
knexTinyLogger(knex, {
29+
logger: {
30+
onEnd() {
31+
throw loggerError
32+
},
33+
},
34+
onLoggerError(event) {
35+
loggerErrors.push(event.error)
36+
},
37+
})
38+
39+
knex.emit('query', { __knexQueryUid: 'query-1', sql: 'select ?', bindings: [1] })
40+
knex.emit('query-response', [], { __knexQueryUid: 'query-1' })
41+
42+
assert.deepEqual(loggerErrors, [loggerError])
43+
})
44+
45+
test('knexTinyLogger falls back to console.error when logger error handlers throw', () => {
46+
const knex = createFakeKnex()
47+
const loggerError = new Error('logger failed')
48+
const handlerError = new Error('handler failed')
49+
const consoleErrors: unknown[][] = []
50+
const originalError = console.error
51+
52+
console.error = (...args: unknown[]) => {
53+
consoleErrors.push(args)
54+
}
55+
56+
try {
57+
knexTinyLogger(knex, {
58+
logger: {
59+
onError() {
60+
throw loggerError
61+
},
62+
},
63+
onLoggerError() {
64+
throw handlerError
65+
},
66+
})
67+
68+
knex.emit('query', { __knexQueryUid: 'query-1', sql: 'select broken' })
69+
knex.emit('query-error', new Error('query failed'), { __knexQueryUid: 'query-1' })
70+
} finally {
71+
console.error = originalError
72+
}
73+
74+
assert.deepEqual(consoleErrors, [[handlerError]])
75+
})

src/pino-logger.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import assert from 'node:assert/strict'
2+
import { Writable } from 'node:stream'
23
import test from 'node:test'
4+
import pino from 'pino'
35
import { createQueryEndEvent, createQueryErrorEvent } from '../test/helpers/events.ts'
46
import { pinoLogger } from './pino-logger.ts'
57

@@ -88,3 +90,25 @@ test('pinoLogger can omit bindings', () => {
8890
],
8991
])
9092
})
93+
94+
test('pinoLogger writes structured entries with real pino', () => {
95+
const chunks: string[] = []
96+
const stream = new Writable({
97+
write(chunk, _encoding, callback) {
98+
chunks.push(String(chunk))
99+
callback()
100+
},
101+
})
102+
const logger = pinoLogger(pino({ base: undefined, timestamp: false }, stream))
103+
104+
logger.onEnd?.(createQueryEndEvent())
105+
106+
assert.equal(chunks.length, 1)
107+
assert.deepEqual(JSON.parse(chunks[0]), {
108+
level: 30,
109+
sql: 'select ?',
110+
bindings: [1],
111+
durationMs: 12.34567,
112+
msg: 'SQL query',
113+
})
114+
})

src/timing.test.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from 'node:assert/strict'
22
import test from 'node:test'
3-
import { hrtimeTimingAdapter, performanceTimingAdapter } from './timing.ts'
3+
import { hrtimeTimingAdapter, performanceTimingAdapter, selectTimingAdapter, supportsPerformance } from './timing.ts'
44

55
test('performance timing adapter measures duration with performance.now', () => {
66
const originalPerformance = globalThis.performance
@@ -33,3 +33,14 @@ test('hrtime timing adapter measures duration with process.hrtime', () => {
3333

3434
assert.ok(hrtimeTimingAdapter.duration(startTime) >= 0)
3535
})
36+
37+
test('supportsPerformance detects performance.now support', () => {
38+
assert.equal(supportsPerformance({ now: () => 0 }), true)
39+
assert.equal(supportsPerformance(null), false)
40+
assert.equal(supportsPerformance({}), false)
41+
})
42+
43+
test('selectTimingAdapter prefers performance.now when available', () => {
44+
assert.equal(selectTimingAdapter({ now: () => 0 }), performanceTimingAdapter)
45+
assert.equal(selectTimingAdapter(null), hrtimeTimingAdapter)
46+
})

0 commit comments

Comments
 (0)