Files
opencli/src/browser.test.ts
T
jackwener 01b8b6b5bf refactor: fix 14 issues from deep code review
P0 Critical:
- #1 Fix double IIFE wrapping: unified wrapForEval() replaces
  normalizeEvaluateSource + ad-hoc wrap in page.evaluate()
- #2 Fix navigate race: check tab.status before addListener,
  reduced timeout 30s→15s

P1 Should Fix:
- #8 Remove unused permissions (scripting, host_permissions, content_scripts)
- #10 Add retry (3x, 500ms) + timeout (30s) to sendCommand()

P2 Cleanup:
- #3 Extract isWebUrl() to safely handle undefined tab.url
- #4 Sanitize maxDepth with Math.max/min bounds
- #6 Delete empty src/daemon/ directory
- #7 Remove dead createJsonRpcRequest + its test
- #9 Remove stale IIFE-mode comment
- #11 Validate body.id in daemon request handler
- #12 Guard ensureAttached: detach+re-attach on 'already attached'
- #14 Extract _tabOpt() helper (removes 13x spread duplication)
- #15 Add verbose warning for unsupported consoleMessages()

All 35 unit tests pass.
2026-03-19 16:21:17 +08:00

80 lines
2.5 KiB
TypeScript

import { afterEach, describe, it, expect, vi } from 'vitest';
import { PlaywrightMCP, __test__ } from './browser/index.js';
describe('browser helpers', () => {
it('extracts tab entries from string snapshots', () => {
const entries = __test__.extractTabEntries('Tab 0 https://example.com\nTab 1 Chrome Extension');
expect(entries).toEqual([
{ index: 0, identity: 'https://example.com' },
{ index: 1, identity: 'Chrome Extension' },
]);
});
it('extracts tab entries from MCP markdown format', () => {
const entries = __test__.extractTabEntries(
'- 0: (current) [Playwright MCP extension](chrome-extension://abc/connect.html)\n- 1: [知乎 - 首页](https://www.zhihu.com/)'
);
expect(entries).toEqual([
{ index: 0, identity: '(current) [Playwright MCP extension](chrome-extension://abc/connect.html)' },
{ index: 1, identity: '[知乎 - 首页](https://www.zhihu.com/)' },
]);
});
it('closes only tabs that were opened during the session', () => {
const tabsToClose = __test__.diffTabIndexes(
['https://example.com', 'Chrome Extension'],
[
{ index: 0, identity: 'https://example.com' },
{ index: 1, identity: 'Chrome Extension' },
{ index: 2, identity: 'https://target.example/page' },
{ index: 3, identity: 'chrome-extension://bridge' },
],
);
expect(tabsToClose).toEqual([3, 2]);
});
it('keeps only the tail of stderr buffers', () => {
expect(__test__.appendLimited('12345', '67890', 8)).toBe('34567890');
});
it('times out slow promises', async () => {
await expect(__test__.withTimeoutMs(new Promise(() => {}), 10, 'timeout')).rejects.toThrow('timeout');
});
});
describe('PlaywrightMCP state', () => {
it('transitions to closed after close()', async () => {
const mcp = new PlaywrightMCP();
expect(mcp.state).toBe('idle');
await mcp.close();
expect(mcp.state).toBe('closed');
});
it('rejects connect() after the session has been closed', async () => {
const mcp = new PlaywrightMCP();
await mcp.close();
await expect(mcp.connect()).rejects.toThrow('Session is closed');
});
it('rejects connect() while already connecting', async () => {
const mcp = new PlaywrightMCP();
(mcp as any)._state = 'connecting';
await expect(mcp.connect()).rejects.toThrow('Already connecting');
});
it('rejects connect() while closing', async () => {
const mcp = new PlaywrightMCP();
(mcp as any)._state = 'closing';
await expect(mcp.connect()).rejects.toThrow('Session is closing');
});
});