Use full Chrome for interactive Reddit login
This commit is contained in:
1 parent
70d62b2da3
commit
674cd89cd7
5 files changed
+241
-3
No files matched your search
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -22,4 +22,25 @@ describe('VNC container entrypoint', () => {
|
||||
expect(script).toContain('"${BROWSER_SESSION_DIR}/SingletonCookie"');
|
||||
expect(script.indexOf('SingletonLock')).toBeLessThan(script.indexOf('launching bot'));
|
||||
});
|
||||
|
||||
it('launches regular Google Chrome before the bot and exposes its local CDP endpoint', () => {
|
||||
const script = fs.readFileSync(path.resolve('docker/entrypoint.sh'), 'utf8');
|
||||
|
||||
expect(script).toContain('google-chrome');
|
||||
expect(script).toContain('--user-data-dir="${BROWSER_SESSION_DIR}"');
|
||||
expect(script).toContain('--remote-debugging-port="${CHROME_CDP_PORT}"');
|
||||
expect(script).toContain('export CHROME_CDP_URL=');
|
||||
expect(script).not.toContain('--enable-automation');
|
||||
expect(script.indexOf('starting Google Chrome')).toBeLessThan(
|
||||
script.indexOf('launching bot'),
|
||||
);
|
||||
});
|
||||
|
||||
it('installs the stable Google Chrome package rather than Chrome for Testing', () => {
|
||||
const dockerfile = fs.readFileSync(path.resolve('Dockerfile'), 'utf8');
|
||||
|
||||
expect(dockerfile).toContain('google-chrome-stable_current_amd64.deb');
|
||||
expect(dockerfile).toContain('google-chrome-stable');
|
||||
expect(dockerfile).not.toContain('chrome-for-testing');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user