chore: remove extension code (#667)
This commit is contained in:
@@ -19,8 +19,6 @@ import path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
test.skip(({ mcpMode }) => mcpMode === 'extension', 'Connecting to CDP server is not supported in combination with --extension');
|
||||
|
||||
test('cdp server', async ({ cdpServer, startClient, server }) => {
|
||||
await cdpServer.start();
|
||||
const { client } = await startClient({ args: [`--cdp-endpoint=${cdpServer.endpoint}`] });
|
||||
|
||||
@@ -20,7 +20,6 @@ import { Config } from '../config.js';
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
test('config user data dir', async ({ startClient, server, mcpMode }, testInfo) => {
|
||||
test.skip(mcpMode === 'extension', 'Connecting to CDP server does not use user data dir');
|
||||
server.setContent('/', `
|
||||
<title>Title</title>
|
||||
<body>Hello, world!</body>
|
||||
@@ -47,7 +46,6 @@ test('config user data dir', async ({ startClient, server, mcpMode }, testInfo)
|
||||
test.describe(() => {
|
||||
test.use({ mcpBrowser: '' });
|
||||
test('browserName', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/458' } }, async ({ startClient, mcpMode }, testInfo) => {
|
||||
test.skip(mcpMode === 'extension', 'Extension mode only supports Chromium');
|
||||
const config: Config = {
|
||||
browser: {
|
||||
browserName: 'firefox',
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
test('--device should work', async ({ startClient, server, mcpMode }) => {
|
||||
test.skip(mcpMode === 'extension', 'Viewport is not supported when connecting via CDP. There we re-use the browser viewport.');
|
||||
const { client } = await startClient({
|
||||
args: ['--device', 'iPhone 15'],
|
||||
});
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import url from 'url';
|
||||
import path from 'path';
|
||||
import { spawnSync } from 'child_process';
|
||||
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
import { createConnection } from '@playwright/mcp';
|
||||
|
||||
test.skip(({ mcpMode }) => mcpMode !== 'extension');
|
||||
|
||||
test('does not allow --cdp-endpoint', async ({ startClient }) => {
|
||||
await expect(createConnection({
|
||||
browser: { browserName: 'firefox' },
|
||||
...({ extension: true })
|
||||
})).rejects.toThrow(/Extension mode is only supported for Chromium browsers/);
|
||||
});
|
||||
|
||||
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
|
||||
test('does not support --device', async () => {
|
||||
const result = spawnSync('node', [
|
||||
path.join(__filename, '../../cli.js'), '--device=Pixel 5', '--extension',
|
||||
]);
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stderr.toString()).toContain('Device emulation is not supported with extension mode.');
|
||||
});
|
||||
@@ -95,7 +95,6 @@ The tool "browser_file_upload" can only be used when there is related modal stat
|
||||
});
|
||||
|
||||
test('clicking on download link emits download', async ({ startClient, server, mcpMode }, testInfo) => {
|
||||
test.fixme(mcpMode === 'extension', 'Downloads are on the Browser CDP domain and not supported with --extension');
|
||||
const { client } = await startClient({
|
||||
config: { outputDir: testInfo.outputPath('output') },
|
||||
});
|
||||
@@ -120,7 +119,6 @@ test('clicking on download link emits download', async ({ startClient, server, m
|
||||
});
|
||||
|
||||
test('navigating to download link emits download', async ({ startClient, server, mcpBrowser, mcpMode }, testInfo) => {
|
||||
test.fixme(mcpMode === 'extension', 'Downloads are on the Browser CDP domain and not supported with --extension');
|
||||
const { client } = await startClient({
|
||||
config: { outputDir: testInfo.outputPath('output') },
|
||||
});
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
import fs from 'fs';
|
||||
import url from 'url';
|
||||
import path from 'path';
|
||||
import net from 'net';
|
||||
import { chromium } from 'playwright';
|
||||
import { fork } from 'child_process';
|
||||
|
||||
import { test as baseTest, expect as baseExpect } from '@playwright/test';
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
||||
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { TestServer } from './testserver/index.ts';
|
||||
import { ManualPromise } from '../src/manualPromise.js';
|
||||
|
||||
import type { Config } from '../config';
|
||||
import type { BrowserContext } from 'playwright';
|
||||
@@ -35,7 +31,7 @@ import type { Stream } from 'stream';
|
||||
|
||||
export type TestOptions = {
|
||||
mcpBrowser: string | undefined;
|
||||
mcpMode: 'docker' | 'extension' | undefined;
|
||||
mcpMode: 'docker' | undefined;
|
||||
};
|
||||
|
||||
type CDPServer = {
|
||||
@@ -52,7 +48,6 @@ type TestFixtures = {
|
||||
server: TestServer;
|
||||
httpsServer: TestServer;
|
||||
mcpHeadless: boolean;
|
||||
startMcpExtension: (relayServerURL: string) => Promise<void>;
|
||||
};
|
||||
|
||||
type WorkerFixtures = {
|
||||
@@ -71,7 +66,7 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
|
||||
await use(client);
|
||||
},
|
||||
|
||||
startClient: async ({ mcpHeadless, mcpBrowser, mcpMode, startMcpExtension }, use, testInfo) => {
|
||||
startClient: async ({ mcpHeadless, mcpBrowser, mcpMode }, use, testInfo) => {
|
||||
const userDataDir = mcpMode !== 'docker' ? testInfo.outputPath('user-data-dir') : undefined;
|
||||
const configDir = path.dirname(test.info().config.configFile!);
|
||||
let client: Client | undefined;
|
||||
@@ -95,7 +90,7 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
|
||||
}
|
||||
|
||||
client = new Client({ name: options?.clientName ?? 'test', version: '1.0.0' });
|
||||
const { transport, stderr, relayServerURL } = await createTransport(args, mcpMode);
|
||||
const { transport, stderr } = await createTransport(args, mcpMode);
|
||||
let stderrBuffer = '';
|
||||
stderr?.on('data', data => {
|
||||
if (process.env.PWMCP_DEBUG)
|
||||
@@ -103,8 +98,6 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
|
||||
stderrBuffer += data.toString();
|
||||
});
|
||||
await client.connect(transport);
|
||||
if (mcpMode === 'extension')
|
||||
await startMcpExtension(relayServerURL!);
|
||||
await client.ping();
|
||||
return { client, stderr: () => stderrBuffer };
|
||||
});
|
||||
@@ -147,38 +140,6 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
|
||||
|
||||
mcpMode: [undefined, { option: true }],
|
||||
|
||||
startMcpExtension: async ({ mcpMode, mcpHeadless }, use) => {
|
||||
let context: BrowserContext | undefined;
|
||||
await use(async (relayServerURL: string) => {
|
||||
if (mcpMode !== 'extension')
|
||||
throw new Error('Must be running in MCP extension mode to use this fixture.');
|
||||
const cdpPort = await findFreePort();
|
||||
const pathToExtension = path.join(url.fileURLToPath(import.meta.url), '../../extension');
|
||||
context = await chromium.launchPersistentContext('', {
|
||||
headless: mcpHeadless,
|
||||
args: [
|
||||
`--disable-extensions-except=${pathToExtension}`,
|
||||
`--load-extension=${pathToExtension}`,
|
||||
'--enable-features=AllowContentInitiatedDataUrlNavigations',
|
||||
],
|
||||
channel: 'chromium',
|
||||
...{ assistantMode: true, cdpPort },
|
||||
});
|
||||
const popupPage = await context.newPage();
|
||||
const page = context.pages()[0];
|
||||
await page.bringToFront();
|
||||
// Do not auto dismiss dialogs.
|
||||
page.on('dialog', () => { });
|
||||
await expect.poll(() => context?.serviceWorkers()).toHaveLength(1);
|
||||
// Connect to the relay server.
|
||||
await popupPage.goto(new URL('/popup.html', context.serviceWorkers()[0].url()).toString());
|
||||
await popupPage.getByRole('textbox', { name: 'Bridge Server URL:' }).clear();
|
||||
await popupPage.getByRole('textbox', { name: 'Bridge Server URL:' }).fill(relayServerURL);
|
||||
await popupPage.getByRole('button', { name: 'Share This Tab' }).click();
|
||||
});
|
||||
await context?.close();
|
||||
},
|
||||
|
||||
_workerServers: [async ({ }, use, workerInfo) => {
|
||||
const port = 8907 + workerInfo.workerIndex * 4;
|
||||
const server = await TestServer.create(port);
|
||||
@@ -208,7 +169,6 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
|
||||
async function createTransport(args: string[], mcpMode: TestOptions['mcpMode']): Promise<{
|
||||
transport: Transport,
|
||||
stderr: Stream | null,
|
||||
relayServerURL?: string,
|
||||
}> {
|
||||
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
@@ -223,42 +183,6 @@ async function createTransport(args: string[], mcpMode: TestOptions['mcpMode']):
|
||||
stderr: transport.stderr,
|
||||
};
|
||||
}
|
||||
if (mcpMode === 'extension') {
|
||||
const relay = fork(path.join(__filename, '../../cli.js'), [...args, '--extension', '--port=0'], {
|
||||
stdio: 'pipe'
|
||||
});
|
||||
const cdpRelayServerReady = new ManualPromise<string>();
|
||||
const sseEndpointPromise = new ManualPromise<string>();
|
||||
let stderrBuffer = '';
|
||||
relay.stderr!.on('data', data => {
|
||||
stderrBuffer += data.toString();
|
||||
const match = stderrBuffer.match(/Listening on (http:\/\/.*)/);
|
||||
if (match)
|
||||
sseEndpointPromise.resolve(match[1].toString());
|
||||
const extensionMatch = stderrBuffer.match(/CDP relay server started on (ws:\/\/.*\/extension)/);
|
||||
if (extensionMatch)
|
||||
cdpRelayServerReady.resolve(extensionMatch[1].toString());
|
||||
});
|
||||
relay.on('exit', () => {
|
||||
sseEndpointPromise.reject(new Error(`Process exited`));
|
||||
cdpRelayServerReady.reject(new Error(`Process exited`));
|
||||
});
|
||||
const relayServerURL = await cdpRelayServerReady;
|
||||
const sseEndpoint = await sseEndpointPromise;
|
||||
|
||||
const transport = new SSEClientTransport(new URL(sseEndpoint));
|
||||
// We cannot just add transport.onclose here as Client.connect() overrides it.
|
||||
const origClose = transport.close;
|
||||
transport.close = async () => {
|
||||
await origClose.call(transport);
|
||||
relay.kill();
|
||||
};
|
||||
return {
|
||||
transport,
|
||||
stderr: relay.stderr!,
|
||||
relayServerURL,
|
||||
};
|
||||
}
|
||||
|
||||
const transport = new StdioClientTransport({
|
||||
command: 'node',
|
||||
@@ -332,17 +256,6 @@ export const expect = baseExpect.extend({
|
||||
},
|
||||
});
|
||||
|
||||
async function findFreePort(): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
server.listen(0, () => {
|
||||
const { port } = server.address() as net.AddressInfo;
|
||||
server.close(() => resolve(port));
|
||||
});
|
||||
server.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
export function formatOutput(output: string): string[] {
|
||||
return output.split('\n').map(line => line.replace(/^pw:mcp:test /, '').replace(/user data dir.*/, 'user data dir').trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import fs from 'fs';
|
||||
|
||||
import { test, expect, formatOutput } from './fixtures.js';
|
||||
|
||||
test.skip(({ mcpMode }) => mcpMode === 'extension', 'launch scenarios are not supported with --extension - the browser is already launched');
|
||||
|
||||
test('test reopen browser', async ({ startClient, server, mcpMode }) => {
|
||||
const { client, stderr } = await startClient();
|
||||
await client.callTool({
|
||||
|
||||
@@ -29,8 +29,6 @@ import type { Config } from '../config.d.ts';
|
||||
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
|
||||
baseTest.skip(({ mcpMode }) => mcpMode === 'extension', 'Extension tests run via SSE anyways');
|
||||
|
||||
const test = baseTest.extend<{ serverEndpoint: (options?: { args?: string[], noPort?: boolean }) => Promise<{ url: URL, stderr: () => string }> }>({
|
||||
serverEndpoint: async ({ mcpHeadless }, use, testInfo) => {
|
||||
let cp: ChildProcess | undefined;
|
||||
|
||||
@@ -27,8 +27,6 @@ async function createTab(client: Client, title: string, body: string) {
|
||||
});
|
||||
}
|
||||
|
||||
test.skip(({ mcpMode }) => mcpMode === 'extension', 'Multi-tab scenarios are not supported with --extension');
|
||||
|
||||
test('list initial tabs', async ({ client }) => {
|
||||
expect(await client.callTool({
|
||||
name: 'browser_tab_list',
|
||||
|
||||
@@ -20,8 +20,6 @@ import path from 'path';
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
test('check that trace is saved', async ({ startClient, server, mcpMode }, testInfo) => {
|
||||
test.fixme(mcpMode === 'extension', 'Tracing is not supported via CDP');
|
||||
|
||||
const outputDir = testInfo.outputPath('output');
|
||||
|
||||
const { client } = await startClient({
|
||||
|
||||
Reference in New Issue
Block a user