Skip to content

Commit eb26a8a

Browse files
committed
Fix nuxt tests
1 parent 489615a commit eb26a8a

4 files changed

Lines changed: 79 additions & 117 deletions

File tree

packages/common/src/utils/Logger.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ export function createPowerSyncLogger(options?: Partial<CreateLoggerOptions>): P
7676
if (level < this.minLevel) return;
7777

7878
let emitter = console.log;
79-
if (level >= LogLevels.error) {
79+
if (level >= LogLevels.info) {
80+
emitter = console.info;
81+
} else if (level >= LogLevels.error) {
8082
emitter = console.error;
8183
} else if (level >= LogLevels.warn) {
8284
emitter = console.warn;

packages/nuxt/src/runtime/composables/useDiagnosticsLogger.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export const useDiagnosticsLogger = (additional?: PowerSyncLogger) => {
4242
date: new Date(),
4343
tag: record.tag,
4444
message: record.message,
45-
error: record.error
45+
error: record.error,
46+
level: nameOfLogLevel(record.level)
4647
};
4748
const key = `log:${logObject.date.toISOString()}`;
4849
await logsStorage.set(key, logObject);
@@ -55,3 +56,19 @@ export const useDiagnosticsLogger = (additional?: PowerSyncLogger) => {
5556

5657
return { logger, logsStorage, emitter };
5758
};
59+
60+
const levelNames: [string, number][] = [
61+
['ERROR', LogLevels.error],
62+
['WARNING', LogLevels.warn],
63+
['INFO', LogLevels.info],
64+
['DEBUG', LogLevels.debug],
65+
['TRACE', LogLevels.trace]
66+
];
67+
68+
function nameOfLogLevel(level: number): string | undefined {
69+
for (const [name, minLevel] of levelNames) {
70+
if (level >= minLevel) return name;
71+
}
72+
73+
return undefined;
74+
}

packages/nuxt/tests/composables/NuxtPowerSyncDatabase.test.ts

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,49 +19,49 @@ describe('NuxtPowerSyncDatabase', () => {
1919
it('should use default sync implementation when diagnostics is disabled', async () => {
2020
const db = openPowerSync(false);
2121
const connector = createMockConnector();
22-
22+
2323
// Spy on the parent class method to verify it's called
2424
const superGenerateSpy = vi.spyOn(
2525
Object.getPrototypeOf(Object.getPrototypeOf(db)),
2626
'generateSyncStreamImplementation'
2727
);
28-
28+
2929
await db.init();
3030
await db.connect(connector);
31-
31+
3232
// When diagnostics is disabled, should call super.generateSyncStreamImplementation
3333
// We can't directly test this, but we can verify the sync implementation exists
3434
expect(db.syncStreamImplementation).toBeDefined();
35-
35+
3636
await db.disconnect();
3737
});
3838

3939
it('should use diagnostics sync implementation when diagnostics is enabled', async () => {
4040
setUseDiagnostics(true);
4141
const db = openPowerSync(true);
4242
const connector = createMockConnector();
43-
43+
4444
await db.init();
4545
await db.connect(connector);
46-
46+
4747
// When diagnostics is enabled, should use SharedWebStreamingSyncImplementation
4848
// (because enableMultiTabs is set to true)
4949
const syncImpl = db.syncStreamImplementation;
5050
expect(syncImpl).toBeDefined();
5151
expect(syncImpl).toBeInstanceOf(SharedWebStreamingSyncImplementation);
52-
52+
5353
await db.disconnect();
5454
});
5555

5656
it('should extend schema with diagnostics tables when diagnostics is enabled', () => {
5757
setUseDiagnostics(true);
5858
const db = openPowerSync(true);
59-
59+
6060
// Verify that diagnostics schema tables are included
6161
// The schema should include both the app schema and diagnostics schema
6262
const schema = db.dbOptions.schema;
6363
expect(schema).toBeDefined();
64-
64+
6565
// Check that diagnostics tables are present
6666
const tableNames = schema.tables.map((t: any) => t.name);
6767
// Diagnostics schema includes local_bucket_data and local_schema
@@ -74,7 +74,7 @@ describe('NuxtPowerSyncDatabase', () => {
7474
it('should set enableMultiTabs and broadcastLogs flags when diagnostics is enabled', () => {
7575
setUseDiagnostics(true);
7676
const db = openPowerSync(true);
77-
77+
7878
// Verify flags are set
7979
const flags = db.dbOptions.flags;
8080
expect(flags?.enableMultiTabs).toBe(true);
@@ -84,28 +84,26 @@ describe('NuxtPowerSyncDatabase', () => {
8484
it('should use diagnostics logger when diagnostics is enabled', () => {
8585
setUseDiagnostics(true);
8686
const db = openPowerSync(true);
87-
87+
8888
// Verify logger is set (it should be the diagnostics logger, not default)
8989
const logger = db.dbOptions.logger;
9090
expect(logger).toBeDefined();
91-
// The diagnostics logger should have DEBUG level
92-
expect(logger?.getLevel()).toBeDefined();
9391
});
9492

9593
it('should store connector and connectionOptions internally', async () => {
9694
const db = openPowerSync(false);
9795
const connector = createMockConnector();
9896
const connectionOptions = { clientImplementation: undefined };
99-
97+
10098
await db.init();
10199
await db.connect(connector, connectionOptions);
102-
100+
103101
// Verify connector is stored
104102
expect(db.connector).toBe(connector);
105103
expect(db.connectionOptions).toBe(connectionOptions);
106-
104+
107105
await db.disconnect();
108-
106+
109107
// After disconnect, should be cleared
110108
expect(db.connector).toBeNull();
111109
expect(db.connectionOptions).toBeNull();
@@ -115,29 +113,29 @@ describe('NuxtPowerSyncDatabase', () => {
115113
setUseDiagnostics(true);
116114
const db = openPowerSync(true);
117115
const connector = createMockConnector();
118-
116+
119117
await db.init();
120118
await db.connect(connector);
121-
119+
122120
// When diagnostics is enabled, enableMultiTabs is set to true,
123121
// so it should use SharedWebStreamingSyncImplementation
124122
const syncImpl = db.syncStreamImplementation;
125123
expect(syncImpl).toBeInstanceOf(SharedWebStreamingSyncImplementation);
126-
124+
127125
await db.disconnect();
128126
});
129127

130128
it('should clear connector and connectionOptions on disconnectAndClear', async () => {
131129
const db = openPowerSync(false);
132130
const connector = createMockConnector();
133-
131+
134132
await db.init();
135133
await db.connect(connector);
136-
134+
137135
expect(db.connector).toBe(connector);
138-
136+
139137
await db.disconnectAndClear();
140-
138+
141139
expect(db.connector).toBeNull();
142140
expect(db.connectionOptions).toBeNull();
143141
});
Lines changed: 36 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
1+
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
22
import { useDiagnosticsLogger } from '../../src/runtime/composables/useDiagnosticsLogger';
3-
import { LogLevel, type ILogHandler } from '@powersync/web';
43
import { withSetup } from '../utils';
4+
import { LogLevels, type LogRecord, type PowerSyncLogger } from '@powersync/common';
55

66
describe('useDiagnosticsLogger', () => {
77
beforeEach(() => {
@@ -17,8 +17,7 @@ describe('useDiagnosticsLogger', () => {
1717
const [{ logger, logsStorage }] = withSetup(() => useDiagnosticsLogger());
1818

1919
const testMessage = 'Test log message for storage';
20-
const extraPayload = { name: 'TestContext', level: { name: 'INFO' } };
21-
await logger.log(testMessage, extraPayload as any);
20+
await logger.log({ level: LogLevels.info, message: testMessage, tag: 'TestContext' });
2221

2322
// Wait for async storage operations
2423
await new Promise((resolve) => setTimeout(resolve, 150));
@@ -30,87 +29,64 @@ describe('useDiagnosticsLogger', () => {
3029
expect(logKeys.length).toBeGreaterThan(0);
3130

3231
// Find the log that contains our message (key order may vary)
33-
let storedLog: { args?: unknown[] } | null = null;
32+
let storedLog: { message: string } | null = null;
3433
for (const key of logKeys) {
35-
const log = (await logsStorage.getItem(key)) as { args?: unknown[] } | null;
36-
const args = log?.args;
37-
if (args?.some((arg) => typeof arg === 'string' && arg.includes(testMessage))) {
34+
const log = (await logsStorage.getItem(key)) as { message: string };
35+
if (log.message.indexOf(testMessage) >= 0) {
3836
storedLog = log;
3937
break;
4038
}
4139
}
4240

43-
expect(storedLog).toBeDefined();
44-
expect(storedLog).toHaveProperty('args');
45-
expect(Array.isArray(storedLog?.args)).toBe(true);
46-
const logArgs = storedLog?.args as any[];
47-
expect(logArgs[0]).toBe(testMessage);
48-
// args[1] is stored as-is (object, not "[object Object]")
49-
expect(logArgs[1]).toBeDefined();
50-
expect(logArgs[1]).toHaveProperty('name', 'TestContext');
51-
expect(logArgs[2]).toBeDefined();
52-
expect(logArgs[2]).toHaveProperty('level');
41+
expect(storedLog).toMatchObject({
42+
tag: 'TestContext',
43+
level: 'INFO',
44+
message: testMessage
45+
});
5346
});
5447

5548
it('should emit log events with correct payload structure', async () => {
5649
const logEvents: any[] = [];
5750
const [{ logger, emitter }] = withSetup(() => useDiagnosticsLogger());
58-
51+
5952
// Listen for log events
6053
emitter.on('log', (event) => {
6154
logEvents.push(event);
6255
});
63-
56+
6457
const testMessage = 'Test event message';
65-
await logger.log(testMessage, {
66-
name: 'TestContext',
67-
level: { name: 'WARN' }
58+
await logger.log({
59+
message: testMessage,
60+
tag: 'TestContext',
61+
level: LogLevels.warn
6862
} as any);
69-
63+
7064
// Wait for async operations
71-
await new Promise(resolve => setTimeout(resolve, 150));
72-
65+
await new Promise((resolve) => setTimeout(resolve, 150));
66+
7367
// Verify event was emitted with correct structure
7468
expect(logEvents.length).toBeGreaterThan(0);
7569
const event = logEvents[0];
76-
expect(event).toHaveProperty('key');
77-
expect(event).toHaveProperty('value');
78-
expect(typeof event.key).toBe('string');
79-
expect(event.key).toMatch(/^log:/);
80-
expect(event.value).toBeDefined();
81-
expect(event.value).toHaveProperty('args');
70+
expect(event.value).toMatchObject({
71+
tag: 'TestContext',
72+
message: testMessage,
73+
level: 'WARNING'
74+
});
8275
});
8376

8477
it('should call custom handler with correct messages and context', async () => {
85-
const customHandler = vi.fn<ILogHandler>();
86-
const [{ logger }] = withSetup(() => useDiagnosticsLogger(customHandler));
78+
const log = vi.fn((_record: LogRecord) => {});
79+
const [{ logger }] = withSetup(() => useDiagnosticsLogger({ log }));
8780

88-
const testMessages = ['Message 1', 'Message 2'];
89-
const testContext = { name: 'TestContext', level: { name: 'ERROR' } } as any;
90-
91-
await logger.log(testMessages, testContext);
81+
await logger.log({ level: LogLevels.warn, message: 'Message 1', tag: 'TestContext' });
9282

9383
// Wait for async handler
9484
await new Promise((resolve) => setTimeout(resolve, 150));
9585

96-
expect(customHandler).toHaveBeenCalledTimes(1);
97-
const [messages, context] = customHandler.mock.calls[0];
98-
99-
const messagesArray = Array.from(messages);
100-
expect(messagesArray.length).toBeGreaterThan(0);
101-
// First argument to log() is what we passed (array or string)
102-
const firstArg = messagesArray[0];
103-
const hasMessage1 =
104-
(Array.isArray(firstArg) && firstArg.includes('Message 1')) ||
105-
(typeof firstArg === 'string' && firstArg.includes('Message 1'));
106-
expect(hasMessage1).toBe(true);
107-
// When two args passed to log(), second is in messages (js-logger passes all log args)
108-
if (messagesArray.length > 1 && typeof messagesArray[1] === 'object' && messagesArray[1]?.name) {
109-
expect(messagesArray[1].name).toBe('TestContext');
110-
expect(messagesArray[1].level?.name).toBe('ERROR');
111-
}
112-
expect(context).toBeDefined();
113-
expect(context.level?.name).toBeDefined();
86+
expect(log).toHaveBeenCalledTimes(1);
87+
const [record] = log.mock.calls[0];
88+
89+
expect(record).toStrictEqual({ level: LogLevels.warn, message: 'Message 1', tag: 'TestContext' });
11490
});
11591

11692
it('should format messages with PowerSync prefix to console', async () => {
@@ -120,46 +96,15 @@ describe('useDiagnosticsLogger', () => {
12096
const [{ logger }] = withSetup(() => useDiagnosticsLogger());
12197

12298
const testMessage = 'Test formatted message';
123-
await logger.log([testMessage, 'Extra data'], {
124-
name: 'PowerSyncTest',
125-
level: { name: 'INFO' }
126-
} as any);
99+
await logger.log({ message: testMessage, level: LogLevels.info, tag: 'tag' });
127100

128101
await new Promise((resolve) => setTimeout(resolve, 150));
129102

130103
expect(consoleSpy).toHaveBeenCalled();
131-
const hasPowerSyncPrefix = consoleSpy.mock.calls.some((call) => {
132-
const firstArg = call[0];
133-
return typeof firstArg === 'string' && firstArg.includes('[PowerSync]');
134-
});
135-
expect(hasPowerSyncPrefix).toBe(true);
104+
expect(consoleSpy.mock.calls.map((call) => call[0])).toEqual(
105+
expect.arrayContaining([expect.stringContaining('[PowerSync.tag]')])
106+
);
136107

137108
consoleSpy.mockRestore();
138109
});
139-
140-
it('should store object as extra arg (not "[object Object]")', async () => {
141-
const [{ logger, logsStorage }] = withSetup(() => useDiagnosticsLogger());
142-
143-
const payload = { userId: 'u1', synced: true };
144-
await logger.log('User is logged in', payload);
145-
146-
await new Promise((resolve) => setTimeout(resolve, 150));
147-
148-
const allKeys = await logsStorage.getKeys();
149-
const logKeys = allKeys.filter((key: string) => key.startsWith('log:'));
150-
expect(logKeys.length).toBeGreaterThan(0);
151-
152-
const storedLog = (await logsStorage.getItem(logKeys[0])) as { args?: unknown[] } | null;
153-
const args = storedLog?.args;
154-
expect(args).toBeDefined();
155-
expect(args?.length).toBeGreaterThanOrEqual(2);
156-
expect(args?.[1]).toEqual(payload);
157-
expect(args?.[1]).not.toBe('[object Object]');
158-
});
159-
160-
it('should configure logger with DEBUG level', () => {
161-
const [{ logger }] = withSetup(() => useDiagnosticsLogger());
162-
163-
expect(logger.getLevel()).toBe(LogLevel.DEBUG);
164-
});
165110
});

0 commit comments

Comments
 (0)