chore: move from esm to cjs before upstreaming (#986)

This commit is contained in:
Pavel Feldman
2025-09-03 08:00:58 -07:00
committed by GitHub
parent 8d86ce4958
commit 2461f32d05
92 changed files with 250 additions and 259 deletions

2
cli.js
View File

@@ -15,4 +15,4 @@
* limitations under the License.
*/
import './lib/program.js';
require('./lib/program');

View File

@@ -14,16 +14,12 @@
* limitations under the License.
*/
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import notice from "eslint-plugin-notice";
import path from "path";
import { fileURLToPath } from "url";
import stylistic from "@stylistic/eslint-plugin";
import importRules from "eslint-plugin-import";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const typescriptEslint = require("@typescript-eslint/eslint-plugin");
const tsParser = require("@typescript-eslint/parser");
const notice = require("eslint-plugin-notice");
const path = require("path");
const stylistic = require("@stylistic/eslint-plugin");
const importRules = require("eslint-plugin-import");
const plugins = {
"@stylistic": stylistic,
@@ -32,8 +28,7 @@ const plugins = {
import: importRules,
};
export const baseRules = {
"import/extensions": ["error", "ignorePackages", {ts: "always"}],
const baseRules = {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-unused-vars": [
2,
@@ -188,7 +183,7 @@ const languageOptions = {
ecmaVersion: 9,
sourceType: "module",
parserOptions: {
project: path.join(fileURLToPath(import.meta.url), "..", "tsconfig.all.json"),
project: path.join(__filename, "..", "tsconfig.all.json"),
}
};
@@ -217,7 +212,7 @@ const noBooleanCompareRules = {
"@typescript-eslint/no-unnecessary-boolean-literal-compare": 2,
};
export default [
module.exports = [
{
ignores: ["**/*.js"],
},

View File

@@ -14,7 +14,7 @@
"<all_urls>"
],
"background": {
"service_worker": "lib/background.js",
"service_worker": "lib/background.mjs",
"type": "module"
},
"action": {

View File

@@ -2,7 +2,6 @@
"name": "@playwright/mcp-extension",
"version": "0.0.36",
"description": "Playwright MCP Browser Extension",
"type": "module",
"private": true,
"repository": {
"type": "git",
@@ -17,8 +16,8 @@
},
"license": "Apache-2.0",
"scripts": {
"build": "tsc --project . && tsc --project tsconfig.ui.json && vite build",
"watch": "tsc --watch --project . & tsc --watch --project tsconfig.ui.json & vite build --watch",
"build": "tsc --project . && tsc --project tsconfig.ui.json && vite build && vite build --config vite.sw.config.mts",
"watch": "tsc --watch --project . & tsc --watch --project tsconfig.ui.json & vite build --watch & vite build --watch --config vite.sw.config.mts",
"test": "playwright test",
"clean": "rm -rf dist"
},

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { RelayConnection, debugLog } from './relayConnection.js';
import { RelayConnection, debugLog } from './relayConnection';
type PageMessage = {
type: 'connectToMCPRelay';

View File

@@ -16,7 +16,6 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { chromium } from 'playwright';
import { test as base, expect } from '../../tests/fixtures.js';
@@ -38,7 +37,7 @@ type TestFixtures = {
const test = base.extend<TestFixtures>({
pathToExtension: async ({}, use) => {
await use(fileURLToPath(new URL('../dist', import.meta.url)));
await use(path.resolve(__dirname, '../dist'));
},
browserWithExtension: async ({ mcpBrowser, pathToExtension }, use, testInfo) => {
@@ -126,7 +125,7 @@ async function startWithExtensionFlag(browserWithExtension: BrowserWithExtension
const testWithOldExtensionVersion = test.extend({
pathToExtension: async ({}, use, testInfo) => {
const extensionDir = testInfo.outputPath('extension');
const oldPath = fileURLToPath(new URL('../dist', import.meta.url));
const oldPath = path.resolve(__dirname, '../dist');
await fs.promises.cp(oldPath, extensionDir, { recursive: true });
const manifestPath = path.join(extensionDir, 'manifest.json');

View File

@@ -10,7 +10,8 @@
"resolveJsonModule": true,
"types": ["chrome"],
"jsx": "react-jsx",
"jsxImportSource": "react"
"jsxImportSource": "react",
"noEmit": true
},
"include": [
"src",

View File

@@ -0,0 +1,31 @@
/**
* 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 { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/background.ts'),
fileName: 'lib/background',
formats: ['es']
},
outDir: 'dist',
emptyOutDir: false,
minify: false
}
});

2
index.d.ts vendored
View File

@@ -16,7 +16,7 @@
*/
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
import type { Config } from './config.js';
import type { Config } from './config';
import type { BrowserContext } from 'playwright';
export declare function createConnection(config?: Config, contextGetter?: () => Promise<BrowserContext>): Promise<Server>;

View File

@@ -15,5 +15,5 @@
* limitations under the License.
*/
import { createConnection } from './lib/index.js';
export { createConnection };
const { createConnection } = require('./lib/index.js');
module.exports = { createConnection };

View File

@@ -2,7 +2,6 @@
"name": "@playwright/mcp",
"version": "0.0.36",
"description": "Playwright Tools for MCP",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/microsoft/playwright-mcp.git"

View File

@@ -16,7 +16,7 @@
import { defineConfig } from '@playwright/test';
import type { TestOptions } from './tests/fixtures.js';
import type { TestOptions } from './tests/fixtures';
export default defineConfig<TestOptions>({
testDir: './tests',

View File

@@ -23,11 +23,11 @@ import * as playwright from 'playwright';
import { registryDirectory } from 'playwright-core/lib/server/registry/index';
// @ts-ignore
import { startTraceViewerServer } from 'playwright-core/lib/server';
import { logUnhandledError, testDebug } from './utils/log.js';
import { createHash } from './utils/guid.js';
import { outputFile } from './config.js';
import { logUnhandledError, testDebug } from './utils/log';
import { createHash } from './utils/guid';
import { outputFile } from './config';
import type { FullConfig } from './config.js';
import type { FullConfig } from './config';
export function contextFactory(config: FullConfig): BrowserContextFactory {
if (config.browser.remoteEndpoint)

View File

@@ -15,18 +15,18 @@
*/
import { fileURLToPath } from 'url';
import { FullConfig } from './config.js';
import { Context } from './context.js';
import { logUnhandledError } from './utils/log.js';
import { Response } from './response.js';
import { SessionLog } from './sessionLog.js';
import { filteredTools } from './tools.js';
import { toMcpTool } from './mcp/tool.js';
import { FullConfig } from './config';
import { Context } from './context';
import { logUnhandledError } from './utils/log';
import { Response } from './response';
import { SessionLog } from './sessionLog';
import { filteredTools } from './tools';
import { toMcpTool } from './mcp/tool';
import type { Tool } from './tools/tool.js';
import type { BrowserContextFactory } from './browserContextFactory.js';
import type * as mcpServer from './mcp/server.js';
import type { ServerBackend } from './mcp/server.js';
import type { Tool } from './tools/tool';
import type { BrowserContextFactory } from './browserContextFactory';
import type * as mcpServer from './mcp/server';
import type { ServerBackend } from './mcp/server';
export class BrowserServerBackend implements ServerBackend {
private _tools: Tool[];

View File

@@ -18,7 +18,7 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import { devices } from 'playwright';
import { sanitizeForFilePath } from './utils/fileUtils.js';
import { sanitizeForFilePath } from './utils/fileUtils';
import type { Config, ToolCapability } from '../config.js';
import type { BrowserContextOptions, LaunchOptions } from 'playwright';

View File

@@ -17,15 +17,15 @@
import debug from 'debug';
import * as playwright from 'playwright';
import { logUnhandledError } from './utils/log.js';
import { Tab } from './tab.js';
import { outputFile } from './config.js';
import { logUnhandledError } from './utils/log';
import { Tab } from './tab';
import { outputFile } from './config';
import type { FullConfig } from './config.js';
import type { Tool } from './tools/tool.js';
import type { BrowserContextFactory, ClientInfo } from './browserContextFactory.js';
import type * as actions from './actions.js';
import type { SessionLog } from './sessionLog.js';
import type { FullConfig } from './config';
import type { Tool } from './tools/tool';
import type { BrowserContextFactory, ClientInfo } from './browserContextFactory';
import type * as actions from './actions';
import type { SessionLog } from './sessionLog';
const testDebug = debug('pw:mcp:test');

View File

@@ -26,17 +26,19 @@ import { spawn } from 'child_process';
import http from 'http';
import debug from 'debug';
import { WebSocket, WebSocketServer } from 'ws';
// @ts-ignore
import { registry } from 'playwright-core/lib/server/registry/index';
import { httpAddressToString } from '../mcp/http.js';
import { logUnhandledError } from '../utils/log.js';
import { ManualPromise } from '../mcp/manualPromise.js';
import * as protocol from './protocol.js';
import * as protocol from './protocol';
import type websocket from 'ws';
import type { ClientInfo } from '../browserContextFactory.js';
import type { ExtensionCommand, ExtensionEvents } from './protocol.js';
import type { ExtensionCommand, ExtensionEvents } from './protocol';
// @ts-ignore
const { registry } = await import('playwright-core/lib/server/registry/index');
const debugLogger = debug('pw:mcp:relay');

View File

@@ -17,7 +17,7 @@
import debug from 'debug';
import * as playwright from 'playwright';
import { startHttpServer } from '../mcp/http.js';
import { CDPRelayServer } from './cdpRelay.js';
import { CDPRelayServer } from './cdpRelay';
import type { BrowserContextFactory, ClientInfo } from '../browserContextFactory.js';

View File

@@ -14,15 +14,15 @@
* limitations under the License.
*/
import { BrowserServerBackend } from './browserServerBackend.js';
import { resolveConfig } from './config.js';
import { contextFactory } from './browserContextFactory.js';
import * as mcpServer from './mcp/server.js';
import { packageJSON } from './utils/package.js';
import { BrowserServerBackend } from './browserServerBackend';
import { resolveConfig } from './config';
import { contextFactory } from './browserContextFactory';
import * as mcpServer from './mcp/server';
import { packageJSON } from './utils/package';
import type { Config } from '../config.js';
import type { BrowserContext } from 'playwright';
import type { BrowserContextFactory } from './browserContextFactory.js';
import type { BrowserContextFactory } from './browserContextFactory';
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
export async function createConnection(userConfig: Config = {}, contextGetter?: () => Promise<BrowserContext>): Promise<Server> {

View File

@@ -15,7 +15,7 @@
*/
import type Anthropic from '@anthropic-ai/sdk';
import type { LLMDelegate, LLMConversation, LLMToolCall, LLMTool } from './loop.js';
import type { LLMDelegate, LLMConversation, LLMToolCall, LLMTool } from './loop';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
const model = 'claude-sonnet-4-20250514';
@@ -26,7 +26,7 @@ export class ClaudeDelegate implements LLMDelegate {
async anthropic(): Promise<Anthropic> {
if (!this._anthropic) {
const anthropic = await import('@anthropic-ai/sdk');
this._anthropic = new anthropic.Anthropic();
this._anthropic = new anthropic.Anthropic() as unknown as Anthropic;
}
return this._anthropic;
}

View File

@@ -15,7 +15,7 @@
*/
import type OpenAI from 'openai';
import type { LLMDelegate, LLMConversation, LLMToolCall, LLMTool } from './loop.js';
import type { LLMDelegate, LLMConversation, LLMToolCall, LLMTool } from './loop';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
const model = 'gpt-4.1';
@@ -26,7 +26,7 @@ export class OpenAIDelegate implements LLMDelegate {
async openai(): Promise<OpenAI> {
if (!this._openai) {
const oai = await import('openai');
this._openai = new oai.OpenAI();
this._openai = new oai.OpenAI() as unknown as OpenAI;
}
return this._openai;
}

View File

@@ -17,28 +17,25 @@
/* eslint-disable no-console */
import path from 'path';
import url from 'url';
import dotenv from 'dotenv';
import { program } from 'commander';
import * as mcpBundle from '../mcp/bundle.js';
import { OpenAIDelegate } from './loopOpenAI.js';
import { ClaudeDelegate } from './loopClaude.js';
import { runTask } from './loop.js';
import { OpenAIDelegate } from './loopOpenAI';
import { ClaudeDelegate } from './loopClaude';
import { runTask } from './loop';
import type { LLMDelegate } from './loop.js';
import type { LLMDelegate } from './loop';
dotenv.config();
const __filename = url.fileURLToPath(import.meta.url);
async function run(delegate: LLMDelegate) {
const transport = new mcpBundle.StdioClientTransport({
command: 'node',
args: [
path.resolve(__filename, '../../../cli.js'),
path.resolve(__dirname, '../../cli.js'),
'--save-session',
'--output-dir', path.resolve(__filename, '../../../sessions')
'--output-dir', path.resolve(__dirname, '../../sessions')
],
stderr: 'inherit',
env: process.env as Record<string, string>,

View File

@@ -18,14 +18,14 @@ import dotenv from 'dotenv';
import * as mcpServer from '../mcp/server.js';
import { packageJSON } from '../utils/package.js';
import { Context } from './context.js';
import { perform } from './perform.js';
import { snapshot } from './snapshot.js';
import { Context } from './context';
import { perform } from './perform';
import { snapshot } from './snapshot';
import { toMcpTool } from '../mcp/tool.js';
import type { FullConfig } from '../config.js';
import type { ServerBackend } from '../mcp/server.js';
import type { Tool } from './tool.js';
import type { Tool } from './tool';
export async function runLoopTools(config: FullConfig) {
dotenv.config();

View File

@@ -16,7 +16,7 @@
import type { z } from 'zod';
import type * as mcpServer from '../mcp/server.js';
import type { Context } from './context.js';
import type { Context } from './context';
import type { ToolSchema } from '../mcp/tool.js';

View File

@@ -21,10 +21,10 @@ import crypto from 'crypto';
import debug from 'debug';
import * as mcpBundle from './bundle.js';
import * as mcpServer from './server.js';
import * as mcpBundle from './bundle';
import * as mcpServer from './server';
import type { ServerBackendFactory } from './server.js';
import type { ServerBackendFactory } from './server';
import type { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import type { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

View File

@@ -16,12 +16,12 @@
import debug from 'debug';
import { defineToolSchema } from './tool.js';
import * as mcpBundle from './bundle.js';
import * as mcpServer from './server.js';
import * as mcpHttp from './http.js';
import { wrapInProcess } from './server.js';
import { ManualPromise } from './manualPromise.js';
import { defineToolSchema } from './tool';
import * as mcpBundle from './bundle';
import * as mcpServer from './server';
import * as mcpHttp from './http';
import { wrapInProcess } from './server';
import { ManualPromise } from './manualPromise';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';

View File

@@ -16,9 +16,9 @@
import debug from 'debug';
import * as mcpBundle from './bundle.js';
import * as mcpBundle from './bundle';
import type { ServerBackend, ClientVersion, Root, Server } from './server.js';
import type { ServerBackend, ClientVersion, Root, Server } from './server';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
import type { Tool, CallToolResult, CallToolRequest } from '@modelcontextprotocol/sdk/types.js';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';

View File

@@ -16,9 +16,9 @@
import debug from 'debug';
import * as mcpBundle from './bundle.js';
import { httpAddressToString, installHttpTransport, startHttpServer } from './http.js';
import { InProcessTransport } from './inProcessTransport.js';
import * as mcpBundle from './bundle';
import { httpAddressToString, installHttpTransport, startHttpServer } from './http';
import { InProcessTransport } from './inProcessTransport';
import type { Tool, CallToolResult, CallToolRequest, Root } from '@modelcontextprotocol/sdk/types.js';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';

View File

@@ -17,7 +17,7 @@
import { zodToJsonSchema } from '../mcp/bundle.js';
import type { z } from 'zod';
import type * as mcpServer from './server.js';
import type * as mcpServer from './server';
export type ToolSchema<Input extends z.Schema> = {
name: string;

View File

@@ -15,18 +15,18 @@
*/
import { program, Option } from 'commander';
import * as mcpServer from './mcp/server.js';
import { commaSeparatedList, resolveCLIConfig, semicolonSeparatedList } from './config.js';
import { packageJSON } from './utils/package.js';
import { Context } from './context.js';
import { contextFactory } from './browserContextFactory.js';
import { runLoopTools } from './loopTools/main.js';
import { ProxyBackend } from './mcp/proxyBackend.js';
import { BrowserServerBackend } from './browserServerBackend.js';
import { ExtensionContextFactory } from './extension/extensionContextFactory.js';
import * as mcpServer from './mcp/server';
import { commaSeparatedList, resolveCLIConfig, semicolonSeparatedList } from './config';
import { packageJSON } from './utils/package';
import { Context } from './context';
import { contextFactory } from './browserContextFactory';
import { runLoopTools } from './loopTools/main';
import { ProxyBackend } from './mcp/proxyBackend';
import { BrowserServerBackend } from './browserServerBackend';
import { ExtensionContextFactory } from './extension/extensionContextFactory';
import { runVSCodeTools } from './vscode/host.js';
import type { MCPProvider } from './mcp/proxyBackend.js';
import { runVSCodeTools } from './vscode/host';
import type { MCPProvider } from './mcp/proxyBackend';
program
.version('Version ' + packageJSON.version)

View File

@@ -14,11 +14,11 @@
* limitations under the License.
*/
import { renderModalStates } from './tab.js';
import { renderModalStates } from './tab';
import type { Tab, TabSnapshot } from './tab.js';
import type { Tab, TabSnapshot } from './tab';
import type { ImageContent, TextContent } from '@modelcontextprotocol/sdk/types.js';
import type { Context } from './context.js';
import type { Context } from './context';
export class Response {
private _result: string[] = [];

View File

@@ -17,13 +17,13 @@
import fs from 'fs';
import path from 'path';
import { Response } from './response.js';
import { logUnhandledError } from './utils/log.js';
import { outputFile } from './config.js';
import { Response } from './response';
import { logUnhandledError } from './utils/log';
import { outputFile } from './config';
import type { FullConfig } from './config.js';
import type * as actions from './actions.js';
import type { Tab, TabSnapshot } from './tab.js';
import type { FullConfig } from './config';
import type * as actions from './actions';
import type { Tab, TabSnapshot } from './tab';
type LogEntry = {
timestamp: number;

View File

@@ -16,12 +16,12 @@
import { EventEmitter } from 'events';
import * as playwright from 'playwright';
import { callOnPageNoTrace, waitForCompletion } from './tools/utils.js';
import { logUnhandledError } from './utils/log.js';
import { ManualPromise } from './mcp/manualPromise.js';
import { ModalState } from './tools/tool.js';
import { callOnPageNoTrace, waitForCompletion } from './tools/utils';
import { logUnhandledError } from './utils/log';
import { ManualPromise } from './mcp/manualPromise';
import { ModalState } from './tools/tool';
import type { Context } from './context.js';
import type { Context } from './context';
type PageEx = playwright.Page & {
_snapshotForAI: () => Promise<string>;

View File

@@ -14,26 +14,26 @@
* limitations under the License.
*/
import common from './tools/common.js';
import console from './tools/console.js';
import dialogs from './tools/dialogs.js';
import evaluate from './tools/evaluate.js';
import files from './tools/files.js';
import form from './tools/form.js';
import install from './tools/install.js';
import keyboard from './tools/keyboard.js';
import mouse from './tools/mouse.js';
import navigate from './tools/navigate.js';
import network from './tools/network.js';
import pdf from './tools/pdf.js';
import snapshot from './tools/snapshot.js';
import tabs from './tools/tabs.js';
import screenshot from './tools/screenshot.js';
import wait from './tools/wait.js';
import verify from './tools/verify.js';
import common from './tools/common';
import console from './tools/console';
import dialogs from './tools/dialogs';
import evaluate from './tools/evaluate';
import files from './tools/files';
import form from './tools/form';
import install from './tools/install';
import keyboard from './tools/keyboard';
import mouse from './tools/mouse';
import navigate from './tools/navigate';
import network from './tools/network';
import pdf from './tools/pdf';
import snapshot from './tools/snapshot';
import tabs from './tools/tabs';
import screenshot from './tools/screenshot';
import wait from './tools/wait';
import verify from './tools/verify';
import type { Tool } from './tools/tool.js';
import type { FullConfig } from './config.js';
import type { Tool } from './tools/tool';
import type { FullConfig } from './config';
export const allTools: Tool<any>[] = [
...common,

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool, defineTool } from './tool.js';
import { defineTabTool, defineTool } from './tool';
const close = defineTool({
capability: 'core',

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
const console = defineTabTool({
capability: 'core',

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
const handleDialog = defineTabTool({
capability: 'core',

View File

@@ -15,9 +15,9 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import { generateLocator } from './utils';
import type * as playwright from 'playwright';

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
const uploadFile = defineTabTool({
capability: 'core',

View File

@@ -15,8 +15,8 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { generateLocator } from './utils.js';
import { defineTabTool } from './tool';
import { generateLocator } from './utils';
import * as javascript from '../utils/codegen.js';
const fillForm = defineTabTool({

View File

@@ -16,10 +16,9 @@
import { fork } from 'child_process';
import path from 'path';
import url from 'url';
import { z } from '../mcp/bundle.js';
import { defineTool } from './tool.js';
import { defineTool } from './tool';
const install = defineTool({
capability: 'core-install',
@@ -33,8 +32,7 @@ const install = defineTool({
handle: async (context, params, response) => {
const channel = context.config.browser?.launchOptions?.channel ?? context.config.browser?.browserName ?? 'chrome';
const cliUrl = import.meta.resolve('playwright/package.json');
const cliPath = path.join(url.fileURLToPath(cliUrl), '..', 'cli.js');
const cliPath = path.join(require.resolve('playwright/package.json'), '../cli.js');
const child = fork(cliPath, ['install', channel], {
stdio: 'pipe',
});

View File

@@ -15,9 +15,9 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { elementSchema } from './snapshot.js';
import { generateLocator } from './utils.js';
import { defineTabTool } from './tool';
import { elementSchema } from './snapshot';
import { generateLocator } from './utils';
import * as javascript from '../utils/codegen.js';
const pressKey = defineTabTool({

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
const elementSchema = z.object({
element: z.string().describe('Human-readable element description used to obtain permission to interact with the element'),

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTool, defineTabTool } from './tool.js';
import { defineTool, defineTabTool } from './tool';
const navigate = defineTool({
capability: 'core',

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
import type * as playwright from 'playwright';

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
import * as javascript from '../utils/codegen.js';
const pdfSchema = z.object({

View File

@@ -15,9 +15,9 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import { generateLocator } from './utils';
import type * as playwright from 'playwright';

View File

@@ -15,9 +15,9 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool, defineTool } from './tool.js';
import { defineTabTool, defineTool } from './tool';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import { generateLocator } from './utils';
const snapshot = defineTool({
capability: 'core',

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTool } from './tool.js';
import { defineTool } from './tool';
const browserTabs = defineTool({
capability: 'core-tabs',

View File

@@ -15,9 +15,9 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTabTool } from './tool.js';
import { defineTabTool } from './tool';
import * as javascript from '../utils/codegen.js';
import { generateLocator } from './utils.js';
import { generateLocator } from './utils';
const verifyElement = defineTabTool({
capability: 'verify',

View File

@@ -15,7 +15,7 @@
*/
import { z } from '../mcp/bundle.js';
import { defineTool } from './tool.js';
import { defineTool } from './tool';
const wait = defineTool({
capability: 'core',

View File

@@ -16,7 +16,5 @@
import fs from 'fs';
import path from 'path';
import url from 'url';
const __filename = url.fileURLToPath(import.meta.url);
export const packageJSON = JSON.parse(fs.readFileSync(path.join(path.dirname(__filename), '..', '..', 'package.json'), 'utf8'));
export const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf8'));

View File

@@ -14,7 +14,6 @@
* limitations under the License.
*/
import url from 'url';
import path from 'path';
import * as mcpBundle from '../mcp/bundle.js';
@@ -137,7 +136,7 @@ class VSCodeProxyBackend implements ServerBackend {
command: process.execPath,
cwd: process.cwd(),
args: [
path.join(url.fileURLToPath(import.meta.url), '..', 'main.js'),
path.join(__dirname, 'main.js'),
JSON.stringify(this._config),
params.connectionString,
params.lib,

View File

@@ -69,8 +69,10 @@ async function main(config: FullConfig, connectionString: string, lib: string) {
);
}
await main(
JSON.parse(process.argv[2]),
process.argv[3],
process.argv[4]
);
void (async () => {
await main(
JSON.parse(process.argv[2]),
process.argv[3],
process.argv[4]
);
})();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('test snapshot tool list', async ({ client }) => {
const { tools } = await client.listTools();

View File

@@ -14,10 +14,9 @@
* limitations under the License.
*/
import url from 'node:url';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('cdp server', async ({ cdpServer, startClient, server }) => {
await cdpServer.start();
@@ -84,9 +83,6 @@ test('should throw connection error and allow re-connecting', async ({ cdpServer
});
});
// 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', '--cdp-endpoint=http://localhost:1234',

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_click', async ({ client, server, mcpBrowser }) => {
server.setContent('/', `

View File

@@ -17,7 +17,7 @@
import fs from 'node:fs';
import { Config } from '../config.js';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('config user data dir', async ({ startClient, server, mcpMode }, testInfo) => {
server.setContent('/', `

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_console_messages', async ({ client, server }) => {
server.setContent('/', `

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_navigate', async ({ client, server }) => {
expect(await client.callTool({

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('--device should work', async ({ startClient, server, mcpMode }) => {
const { client } = await startClient({

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('alert dialog', async ({ client, server }) => {
server.setContent('/', `<button onclick="alert('Alert')">Button</button>`, 'text/html');

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_evaluate', async ({ client, server }) => {
expect(await client.callTool({

View File

@@ -15,7 +15,7 @@
*/
import fs from 'fs/promises';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_file_upload', async ({ client, server }, testInfo) => {
server.setContent('/', `

View File

@@ -15,7 +15,6 @@
*/
import fs from 'fs';
import url from 'url';
import path from 'path';
import { chromium } from 'playwright';
@@ -23,7 +22,7 @@ import { test as baseTest, expect as baseExpect } from '@playwright/test';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { ListRootsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { TestServer } from './testserver/index.ts';
import { TestServer } from './testserver/index';
import type { Config } from '../config';
import type { BrowserContext } from 'playwright';
@@ -186,8 +185,6 @@ async function createTransport(args: string[], mcpMode: TestOptions['mcpMode'],
transport: Transport,
stderr: Stream | null,
}> {
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
const __filename = url.fileURLToPath(import.meta.url);
if (mcpMode === 'docker') {
const dockerArgs = ['run', '--rm', '-i', '--network=host', '-v', `${test.info().project.outputDir}:/app/test-results`];
const transport = new StdioClientTransport({
@@ -202,7 +199,7 @@ async function createTransport(args: string[], mcpMode: TestOptions['mcpMode'],
const transport = new StdioClientTransport({
command: 'node',
args: [path.join(path.dirname(__filename), '../cli.js'), ...args],
args: [path.join(__dirname, '../cli.js'), ...args],
cwd: path.dirname(test.info().config.configFile!),
stderr: 'pipe',
env: {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_fill_form (textbox)', async ({ client, server }) => {
server.setContent('/', `

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
for (const mcpHeadless of [false, true]) {
test.describe(`mcpHeadless: ${mcpHeadless}`, () => {

View File

@@ -14,20 +14,16 @@
* limitations under the License.
*/
import fs from 'node:fs';
import url from 'node:url';
import fs from 'fs';
import { ChildProcess, spawn } from 'node:child_process';
import path from 'node:path';
import { ChildProcess, spawn } from 'child_process';
import path from 'path';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { test as baseTest, expect } from './fixtures.js';
import { test as baseTest, expect } from './fixtures';
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);
const test = baseTest.extend<{ serverEndpoint: (options?: { args?: string[], noPort?: boolean }) => Promise<{ url: URL, stderr: () => string }> }>({
serverEndpoint: async ({ mcpHeadless }, use, testInfo) => {
let cp: ChildProcess | undefined;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('stitched aria frames', async ({ client }) => {
expect(await client.callTool({

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_install', async ({ client, mcpBrowser }) => {
test.skip(mcpBrowser !== 'chromium', 'Test only chromium');

View File

@@ -16,7 +16,7 @@
import fs from 'fs';
import { test, expect, formatOutput } from './fixtures.js';
import { test, expect, formatOutput } from './fixtures';
test('test reopen browser', async ({ startClient, server, mcpMode }) => {
const { client, stderr } = await startClient();

View File

@@ -15,7 +15,7 @@
*/
import child_process from 'child_process';
import fs from 'fs/promises';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('library can be used from CommonJS', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/456' } }, async ({}, testInfo) => {
const file = testInfo.outputPath('main.cjs');

View File

@@ -21,7 +21,7 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/
import { runMainBackend, runOnPauseBackendLoop } from '../src/mcp/mdb.js';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
import type * as mcpServer from '../src/mcp/server.js';
import type { ServerBackendOnPause } from '../src/mcp/mdb.js';

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_network_requests', async ({ client, server }) => {
server.setContent('/', `

View File

@@ -16,7 +16,7 @@
import fs from 'fs';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('save as pdf unavailable', async ({ startClient, server }) => {
const { client } = await startClient();

View File

@@ -18,7 +18,7 @@ import fs from 'fs';
import path from 'path';
import { pathToFileURL } from 'url';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
import { createHash } from '../src/utils/guid.js';
const p = process.platform === 'win32' ? 'c:\\non\\existent\\folder' : '/non/existent/folder';

View File

@@ -16,7 +16,7 @@
import fs from 'fs';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_take_screenshot (viewport)', async ({ startClient, server }, testInfo) => {
const { client } = await startClient({

View File

@@ -17,7 +17,7 @@
import fs from 'fs';
import path from 'path';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('session log should record tool calls', async ({ startClient, server }, testInfo) => {
const { client, stderr } = await startClient({

View File

@@ -14,20 +14,16 @@
* limitations under the License.
*/
import fs from 'node:fs';
import url from 'node:url';
import fs from 'fs';
import { ChildProcess, spawn } from 'node:child_process';
import path from 'node:path';
import { ChildProcess, spawn } from 'child_process';
import path from 'path';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { test as baseTest, expect } from './fixtures.js';
import { test as baseTest, expect } from './fixtures';
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);
const test = baseTest.extend<{ serverEndpoint: (options?: { args?: string[], noPort?: boolean }) => Promise<{ url: URL, stderr: () => string }> }>({
serverEndpoint: async ({ mcpHeadless }, use, testInfo) => {
let cp: ChildProcess | undefined;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';

View File

@@ -16,7 +16,6 @@
*/
import fs from 'fs';
import url from 'node:url';
import http from 'http';
import https from 'https';
import path from 'path';
@@ -25,9 +24,6 @@ import debug from 'debug';
const fulfillSymbol = Symbol('fulfil callback');
const rejectSymbol = Symbol('reject callback');
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
const __filename = url.fileURLToPath(import.meta.url);
export class TestServer {
private _server: http.Server;
readonly debugServer: any;

View File

@@ -16,7 +16,7 @@
import fs from 'fs';
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('check that trace is saved', async ({ startClient, server, mcpMode }, testInfo) => {
const outputDir = testInfo.outputPath('output');

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_type', async ({ client, server }) => {
server.setContent('/', `

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test.use({ mcpArgs: ['--caps=verify'] });

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_connect(vscode) works', async ({ startClient, playwright, browserName }) => {
const { client } = await startClient({
@@ -27,7 +27,7 @@ test('browser_connect(vscode) works', async ({ startClient, playwright, browserN
name: 'browser_connect',
arguments: {
connectionString: server.wsEndpoint(),
lib: import.meta.resolve('playwright'),
lib: require.resolve('playwright'),
}
})).toHaveResponse({
result: 'Successfully connected.'

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('browser_wait_for(text)', async ({ client, server }) => {
server.setContent('/', `

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import { test, expect } from './fixtures';
test('do not falsely advertise user agent as a test driver', async ({ client, server, mcpBrowser }) => {
test.skip(mcpBrowser === 'firefox');

View File

@@ -1,10 +1,9 @@
{
"compilerOptions": {
"target": "ESNext",
"target": "ES2019",
"esModuleInterop": true,
"moduleResolution": "nodenext",
"strict": true,
"module": "NodeNext",
"module": "commonjs",
"rootDir": "src",
"outDir": "./lib",
"resolveJsonModule": true

View File

@@ -18,13 +18,10 @@
// @ts-check
import fs from 'fs';
import ts from 'typescript';
import path from 'path';
import Module from 'module';
const __dirname = path.dirname(new URL(import.meta.url).pathname);
const require = Module.createRequire(import.meta.url);
const fs = require('fs');
const ts = require('typescript');
const path = require('path');
const Module = require('module');
const builtins = new Set(Module.builtinModules);

View File

@@ -22,8 +22,6 @@ import path from 'path';
import child_process from 'child_process';
import { argv } from 'process';
const __dirname = path.dirname(new URL(import.meta.url).pathname);
const readJSON = async (filePath) => JSON.parse(await fs.promises.readFile(filePath, 'utf8'));
const writeJSON = async (filePath, json) => {
await fs.promises.writeFile(filePath, JSON.stringify(json, null, 2) + '\n');

View File

@@ -16,13 +16,12 @@
*/
// @ts-check
import fs from 'node:fs'
import path from 'node:path'
import url from 'node:url'
import zodToJsonSchema from 'zod-to-json-schema'
import { execSync } from 'node:child_process';
const fs = require('fs')
const path = require('path')
const { zodToJsonSchema } = require('zod-to-json-schema')
const { execSync } = require('child_process');
import { allTools } from '../lib/tools.js';
const { allTools } = require('../lib/tools.js');
const capabilities = {
'core': 'Core automation',
@@ -35,11 +34,8 @@ const capabilities = {
const toolsByCapability = Object.fromEntries(Object.entries(capabilities).map(([capability, title]) => [title, allTools.filter(tool => tool.capability === capability).sort((a, b) => a.schema.name.localeCompare(b.schema.name))]));
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
const __filename = url.fileURLToPath(import.meta.url);
/**
* @param {import('../src/tools/tool.js').ToolSchema<any>} tool
* @param {import('../src/mcp/tool.js').ToolSchema<any>} tool
* @returns {string[]}
*/
function formatToolForReadme(tool) {