Improve remote Matrix token refresh

This commit is contained in:
jjbrunton committed 2026-08-08 14:30:40 +01:00
1 parent b9df8459e3
commit bffda95251
6 files changed
+226 -14

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
import { describe, expect, it, vi } from 'vitest';
import type { BrowserContext } from 'playwright';
import { createMockLogger } from './mockLogger.js';
import {
MatrixRemoteLoginRequiredError,
MatrixTokenRefresher,
} from '../src/services/chat/matrix/token-refresher.js';
import type { MatrixCredentials } from '../src/services/chat/matrix/types.js';
const credentials: MatrixCredentials = {
homeserver: 'https://matrix.redditspace.com',
accessToken: 'fresh-token',
userId: '@t2_bot:reddit.com',
capturedAt: 123,
};
function setup(options: { sessionValid?: boolean; loginSucceeds?: boolean } = {}) {
const context = {} as BrowserContext;
const browser = {
getContext: vi.fn(() => context),
isSessionValid: vi.fn(async () => options.sessionValid ?? true),
login: vi.fn(async () => options.loginSucceeds ?? true),
};
const extract = vi.fn(async () => credentials);
const applyCredentials = vi.fn();
const logger = createMockLogger();
const refresher = new MatrixTokenRefresher(
browser,
logger,
applyCredentials,
extract,
);
return { refresher, browser, context, extract, applyCredentials, logger };
}
describe('MatrixTokenRefresher', () => {
it('repairs an expired Reddit browser session before capturing a Matrix token', async () => {
const { refresher, browser, context, extract, applyCredentials } = setup({
sessionValid: false,
loginSucceeds: true,
});
await refresher.refresh();
expect(browser.login).toHaveBeenCalledOnce();
expect(extract).toHaveBeenCalledWith(context, expect.anything());
expect(applyCredentials).toHaveBeenCalledWith(credentials);
});
it('fails fast with remote-login guidance when the Reddit session cannot be restored', async () => {
const { refresher, browser, extract } = setup({
sessionValid: false,
loginSucceeds: false,
});
await expect(refresher.refresh()).rejects.toBeInstanceOf(MatrixRemoteLoginRequiredError);
await expect(refresher.refresh()).rejects.toThrow(/dashboard.*noVNC/i);
expect(browser.login).toHaveBeenCalledTimes(2);
expect(extract).not.toHaveBeenCalled();
});
it('coalesces concurrent refreshes so only one browser capture runs', async () => {
const { refresher, extract, applyCredentials } = setup();
let release: ((value: MatrixCredentials) => void) | undefined;
extract.mockImplementation(
() => new Promise<MatrixCredentials>((resolve) => { release = resolve; }),
);
const first = refresher.refresh();
const second = refresher.refresh();
await vi.waitFor(() => expect(extract).toHaveBeenCalledOnce());
release?.(credentials);
await Promise.all([first, second]);
expect(applyCredentials).toHaveBeenCalledOnce();
});
});