From f09ec2cf2648e8287fb5f4bbd445f34bd117ad13 Mon Sep 17 00:00:00 2001
From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Date: Wed, 18 Oct 2023 11:52:07 +0100
Subject: [PATCH] Cypress: distinguish logs from bot clients (#11770)
When we instantiate a `MatrixClient` for a "bot" user, give it a custom
`Logger` which will add a prefix to any logs written by that client.
---
cypress/support/bot.ts | 50 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts
index c1e1e9221b..4273b65a23 100644
--- a/cypress/support/bot.ts
+++ b/cypress/support/bot.ts
@@ -16,13 +16,16 @@ limitations under the License.
///
+import * as loglevel from "loglevel";
+
import type { ISendEventResponse, MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import type { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
import type { AddSecretStorageKeyOpts } from "matrix-js-sdk/src/secret-storage";
import { HomeserverInstance } from "../plugins/utils/homeserver";
import { Credentials } from "./homeserver";
-import Chainable = Cypress.Chainable;
import { collapseLastLogGroup } from "./log";
+import type { Logger } from "matrix-js-sdk/src/logger";
+import Chainable = Cypress.Chainable;
interface CreateBotOpts {
/**
@@ -140,6 +143,8 @@ function setupBotClient(
// extra timeout, as this sometimes takes a while
{ timeout: 30_000 },
async (win): Promise => {
+ const logger = getLogger(win, `cypress bot ${credentials.userId}`);
+
const keys = {};
const getCrossSigningKey = (type: string) => {
@@ -176,6 +181,7 @@ function setupBotClient(
store: new win.matrixcs.MemoryStore(),
scheduler: new win.matrixcs.MatrixScheduler(),
cryptoStore: new win.matrixcs.MemoryCryptoStore(),
+ logger: logger,
cryptoCallbacks,
});
@@ -323,3 +329,45 @@ Cypress.Commands.add(
);
},
);
+
+/** Get a Logger implementation based on `loglevel` with the given logger name */
+function getLogger(win: Cypress.AUTWindow, loggerName: string): Logger {
+ const logger = loglevel.getLogger(loggerName);
+
+ // If this is the first time this logger has been returned, turn it into a `Logger` and set the default level
+ if (!("extend" in logger)) {
+ logger["extend"] = (namespace: string) => getLogger(win, loggerName + ":" + namespace);
+ logger.methodFactory = makeLogMethodFactory(win);
+ logger.setLevel(loglevel.levels.DEBUG);
+ }
+
+ return logger as unknown as Logger;
+}
+
+/**
+ * Helper for getLogger: a factory for loglevel method factories.
+ */
+function makeLogMethodFactory(win: Cypress.AUTWindow): loglevel.MethodFactory {
+ function methodFactory(
+ methodName: loglevel.LogLevelNames,
+ level: loglevel.LogLevelNumbers,
+ loggerName: string | symbol,
+ ): loglevel.LoggingMethod {
+ // here's the actual log method, which implements `Logger.info`, `Logger.debug`, etc.
+ return function (first: any, ...rest): void {
+ // include the logger name in the output...
+ first = `\x1B[31m[${loggerName.toString()}]\x1B[m ${first.toString()}`;
+
+ // ... and delegate to the corresponding method in the console of the application under test.
+ // Doing so (rather than using the global `console`) ensures that the output is collected
+ // by the `cypress-terminal-report` plugin.
+ const console = win.console;
+ if (methodName in console) {
+ console[methodName](first, ...rest);
+ } else {
+ console.log(first, ...rest);
+ }
+ };
+ }
+ return methodFactory;
+}