@@ -2,6 +2,7 @@ import { CreateWebSocket, TimingSafeEqual, WebSocket } from "@evolu/common";
22import BetterSQLite , { Statement } from "better-sqlite3" ;
33import { timingSafeEqual } from "crypto" ;
44import { customRandom , urlAlphabet } from "nanoid" ;
5+ import { Console } from "../src/Console.js" ;
56import {
67 createSymmetricCrypto ,
78 RandomBytes ,
@@ -215,3 +216,102 @@ export const testCreateDummyWebSocket: CreateWebSocket = () => ({
215216 isOpen : constFalse ,
216217 [ Symbol . dispose ] : constVoid ,
217218} ) ;
219+
220+ /**
221+ * A test console that captures all console output for snapshot testing.
222+ *
223+ * Use this as a drop-in replacement for `createConsole` in tests where you want
224+ * to capture and verify console output.
225+ */
226+ export interface TestConsole extends Console {
227+ /**
228+ * Gets all captured console logs. Clears the captured logs after returning
229+ * them.
230+ */
231+ readonly getLogsSnapshot : ( ) => ReadonlyArray < Array < unknown > > ;
232+
233+ /** Clears all captured logs. */
234+ readonly clearLogs : ( ) => void ;
235+ }
236+
237+ /**
238+ * Creates a test console that captures all console output for testing.
239+ *
240+ * ### Example
241+ *
242+ * ```ts
243+ * test("console output", () => {
244+ * const testConsole = createTestConsole();
245+ *
246+ * // Use it in place of createConsole()
247+ * const deps = { console: testConsole };
248+ *
249+ * // ... run code that logs to console
250+ *
251+ * expect(testConsole.getLogsSnapshot()).toMatchInlineSnapshot();
252+ * });
253+ * ```
254+ */
255+ export const createTestConsole = ( ) : TestConsole => {
256+ const logs : Array < Array < unknown > > = [ ] ;
257+
258+ return {
259+ enabled : true ,
260+
261+ log : ( ...args ) => {
262+ logs . push ( args ) ;
263+ } ,
264+ info : ( ...args ) => {
265+ logs . push ( args ) ;
266+ } ,
267+ warn : ( ...args ) => {
268+ logs . push ( args ) ;
269+ } ,
270+ error : ( ...args ) => {
271+ logs . push ( args ) ;
272+ } ,
273+ debug : ( ...args ) => {
274+ logs . push ( args ) ;
275+ } ,
276+ time : ( label ) => {
277+ logs . push ( [ "time" , label ] ) ;
278+ } ,
279+ timeLog : ( label , ...data ) => {
280+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
281+ logs . push ( [ "timeLog" , label , ...data ] ) ;
282+ } ,
283+ timeEnd : ( label ) => {
284+ logs . push ( [ "timeEnd" , label ] ) ;
285+ } ,
286+ dir : ( object , options ) => {
287+ logs . push ( [ "dir" , object , options ] ) ;
288+ } ,
289+ table : ( tabularData , properties ) => {
290+ logs . push ( [ "table" , tabularData , properties ] ) ;
291+ } ,
292+ count : ( label ) => {
293+ logs . push ( [ "count" , label ] ) ;
294+ } ,
295+ countReset : ( label ) => {
296+ logs . push ( [ "countReset" , label ] ) ;
297+ } ,
298+ assert : ( value , message , ...optionalParams ) => {
299+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
300+ logs . push ( [ "assert" , value , message , ...optionalParams ] ) ;
301+ } ,
302+ trace : ( message , ...optionalParams ) => {
303+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
304+ logs . push ( [ "trace" , message , ...optionalParams ] ) ;
305+ } ,
306+
307+ getLogsSnapshot : ( ) => {
308+ const snapshot = [ ...logs ] ;
309+ logs . length = 0 ; // Clear captured logs
310+ return snapshot ;
311+ } ,
312+
313+ clearLogs : ( ) => {
314+ logs . length = 0 ;
315+ } ,
316+ } ;
317+ } ;
0 commit comments