Use full Chrome for interactive Reddit login

This commit is contained in:
jjbrunton committed 2026-08-08 15:30:24 +01:00
1 parent 70d62b2da3
commit 674cd89cd7
5 files changed
+241 -3

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import type { BrowserContext, Page } from 'playwright';
import {
BrowserClient,
type BrowserRuntime,
type ConnectedBrowser,
} from '../src/browser/client.js';
import type { Logger } from '../src/utils/logger.js';
import { getTestConfig } from './testUtils.js';
function createLogger(): Logger {
return {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
} as unknown as Logger;
}
afterEach(() => {
delete process.env.CHROME_CDP_URL;
});
describe('BrowserClient external Chrome', () => {
it('attaches to independently launched Chrome before considering Playwright launch', async () => {
process.env.CHROME_CDP_URL = 'http://127.0.0.1:9222';
const context = { pages: () => [] } as unknown as BrowserContext;
const connectedBrowser = {
contexts: () => [context],
close: vi.fn(),
} as unknown as ConnectedBrowser;
const runtime: BrowserRuntime = {
connectOverCDP: vi.fn().mockResolvedValue(connectedBrowser),
launchPersistentContext: vi.fn(),
};
const client = new BrowserClient(getTestConfig(), createLogger(), runtime);
const result = await client.initialize();
expect(result).toBe(context);
expect(runtime.connectOverCDP).toHaveBeenCalledWith('http://127.0.0.1:9222');
expect(runtime.launchPersistentContext).not.toHaveBeenCalled();
});
it('falls back to Playwright only when external Chrome cannot be reached', async () => {
process.env.CHROME_CDP_URL = 'http://127.0.0.1:9222';
const fallbackContext = { pages: () => [] } as unknown as BrowserContext;
const runtime: BrowserRuntime = {
connectOverCDP: vi.fn().mockRejectedValue(new Error('connection refused')),
launchPersistentContext: vi.fn().mockResolvedValue(fallbackContext),
};
const client = new BrowserClient(getTestConfig(), createLogger(), runtime);
const result = await client.initialize();
expect(result).toBe(fallbackContext);
expect(runtime.launchPersistentContext).toHaveBeenCalledOnce();
});
it('opens the login page for a human without submitting credentials', async () => {
process.env.CHROME_CDP_URL = 'http://127.0.0.1:9222';
const page = {
goto: vi.fn().mockResolvedValue(undefined),
bringToFront: vi.fn().mockResolvedValue(undefined),
fill: vi.fn(),
} as unknown as Page;
const context = { pages: () => [page] } as unknown as BrowserContext;
const runtime: BrowserRuntime = {
connectOverCDP: vi.fn().mockResolvedValue({
contexts: () => [context],
close: vi.fn(),
}),
launchPersistentContext: vi.fn(),
};
const client = new BrowserClient(getTestConfig({
reddit: { username: 'human', password: 'secret' },
}), createLogger(), runtime);
await client.initialize();
await expect(client.login()).resolves.toBe(false);
expect(page.bringToFront).toHaveBeenCalledOnce();
expect(page.goto).toHaveBeenCalledWith(
'https://www.reddit.com/login',
{ waitUntil: 'domcontentloaded' },
);
expect(page.fill).not.toHaveBeenCalled();
expect(client.getSessionState()).toBe('login-required');
});
});