import { afterEach, beforeEach, describe, expect, it, vi } from
"vitest" ;
import { installMatrixTestRuntime } from
"../test-runtime.js" ;
import type { CoreConfig } from
"../types.js" ;
import {
backfillMatrixAuthDeviceIdAfterStartup,
resolveMatrixAuth,
setMatrixAuthClientDepsForTest,
} from
"./client/config.js" ;
import * as credentialsReadModule from
"./credentials-read.js" ;
const saveMatrixCredentialsMock = vi.hoisted(() => vi.fn());
const saveBackfilledMatrixDeviceIdMock = vi.hoisted(() => vi.fn(async () =>
"saved" ));
const touchMatrixCredentialsMock = vi.hoisted(() => vi.fn());
const repairCurrentTokenStorageMetaDeviceIdMock = vi.hoisted(() => vi.fn());
const resolveConfiguredSecretInputStringMock = vi.hoisted(() => vi.fn());
vi.mock(
"./credentials-read.js" , () => ({
loadMatrixCredentials: vi.fn(() =>
null ),
credentialsMatchConfig: vi.fn(() =>
false ),
}));
vi.mock(
"./credentials-write.runtime.js" , () => ({
saveBackfilledMatrixDeviceId: saveBackfilledMatrixDeviceIdMock,
saveMatrixCredentials: saveMatrixCredentialsMock,
touchMatrixCredentials: touchMatrixCredentialsMock,
}));
vi.mock(
"./client/storage.js" , async () => {
const actual = await vi.importActual<
typeof import (
"./client/storage.js" )>(
"./client/storage.js" );
return {
...actual,
repairCurrentTokenStorageMetaDeviceId: repairCurrentTokenStorageMetaDeviceIdMock,
};
});
vi.mock(
"./client/config-secret-input.runtime.js" , () => ({
resolveConfiguredSecretInputString: resolveConfiguredSecretInputStringMock,
}));
const ensureMatrixSdkLoggingConfiguredMock = vi.fn();
const matrixDoRequestMock = vi.fn();
class MockMatrixClient {
async doRequest(...args: unknown[]) {
return await matrixDoRequestMock(...args);
}
}
describe(
"resolveMatrixAuth" , () => {
beforeEach(() => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReset();
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue(
null );
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReset();
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(
false );
saveMatrixCredentialsMock.mockReset();
saveBackfilledMatrixDeviceIdMock.mockReset().mockResolvedValue(
"saved" );
touchMatrixCredentialsMock.mockReset();
repairCurrentTokenStorageMetaDeviceIdMock.mockReset().mockReturnValue(
true );
resolveConfiguredSecretInputStringMock.mockReset().mockResolvedValue({});
ensureMatrixSdkLoggingConfiguredMock.mockReset();
matrixDoRequestMock.mockReset();
setMatrixAuthClientDepsForTest({
MatrixClient: MockMatrixClient as unknown as
typeof import (
"./sdk.js" ).MatrixClient,
ensureMatrixSdkLoggingConfigured: ensureMatrixSdkLoggingConfiguredMock,
retryMinDelayMs:
0 ,
});
});
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
setMatrixAuthClientDepsForTest(undefined);
});
it(
"uses the hardened client request path for password login and persists deviceId" , async ()
=> {
matrixDoRequestMock.mockResolvedValue({
access_token: "tok-123" ,
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "secret" , // pragma: allowlist secret
encryption: true ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith(
"POST" ,
"/_matrix/client/v3/login" ,
undefined,
expect.objectContaining({
type: "m.login.password" ,
}),
);
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
encryption: true ,
});
expect(saveMatrixCredentialsMock).toHaveBeenCalledWith(
expect.objectContaining({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
}),
expect.any(Object),
"default" ,
);
});
it("surfaces password login errors when account credentials are invalid" , async () => {
matrixDoRequestMock.mockRejectedValueOnce(new Error("Invalid username or password" ));
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "secret" , // pragma: allowlist secret
},
},
} as CoreConfig;
await expect(
resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
}),
).rejects.toThrow("Invalid username or password" );
expect(matrixDoRequestMock).toHaveBeenCalledWith(
"POST" ,
"/_matrix/client/v3/login" ,
undefined,
expect.objectContaining({
type: "m.login.password" ,
}),
);
expect(saveMatrixCredentialsMock).not.toHaveBeenCalled();
});
it("uses cached matching credentials when access token is not configured" , async () => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "cached-token" ,
deviceId: "CACHEDDEVICE" ,
createdAt: "2026-01-01T00:00:00.000Z" ,
});
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(true );
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "secret" , // pragma: allowlist secret
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "cached-token" ,
deviceId: "CACHEDDEVICE" ,
});
expect(saveMatrixCredentialsMock).not.toHaveBeenCalled();
});
it("uses cached matching credentials for env-backed named accounts without fresh auth" , async () => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue({
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "cached-token" ,
deviceId: "CACHEDDEVICE" ,
createdAt: "2026-01-01T00:00:00.000Z" ,
});
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(true );
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
},
},
} as CoreConfig;
const env = {
MATRIX_OPS_USER_ID: "@ops:example.org" ,
} as NodeJS.ProcessEnv;
const auth = await resolveMatrixAuth({
cfg,
env,
accountId: "ops" ,
});
expect(auth).toMatchObject({
accountId: "ops" ,
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "cached-token" ,
deviceId: "CACHEDDEVICE" ,
});
expect(saveMatrixCredentialsMock).not.toHaveBeenCalled();
});
it("rejects embedded credentials in Matrix homeserver URLs" , async () => {
const cfg = {
channels: {
matrix: {
homeserver: "https://user:pass@matrix.example.org ",
accessToken: "tok-123" ,
},
},
} as CoreConfig;
await expect(resolveMatrixAuth({ cfg, env: {} as NodeJS.ProcessEnv })).rejects.toThrow(
"Matrix homeserver URL must not include embedded credentials" ,
);
});
it("falls back to config deviceId when cached credentials are missing it" , async () => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
createdAt: "2026-01-01T00:00:00.000Z" ,
});
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(true );
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
encryption: true ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({ cfg, env: {} as NodeJS.ProcessEnv });
expect(auth.deviceId).toBe("DEVICE123" );
expect(auth.accountId).toBe("default" );
expect(saveMatrixCredentialsMock).toHaveBeenCalledWith(
expect.objectContaining({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
}),
expect.any(Object),
"default" ,
);
});
it("carries the private-network opt-in through Matrix auth resolution" , async () => {
const cfg = {
channels: {
matrix: {
homeserver: "http://127.0.0.1:8008 ",
allowPrivateNetwork: true ,
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({ cfg, env: {} as NodeJS.ProcessEnv });
expect(auth).toMatchObject({
homeserver: "http://127.0.0.1:8008 ",
allowPrivateNetwork: true ,
ssrfPolicy: { allowPrivateNetwork: true },
});
});
it("resolves token-only non-default account userId from whoami instead of inheriting the base user" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@ops:example.org" ,
device_id: "OPSDEVICE" ,
});
const cfg = {
channels: {
matrix: {
userId: "@base:example.org" ,
homeserver: "https://matrix.example.org ",
accounts: {
ops: {
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
},
},
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
accountId: "ops" ,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET" , "/_matrix/client/v3/account/whoami" );
expect(auth.userId).toBe("@ops:example.org" );
expect(auth.deviceId).toBe("OPSDEVICE" );
});
it("uses named-account password auth instead of inheriting the base access token" , async () => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue(null );
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(false );
matrixDoRequestMock.mockResolvedValue({
access_token: "ops-token" ,
user_id: "@ops:example.org" ,
device_id: "OPSDEVICE" ,
});
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
accessToken: "legacy-token" ,
accounts: {
ops: {
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
password: "ops-pass" , // pragma: allowlist secret
},
},
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
accountId: "ops" ,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith(
"POST" ,
"/_matrix/client/v3/login" ,
undefined,
expect.objectContaining({
type: "m.login.password" ,
identifier: { type: "m.id.user" , user: "@ops:example.org" },
password: "ops-pass" ,
}),
);
expect(auth).toMatchObject({
accountId: "ops" ,
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
deviceId: "OPSDEVICE" ,
});
});
it("resolves missing whoami identity fields for token auth" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
accessToken: "tok-123" ,
encryption: true ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET" , "/_matrix/client/v3/account/whoami" );
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
encryption: true ,
});
});
it("retries token whoami when startup auth hits a transient network error" , async () => {
matrixDoRequestMock
.mockRejectedValueOnce(
Object.assign(new TypeError("fetch failed" ), {
cause: Object.assign(new Error("read ECONNRESET" ), {
code: "ECONNRESET" ,
}),
}),
)
.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
accessToken: "tok-123" ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).toHaveBeenCalledTimes(2 );
expect(auth).toMatchObject({
userId: "@bot:example.org" ,
deviceId: "DEVICE123" ,
});
});
it("does not call whoami when token auth already has a userId and only deviceId is missing" , async () => {
matrixDoRequestMock.mockRejectedValue(new Error("whoami should not be called" ));
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
encryption: true ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).not.toHaveBeenCalled();
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: undefined,
encryption: true ,
});
});
it("retries password login when startup auth hits a transient network error" , async () => {
matrixDoRequestMock
.mockRejectedValueOnce(
Object.assign(new TypeError("fetch failed" ), {
cause: Object.assign(new Error("socket hang up" ), {
code: "ECONNRESET" ,
}),
}),
)
.mockResolvedValue({
access_token: "tok-123" ,
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "secret" , // pragma: allowlist secret
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).toHaveBeenCalledTimes(2 );
expect(auth).toMatchObject({
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
});
});
it("best-effort backfills a missing deviceId after startup" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
const deviceId = await backfillMatrixAuthDeviceIdAfterStartup({
auth: {
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
},
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET" , "/_matrix/client/v3/account/whoami" );
expect(saveBackfilledMatrixDeviceIdMock).toHaveBeenCalledWith(
{
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
},
expect.any(Object),
"default" ,
);
expect(repairCurrentTokenStorageMetaDeviceIdMock).toHaveBeenCalledWith({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
accountId: "default" ,
deviceId: "DEVICE123" ,
env: expect.any(Object),
});
expect(repairCurrentTokenStorageMetaDeviceIdMock.mock.invocationCallOrder[0 ]).toBeLessThan(
saveBackfilledMatrixDeviceIdMock.mock.invocationCallOrder[0 ],
);
expect(deviceId).toBe("DEVICE123" );
});
it("skips deviceId backfill when auth already includes it" , async () => {
const deviceId = await backfillMatrixAuthDeviceIdAfterStartup({
auth: {
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
},
env: {} as NodeJS.ProcessEnv,
});
expect(matrixDoRequestMock).not.toHaveBeenCalled();
expect(saveMatrixCredentialsMock).not.toHaveBeenCalled();
expect(saveBackfilledMatrixDeviceIdMock).not.toHaveBeenCalled();
expect(repairCurrentTokenStorageMetaDeviceIdMock).not.toHaveBeenCalled();
expect(deviceId).toBe("DEVICE123" );
});
it("fails before saving repaired credentials when storage metadata repair fails" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
repairCurrentTokenStorageMetaDeviceIdMock.mockReturnValue(false );
await expect(
backfillMatrixAuthDeviceIdAfterStartup({
auth: {
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
},
env: {} as NodeJS.ProcessEnv,
}),
).rejects.toThrow("Matrix deviceId backfill failed to repair current-token storage metadata" );
expect(saveBackfilledMatrixDeviceIdMock).not.toHaveBeenCalled();
});
it("skips stale deviceId backfill writes after newer credentials take over" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-new" ,
deviceId: "DEVICE999" ,
createdAt: "2026-03-01T00:00:00.000Z" ,
});
const deviceId = await backfillMatrixAuthDeviceIdAfterStartup({
auth: {
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-old" ,
},
env: {} as NodeJS.ProcessEnv,
});
expect(deviceId).toBeUndefined();
expect(repairCurrentTokenStorageMetaDeviceIdMock).not.toHaveBeenCalled();
expect(saveBackfilledMatrixDeviceIdMock).not.toHaveBeenCalled();
});
it("skips persistence when startup backfill is aborted before whoami resolves" , async () => {
let resolveWhoami: ((value: { user_id: string; device_id: string }) => void ) | undefined;
matrixDoRequestMock.mockImplementation(
() =>
new Promise((resolve) => {
resolveWhoami = resolve;
}),
);
const abortController = new AbortController();
const backfillPromise = backfillMatrixAuthDeviceIdAfterStartup({
auth: {
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
},
env: {} as NodeJS.ProcessEnv,
abortSignal: abortController.signal,
});
await vi.waitFor(() => {
expect(resolveWhoami).toBeTypeOf("function" );
});
abortController.abort();
resolveWhoami?.({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
await expect(backfillPromise).resolves.toBeUndefined();
expect(repairCurrentTokenStorageMetaDeviceIdMock).not.toHaveBeenCalled();
expect(saveBackfilledMatrixDeviceIdMock).not.toHaveBeenCalled();
});
it("resolves configured accessToken SecretRefs during Matrix auth" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@bot:example.org" ,
device_id: "DEVICE123" ,
});
resolveConfiguredSecretInputStringMock.mockResolvedValue({ value: "resolved-token" });
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
accessToken: { source: "file" , provider: "matrix-file" , id: "value" },
},
},
secrets: {
providers: {
"matrix-file" : {
source: "file" ,
path: "/tmp/matrix-token.txt" ,
mode: "singleValue" ,
},
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({
cfg,
env: {} as NodeJS.ProcessEnv,
});
expect(resolveConfiguredSecretInputStringMock).toHaveBeenCalledWith(
expect.objectContaining({
config: cfg,
value: { source: "file" , provider: "matrix-file" , id: "value" },
path: "channels.matrix.accessToken" ,
}),
);
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET" , "/_matrix/client/v3/account/whoami" );
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "resolved-token" ,
deviceId: "DEVICE123" ,
});
});
it("does not resolve inactive password SecretRefs when scoped token auth wins" , async () => {
matrixDoRequestMock.mockResolvedValue({
user_id: "@ops:example.org" ,
device_id: "OPSDEVICE" ,
});
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: "https://matrix.example.org ",
password: { source: "env" , provider: "default" , id: "MATRIX_OPS_PASSWORD" },
},
},
},
},
secrets: {
defaults: {
env: "default" ,
},
},
} as CoreConfig;
installMatrixTestRuntime({ cfg });
const auth = await resolveMatrixAuth({
cfg,
env: {
MATRIX_OPS_ACCESS_TOKEN: "ops-token" ,
} as NodeJS.ProcessEnv,
accountId: "ops" ,
});
expect(matrixDoRequestMock).toHaveBeenCalledWith("GET" , "/_matrix/client/v3/account/whoami" );
expect(auth).toMatchObject({
accountId: "ops" ,
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
deviceId: "OPSDEVICE" ,
password: undefined,
});
});
it("uses config deviceId with cached credentials when token is loaded from cache" , async () => {
vi.mocked(credentialsReadModule.loadMatrixCredentials).mockReturnValue({
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
createdAt: "2026-01-01T00:00:00.000Z" ,
});
vi.mocked(credentialsReadModule.credentialsMatchConfig).mockReturnValue(true );
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
deviceId: "DEVICE123" ,
encryption: true ,
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({ cfg, env: {} as NodeJS.ProcessEnv });
expect(auth).toMatchObject({
accountId: "default" ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "tok-123" ,
deviceId: "DEVICE123" ,
encryption: true ,
});
});
it("falls back to the sole configured account when no global homeserver is set" , async () => {
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: "https://ops.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
deviceId: "OPSDEVICE" ,
encryption: true ,
},
},
},
},
} as CoreConfig;
const auth = await resolveMatrixAuth({ cfg, env: {} as NodeJS.ProcessEnv });
expect(auth).toMatchObject({
accountId: "ops" ,
homeserver: "https://ops.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
deviceId: "OPSDEVICE" ,
encryption: true ,
});
expect(saveMatrixCredentialsMock).toHaveBeenCalledWith(
expect.objectContaining({
homeserver: "https://ops.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
deviceId: "OPSDEVICE" ,
}),
expect.any(Object),
"ops" ,
);
});
});
Messung V0.5 in Prozent C=97 H=98 G=97
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland