From 33276bfbdbe352c3dbe9de7d40218fadc3b9cdc9 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 24 Feb 2026 12:44:26 +0000 Subject: [PATCH 1/3] Add `assertNotLogged` test helper --- src/testing-utils.ts | 48 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/testing-utils.ts b/src/testing-utils.ts index 3abc1f4f4c..5f0bb607b2 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -245,6 +245,32 @@ export function getRecordingLogger( }; } +/** + * Checks whether `messages` contains `messageOrRegExp`. + * + * If `messageOrRegExp` is a string, this function returns true as long as + * `messageOrRegExp` appears as part of one of the `messages`. + * + * If `messageOrRegExp` is a regular expression, this function returns true as long as + * one of the `messages` matches `messageOrRegExp`. + */ +function hasLoggedMessage( + messages: LoggedMessage[], + messageOrRegExp: string | RegExp, +): boolean { + const check = (val: string) => + typeof messageOrRegExp === "string" + ? val.includes(messageOrRegExp) + : messageOrRegExp.test(val); + + return messages.some( + (msg) => typeof msg.message === "string" && check(msg.message), + ); +} + +/** + * Checks that `messages` contains all of `expectedMessages`. + */ export function checkExpectedLogMessages( t: ExecutionContext, messages: LoggedMessage[], @@ -253,13 +279,7 @@ export function checkExpectedLogMessages( const missingMessages: string[] = []; for (const expectedMessage of expectedMessages) { - if ( - !messages.some( - (msg) => - typeof msg.message === "string" && - msg.message.includes(expectedMessage), - ) - ) { + if (!hasLoggedMessage(messages, expectedMessage)) { missingMessages.push(expectedMessage); } } @@ -276,6 +296,20 @@ export function checkExpectedLogMessages( } } +/** + * Asserts that `message` should not have been logged to `logger`. + */ +export function assertNotLogged( + t: ExecutionContext, + logger: RecordingLogger, + message: string | RegExp, +) { + t.false( + hasLoggedMessage(logger.messages, message), + `'${message}' should not have been logged, but was.`, + ); +} + /** * Initialises a recording logger and calls `body` with it. * From 33edb83959ae626c8409fc93b5f72839719edfc7 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 24 Feb 2026 20:40:41 +0000 Subject: [PATCH 2/3] Replace `getRecordingLogger` implementation with `RecordingLogger` --- src/testing-utils.ts | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/testing-utils.ts b/src/testing-utils.ts index 5f0bb607b2..d2a2e4857f 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -210,39 +210,9 @@ export function getRecordingLogger( messages: LoggedMessage[], { logToConsole }: { logToConsole?: boolean } = { logToConsole: true }, ): Logger { - return { - debug: (message: string) => { - messages.push({ type: "debug", message }); - if (logToConsole) { - // eslint-disable-next-line no-console - console.debug(message); - } - }, - info: (message: string) => { - messages.push({ type: "info", message }); - if (logToConsole) { - // eslint-disable-next-line no-console - console.info(message); - } - }, - warning: (message: string | Error) => { - messages.push({ type: "warning", message }); - if (logToConsole) { - // eslint-disable-next-line no-console - console.warn(message); - } - }, - error: (message: string | Error) => { - messages.push({ type: "error", message }); - if (logToConsole) { - // eslint-disable-next-line no-console - console.error(message); - } - }, - isDebug: () => true, - startGroup: () => undefined, - endGroup: () => undefined, - }; + const logger = new RecordingLogger(logToConsole); + logger.messages = messages; + return logger; } /** From f56d0ec51b3334931a297a8c64e0ce9751d4b9c9 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 24 Feb 2026 20:45:41 +0000 Subject: [PATCH 3/3] Add `hasMessage` to `RecordingLogger` --- src/testing-utils.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/testing-utils.ts b/src/testing-utils.ts index d2a2e4857f..11cc21c064 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -157,8 +157,8 @@ export interface LoggedMessage { export class RecordingLogger implements Logger { messages: LoggedMessage[] = []; - groups: string[] = []; - unfinishedGroups: Set = new Set(); + readonly groups: string[] = []; + readonly unfinishedGroups: Set = new Set(); private currentGroup: string | undefined = undefined; constructor(private readonly logToConsole: boolean = true) {} @@ -172,6 +172,19 @@ export class RecordingLogger implements Logger { } } + /** + * Checks whether the logged messages contain `messageOrRegExp`. + * + * If `messageOrRegExp` is a string, this function returns true as long as + * `messageOrRegExp` appears as part of one of the `messages`. + * + * If `messageOrRegExp` is a regular expression, this function returns true as long as + * one of the `messages` matches `messageOrRegExp`. + */ + hasMessage(messageOrRegExp: string | RegExp): boolean { + return hasLoggedMessage(this.messages, messageOrRegExp); + } + isDebug() { return true; } @@ -275,7 +288,7 @@ export function assertNotLogged( message: string | RegExp, ) { t.false( - hasLoggedMessage(logger.messages, message), + logger.hasMessage(message), `'${message}' should not have been logged, but was.`, ); }