feat(auth): implement user authentication system

This commit is contained in:
J.A.R.V.I.S. 2026-03-19 23:10:50 +00:00
parent 4847ab793a
commit 25cea4fbe8
12051 changed files with 1462377 additions and 0 deletions

View file

@ -0,0 +1,89 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var agentParser_exports = {};
__export(agentParser_exports, {
parseAgentSpec: () => parseAgentSpec
});
module.exports = __toCommonJS(agentParser_exports);
var import_fs = __toESM(require("fs"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
async function parseAgentSpec(filePath) {
const source = await import_fs.default.promises.readFile(filePath, "utf-8");
const { header, content } = extractYamlAndContent(source);
const { instructions, examples } = extractInstructionsAndExamples(content);
return {
...header,
instructions,
examples
};
}
function extractYamlAndContent(markdown) {
const lines = markdown.split("\n");
if (lines[0] !== "---")
throw new Error("Markdown file must start with YAML front matter (---)");
let yamlEndIndex = -1;
for (let i = 1; i < lines.length; i++) {
if (lines[i] === "---") {
yamlEndIndex = i;
break;
}
}
if (yamlEndIndex === -1)
throw new Error("YAML front matter must be closed with ---");
const yamlLines = lines.slice(1, yamlEndIndex);
const yamlRaw = yamlLines.join("\n");
const contentLines = lines.slice(yamlEndIndex + 1);
const content = contentLines.join("\n");
let header;
try {
header = import_utilsBundle.yaml.parse(yamlRaw);
} catch (error) {
throw new Error(`Failed to parse YAML header: ${error.message}`);
}
if (!header.name)
throw new Error('YAML header must contain a "name" field');
if (!header.description)
throw new Error('YAML header must contain a "description" field');
return { header, content };
}
function extractInstructionsAndExamples(content) {
const examples = [];
const instructions = content.split("<example>")[0].trim();
const exampleRegex = /<example>([\s\S]*?)<\/example>/g;
let match;
while ((match = exampleRegex.exec(content)) !== null) {
const example = match[1].trim();
examples.push(example.replace(/[\n]/g, " ").replace(/ +/g, " "));
}
return { instructions, examples };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
parseAgentSpec
});

View file

@ -0,0 +1,34 @@
name: "Copilot Setup Steps"
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
# Customize this step as needed
- name: Build application
run: npx run build

View file

@ -0,0 +1,348 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var generateAgents_exports = {};
__export(generateAgents_exports, {
ClaudeGenerator: () => ClaudeGenerator,
CopilotGenerator: () => CopilotGenerator,
OpencodeGenerator: () => OpencodeGenerator,
VSCodeGenerator: () => VSCodeGenerator
});
module.exports = __toCommonJS(generateAgents_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_utils = require("playwright-core/lib/utils");
var import_seed = require("../mcp/test/seed");
var import_agentParser = require("./agentParser");
async function loadAgentSpecs() {
const files = await import_fs.default.promises.readdir(__dirname);
return Promise.all(files.filter((file) => file.endsWith(".agent.md")).map((file) => (0, import_agentParser.parseAgentSpec)(import_path.default.join(__dirname, file))));
}
class ClaudeGenerator {
static async init(config, projectName, prompts) {
await initRepo(config, projectName, {
promptsFolder: prompts ? ".claude/prompts" : void 0
});
const agents = await loadAgentSpecs();
await import_fs.default.promises.mkdir(".claude/agents", { recursive: true });
for (const agent of agents)
await writeFile(`.claude/agents/${agent.name}.md`, ClaudeGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
await writeFile(".mcp.json", JSON.stringify({
mcpServers: {
"playwright-test": {
command: "npx",
args: ["playwright", "run-test-mcp-server"]
}
}
}, null, 2), "\u{1F527}", "mcp configuration");
initRepoDone();
}
static agentSpec(agent) {
const claudeToolMap = /* @__PURE__ */ new Map([
["search", ["Glob", "Grep", "Read", "LS"]],
["edit", ["Edit", "MultiEdit", "Write"]]
]);
function asClaudeTool(tool) {
const [first, second] = tool.split("/");
if (!second)
return (claudeToolMap.get(first) || [first]).join(", ");
return `mcp__${first}__${second}`;
}
const examples = agent.examples.length ? ` Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}` : "";
const lines = [];
const header = {
name: agent.name,
description: agent.description + examples,
tools: agent.tools.map((tool) => asClaudeTool(tool)).join(", "),
model: agent.model,
color: agent.color
};
lines.push(`---`);
lines.push(import_utilsBundle.yaml.stringify(header, { lineWidth: 1e5 }) + `---`);
lines.push("");
lines.push(agent.instructions);
return lines.join("\n");
}
}
class OpencodeGenerator {
static async init(config, projectName, prompts) {
await initRepo(config, projectName, {
defaultAgentName: "Build",
promptsFolder: prompts ? ".opencode/prompts" : void 0
});
const agents = await loadAgentSpecs();
for (const agent of agents) {
const prompt = [agent.instructions];
prompt.push("");
prompt.push(...agent.examples.map((example) => `<example>${example}</example>`));
await writeFile(`.opencode/prompts/${agent.name}.md`, prompt.join("\n"), "\u{1F916}", "agent definition");
}
await writeFile("opencode.json", OpencodeGenerator.configuration(agents), "\u{1F527}", "opencode configuration");
initRepoDone();
}
static configuration(agents) {
const opencodeToolMap = /* @__PURE__ */ new Map([
["search", ["ls", "glob", "grep", "read"]],
["edit", ["edit", "write"]]
]);
const asOpencodeTool = (tools, tool) => {
const [first, second] = tool.split("/");
if (!second) {
for (const tool2 of opencodeToolMap.get(first) || [first])
tools[tool2] = true;
} else {
tools[`${first}*${second}`] = true;
}
};
const result = {};
result["$schema"] = "https://opencode.ai/config.json";
result["mcp"] = {};
result["tools"] = {
"playwright*": false
};
result["agent"] = {};
for (const agent of agents) {
const tools = {};
result["agent"][agent.name] = {
description: agent.description,
mode: "subagent",
prompt: `{file:.opencode/prompts/${agent.name}.md}`,
tools
};
for (const tool of agent.tools)
asOpencodeTool(tools, tool);
}
result["mcp"]["playwright-test"] = {
type: "local",
command: ["npx", "playwright", "run-test-mcp-server"],
enabled: true
};
return JSON.stringify(result, null, 2);
}
}
class CopilotGenerator {
static async init(config, projectName, prompts) {
await initRepo(config, projectName, {
defaultAgentName: "agent",
promptsFolder: prompts ? ".github/prompts" : void 0,
promptSuffix: "prompt"
});
const agents = await loadAgentSpecs();
await import_fs.default.promises.mkdir(".github/agents", { recursive: true });
for (const agent of agents)
await writeFile(`.github/agents/${agent.name}.agent.md`, CopilotGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
await deleteFile(`.github/chatmodes/ \u{1F3AD} planner.chatmode.md`, "legacy planner chatmode");
await deleteFile(`.github/chatmodes/\u{1F3AD} generator.chatmode.md`, "legacy generator chatmode");
await deleteFile(`.github/chatmodes/\u{1F3AD} healer.chatmode.md`, "legacy healer chatmode");
await deleteFile(`.github/agents/ \u{1F3AD} planner.agent.md`, "legacy planner agent");
await deleteFile(`.github/agents/\u{1F3AD} generator.agent.md`, "legacy generator agent");
await deleteFile(`.github/agents/\u{1F3AD} healer.agent.md`, "legacy healer agent");
await VSCodeGenerator.appendToMCPJson();
const mcpConfig = { mcpServers: CopilotGenerator.mcpServers };
if (!import_fs.default.existsSync(".github/copilot-setup-steps.yml")) {
const yaml2 = import_fs.default.readFileSync(import_path.default.join(__dirname, "copilot-setup-steps.yml"), "utf-8");
await writeFile(".github/workflows/copilot-setup-steps.yml", yaml2, "\u{1F527}", "GitHub Copilot setup steps");
}
console.log("");
console.log("");
console.log(" \u{1F527} TODO: GitHub > Settings > Copilot > Coding agent > MCP configuration");
console.log("------------------------------------------------------------------");
console.log(JSON.stringify(mcpConfig, null, 2));
console.log("------------------------------------------------------------------");
initRepoDone();
}
static agentSpec(agent) {
const examples = agent.examples.length ? ` Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}` : "";
const lines = [];
const header = {
"name": agent.name,
"description": agent.description + examples,
"tools": agent.tools,
"model": "Claude Sonnet 4",
"mcp-servers": CopilotGenerator.mcpServers
};
lines.push(`---`);
lines.push(import_utilsBundle.yaml.stringify(header, { lineWidth: 1e5 }) + `---`);
lines.push("");
lines.push(agent.instructions);
lines.push("");
return lines.join("\n");
}
static {
this.mcpServers = {
"playwright-test": {
"type": "stdio",
"command": "npx",
"args": [
"playwright",
"run-test-mcp-server"
],
"tools": ["*"]
}
};
}
}
class VSCodeGenerator {
static async init(config, projectName) {
await initRepo(config, projectName, {
promptsFolder: void 0
});
const agents = await loadAgentSpecs();
const nameMap = /* @__PURE__ */ new Map([
["playwright-test-planner", " \u{1F3AD} planner"],
["playwright-test-generator", "\u{1F3AD} generator"],
["playwright-test-healer", "\u{1F3AD} healer"]
]);
await import_fs.default.promises.mkdir(".github/chatmodes", { recursive: true });
for (const agent of agents)
await writeFile(`.github/chatmodes/${nameMap.get(agent.name)}.chatmode.md`, VSCodeGenerator.agentSpec(agent), "\u{1F916}", "chatmode definition");
await VSCodeGenerator.appendToMCPJson();
initRepoDone();
}
static async appendToMCPJson() {
await import_fs.default.promises.mkdir(".vscode", { recursive: true });
const mcpJsonPath = ".vscode/mcp.json";
let mcpJson = {
servers: {},
inputs: []
};
try {
mcpJson = JSON.parse(import_fs.default.readFileSync(mcpJsonPath, "utf8"));
} catch {
}
if (!mcpJson.servers)
mcpJson.servers = {};
mcpJson.servers["playwright-test"] = {
type: "stdio",
command: "npx",
args: ["playwright", "run-test-mcp-server"]
};
await writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2), "\u{1F527}", "mcp configuration");
}
static agentSpec(agent) {
const vscodeToolMap = /* @__PURE__ */ new Map([
["search", ["search/listDirectory", "search/fileSearch", "search/textSearch"]],
["read", ["search/readFile"]],
["edit", ["edit/editFiles"]],
["write", ["edit/createFile", "edit/createDirectory"]]
]);
const vscodeToolsOrder = ["edit/createFile", "edit/createDirectory", "edit/editFiles", "search/fileSearch", "search/textSearch", "search/listDirectory", "search/readFile"];
const vscodeMcpName = "playwright-test";
function asVscodeTool(tool) {
const [first, second] = tool.split("/");
if (second)
return `${vscodeMcpName}/${second}`;
return vscodeToolMap.get(first) || first;
}
const tools = agent.tools.map(asVscodeTool).flat().sort((a, b) => {
const indexA = vscodeToolsOrder.indexOf(a);
const indexB = vscodeToolsOrder.indexOf(b);
if (indexA === -1 && indexB === -1)
return a.localeCompare(b);
if (indexA === -1)
return 1;
if (indexB === -1)
return -1;
return indexA - indexB;
}).map((tool) => `'${tool}'`).join(", ");
const lines = [];
lines.push(`---`);
lines.push(`description: ${agent.description}.`);
lines.push(`tools: [${tools}]`);
lines.push(`---`);
lines.push("");
lines.push(agent.instructions);
for (const example of agent.examples)
lines.push(`<example>${example}</example>`);
lines.push("");
return lines.join("\n");
}
}
async function writeFile(filePath, content, icon, description) {
console.log(` ${icon} ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
await (0, import_utils.mkdirIfNeeded)(filePath);
await import_fs.default.promises.writeFile(filePath, content, "utf-8");
}
async function deleteFile(filePath, description) {
try {
if (!import_fs.default.existsSync(filePath))
return;
} catch {
return;
}
console.log(` \u2702\uFE0F ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
await import_fs.default.promises.unlink(filePath);
}
async function initRepo(config, projectName, options) {
const project = (0, import_seed.seedProject)(config, projectName);
console.log(` \u{1F3AD} Using project "${project.project.name}" as a primary project`);
if (!import_fs.default.existsSync("specs")) {
await import_fs.default.promises.mkdir("specs");
await writeFile(import_path.default.join("specs", "README.md"), `# Specs
This is a directory for test plans.
`, "\u{1F4DD}", "directory for test plans");
}
let seedFile = await (0, import_seed.findSeedFile)(project);
if (!seedFile) {
seedFile = (0, import_seed.defaultSeedFile)(project);
await writeFile(seedFile, import_seed.seedFileContent, "\u{1F331}", "default environment seed file");
}
if (options.promptsFolder) {
await import_fs.default.promises.mkdir(options.promptsFolder, { recursive: true });
for (const promptFile of await import_fs.default.promises.readdir(__dirname)) {
if (!promptFile.endsWith(".prompt.md"))
continue;
const shortName = promptFile.replace(".prompt.md", "");
const fileName = options.promptSuffix ? `${shortName}.${options.promptSuffix}.md` : `${shortName}.md`;
const content = await loadPrompt(promptFile, {
defaultAgentName: "default",
...options,
seedFile: import_path.default.relative(process.cwd(), seedFile)
});
await writeFile(import_path.default.join(options.promptsFolder, fileName), content, "\u{1F4DD}", "prompt template");
}
}
}
function initRepoDone() {
console.log(" \u2705 Done.");
}
async function loadPrompt(file, params) {
const content = await import_fs.default.promises.readFile(import_path.default.join(__dirname, file), "utf-8");
return Object.entries(params).reduce((acc, [key, value]) => {
return acc.replace(new RegExp(`\\\${${key}}`, "g"), value);
}, content);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ClaudeGenerator,
CopilotGenerator,
OpencodeGenerator,
VSCodeGenerator
});

View file

@ -0,0 +1,31 @@
---
agent: ${defaultAgentName}
description: Produce test coverage
---
Parameters:
- Task: the task to perform
- Seed file (optional): the seed file to use, defaults to `${seedFile}`
- Test plan file (optional): the test plan file to write, under `specs/` folder.
1. Call #playwright-test-planner subagent with prompt:
<plan>
<task-text><!-- the task --></task-text>
<seed-file><!-- path to seed file --></seed-file>
<plan-file><!-- path to test plan file to generate --></plan-file>
</plan>
2. For each test case from the test plan file (1.1, 1.2, ...), one after another, not in parallel, call #playwright-test-generator subagent with prompt:
<generate>
<test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite>
<test-name><!-- Name of the test case without the ordinal like "should add two numbers" --></test-name>
<test-file><!-- Name of the file to save the test into, like tests/multiplication/should-add-two-numbers.spec.ts --></test-file>
<seed-file><!-- Seed file path from test plan --></seed-file>
<body><!-- Test case content including steps and expectations --></body>
</generate>
3. Call #playwright-test-healer subagent with prompt:
<heal>Run all tests and fix the failing ones one after another.</heal>

View file

@ -0,0 +1,8 @@
---
agent: playwright-test-generator
description: Generate test plan
---
Generate tests for the test plan's bullet 1.1 Add item to card.
Test plan: `specs/coverage.plan.md`

View file

@ -0,0 +1,88 @@
---
name: playwright-test-generator
description: Use this agent when you need to create automated browser tests using Playwright
model: sonnet
color: blue
tools:
- search
- playwright-test/browser_click
- playwright-test/browser_drag
- playwright-test/browser_evaluate
- playwright-test/browser_file_upload
- playwright-test/browser_handle_dialog
- playwright-test/browser_hover
- playwright-test/browser_navigate
- playwright-test/browser_press_key
- playwright-test/browser_select_option
- playwright-test/browser_snapshot
- playwright-test/browser_type
- playwright-test/browser_verify_element_visible
- playwright-test/browser_verify_list_visible
- playwright-test/browser_verify_text_visible
- playwright-test/browser_verify_value
- playwright-test/browser_wait_for
- playwright-test/generator_read_log
- playwright-test/generator_setup_page
- playwright-test/generator_write_test
---
You are a Playwright Test Generator, an expert in browser automation and end-to-end testing.
Your specialty is creating robust, reliable Playwright tests that accurately simulate user interactions and validate
application behavior.
# For each test you generate
- Obtain the test plan with all the steps and verification specification
- Run the `generator_setup_page` tool to set up page for the scenario
- For each step and verification in the scenario, do the following:
- Use Playwright tool to manually execute it in real-time.
- Use the step description as the intent for each Playwright tool call.
- Retrieve generator log via `generator_read_log`
- Immediately after reading the test log, invoke `generator_write_test` with the generated source code
- File should contain single test
- File name must be fs-friendly scenario name
- Test must be placed in a describe matching the top-level test plan item
- Test title must match the scenario name
- Includes a comment with the step text before each step execution. Do not duplicate comments if step requires
multiple actions.
- Always use best practices from the log when generating tests.
<example-generation>
For following plan:
```markdown file=specs/plan.md
### 1. Adding New Todos
**Seed:** `tests/seed.spec.ts`
#### 1.1 Add Valid Todo
**Steps:**
1. Click in the "What needs to be done?" input field
#### 1.2 Add Multiple Todos
...
```
Following file is generated:
```ts file=add-valid-todo.spec.ts
// spec: specs/plan.md
// seed: tests/seed.spec.ts
test.describe('Adding New Todos', () => {
test('Add Valid Todo', async { page } => {
// 1. Click in the "What needs to be done?" input field
await page.click(...);
...
});
});
```
</example-generation>
<example>
Context: User wants to generate a test for the test plan item.
<test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite>
<test-name><!-- Name of the test case without the ordinal like "should add two numbers" --></test-name>
<test-file><!-- Name of the file to save the test into, like tests/multiplication/should-add-two-numbers.spec.ts --></test-file>
<seed-file><!-- Seed file path from test plan --></seed-file>
<body><!-- Test case content including steps and expectations --></body>
</example>

View file

@ -0,0 +1,6 @@
---
agent: playwright-test-healer
description: Fix tests
---
Run all my tests and fix the failing ones.

View file

@ -0,0 +1,55 @@
---
name: playwright-test-healer
description: Use this agent when you need to debug and fix failing Playwright tests
model: sonnet
color: red
tools:
- search
- edit
- playwright-test/browser_console_messages
- playwright-test/browser_evaluate
- playwright-test/browser_generate_locator
- playwright-test/browser_network_requests
- playwright-test/browser_snapshot
- playwright-test/test_debug
- playwright-test/test_list
- playwright-test/test_run
---
You are the Playwright Test Healer, an expert test automation engineer specializing in debugging and
resolving Playwright test failures. Your mission is to systematically identify, diagnose, and fix
broken Playwright tests using a methodical approach.
Your workflow:
1. **Initial Execution**: Run all tests using `test_run` tool to identify failing tests
2. **Debug failed tests**: For each failing test run `test_debug`.
3. **Error Investigation**: When the test pauses on errors, use available Playwright MCP tools to:
- Examine the error details
- Capture page snapshot to understand the context
- Analyze selectors, timing issues, or assertion failures
4. **Root Cause Analysis**: Determine the underlying cause of the failure by examining:
- Element selectors that may have changed
- Timing and synchronization issues
- Data dependencies or test environment problems
- Application changes that broke test assumptions
5. **Code Remediation**: Edit the test code to address identified issues, focusing on:
- Updating selectors to match current application state
- Fixing assertions and expected values
- Improving test reliability and maintainability
- For inherently dynamic data, utilize regular expressions to produce resilient locators
6. **Verification**: Restart the test after each fix to validate the changes
7. **Iteration**: Repeat the investigation and fixing process until the test passes cleanly
Key principles:
- Be systematic and thorough in your debugging approach
- Document your findings and reasoning for each fix
- Prefer robust, maintainable solutions over quick hacks
- Use Playwright best practices for reliable test automation
- If multiple errors exist, fix them one at a time and retest
- Provide clear explanations of what was broken and how you fixed it
- You will continue this process until the test runs successfully without any failures or errors.
- If the error persists and you have high level of confidence that the test is correct, mark this test as test.fixme()
so that it is skipped during the execution. Add a comment before the failing step explaining what is happening instead
of the expected behavior.
- Do not ask user questions, you are not interactive tool, do the most reasonable thing possible to pass the test.
- Never wait for networkidle or use other discouraged or deprecated apis

View file

@ -0,0 +1,9 @@
---
agent: playwright-test-planner
description: Create test plan
---
Create test plan for "add to cart" functionality of my app.
- Seed file: `${seedFile}`
- Test plan: `specs/coverage.plan.md`

View file

@ -0,0 +1,73 @@
---
name: playwright-test-planner
description: Use this agent when you need to create comprehensive test plan for a web application or website
model: sonnet
color: green
tools:
- search
- playwright-test/browser_click
- playwright-test/browser_close
- playwright-test/browser_console_messages
- playwright-test/browser_drag
- playwright-test/browser_evaluate
- playwright-test/browser_file_upload
- playwright-test/browser_handle_dialog
- playwright-test/browser_hover
- playwright-test/browser_navigate
- playwright-test/browser_navigate_back
- playwright-test/browser_network_requests
- playwright-test/browser_press_key
- playwright-test/browser_run_code
- playwright-test/browser_select_option
- playwright-test/browser_snapshot
- playwright-test/browser_take_screenshot
- playwright-test/browser_type
- playwright-test/browser_wait_for
- playwright-test/planner_setup_page
- playwright-test/planner_save_plan
---
You are an expert web test planner with extensive experience in quality assurance, user experience testing, and test
scenario design. Your expertise includes functional testing, edge case identification, and comprehensive test coverage
planning.
You will:
1. **Navigate and Explore**
- Invoke the `planner_setup_page` tool once to set up page before using any other tools
- Explore the browser snapshot
- Do not take screenshots unless absolutely necessary
- Use `browser_*` tools to navigate and discover interface
- Thoroughly explore the interface, identifying all interactive elements, forms, navigation paths, and functionality
2. **Analyze User Flows**
- Map out the primary user journeys and identify critical paths through the application
- Consider different user types and their typical behaviors
3. **Design Comprehensive Scenarios**
Create detailed test scenarios that cover:
- Happy path scenarios (normal user behavior)
- Edge cases and boundary conditions
- Error handling and validation
4. **Structure Test Plans**
Each scenario must include:
- Clear, descriptive title
- Detailed step-by-step instructions
- Expected outcomes where appropriate
- Assumptions about starting state (always assume blank/fresh state)
- Success criteria and failure conditions
5. **Create Documentation**
Submit your test plan using `planner_save_plan` tool.
**Quality Standards**:
- Write steps that are specific enough for any tester to follow
- Include negative testing scenarios
- Ensure scenarios are independent and can be run in any order
**Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and
professional formatting suitable for sharing with development and QA teams.

282
backend/node_modules/playwright/lib/common/config.js generated vendored Normal file
View file

@ -0,0 +1,282 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var config_exports = {};
__export(config_exports, {
FullConfigInternal: () => FullConfigInternal,
FullProjectInternal: () => FullProjectInternal,
builtInReporters: () => builtInReporters,
defaultGrep: () => defaultGrep,
defaultReporter: () => defaultReporter,
defaultTimeout: () => defaultTimeout,
getProjectId: () => getProjectId,
takeFirst: () => takeFirst,
toReporters: () => toReporters
});
module.exports = __toCommonJS(config_exports);
var import_fs = __toESM(require("fs"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_util = require("../util");
const defaultTimeout = 3e4;
class FullConfigInternal {
constructor(location, userConfig, configCLIOverrides, metadata) {
this.projects = [];
this.cliArgs = [];
this.cliListOnly = false;
this.preOnlyTestFilters = [];
this.postShardTestFilters = [];
this.defineConfigWasUsed = false;
this.globalSetups = [];
this.globalTeardowns = [];
if (configCLIOverrides.projects && userConfig.projects)
throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);
const { resolvedConfigFile, configDir } = location;
const packageJsonPath = (0, import_util.getPackageJsonPath)(configDir);
const packageJsonDir = packageJsonPath ? import_path.default.dirname(packageJsonPath) : process.cwd();
this.configDir = configDir;
this.configCLIOverrides = configCLIOverrides;
const privateConfiguration = userConfig["@playwright/test"];
this.plugins = (privateConfiguration?.plugins || []).map((p) => ({ factory: p }));
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
this.captureGitInfo = userConfig.captureGitInfo;
this.failOnFlakyTests = takeFirst(configCLIOverrides.failOnFlakyTests, userConfig.failOnFlakyTests, false);
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0);
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0);
userConfig.metadata = userConfig.metadata || {};
const globalTags = Array.isArray(userConfig.tag) ? userConfig.tag : userConfig.tag ? [userConfig.tag] : [];
for (const tag of globalTags) {
if (tag[0] !== "@")
throw new Error(`Tag must start with "@" symbol, got "${tag}" instead.`);
}
this.config = {
configFile: resolvedConfigFile,
rootDir: pathResolve(configDir, userConfig.testDir) || configDir,
forbidOnly: takeFirst(configCLIOverrides.forbidOnly, userConfig.forbidOnly, false),
fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false),
globalSetup: this.globalSetups[0] ?? null,
globalTeardown: this.globalTeardowns[0] ?? null,
globalTimeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0),
grep: takeFirst(userConfig.grep, defaultGrep),
grepInvert: takeFirst(userConfig.grepInvert, null),
maxFailures: takeFirst(configCLIOverrides.debug ? 1 : void 0, configCLIOverrides.maxFailures, userConfig.maxFailures, 0),
metadata: metadata ?? userConfig.metadata,
preserveOutput: takeFirst(userConfig.preserveOutput, "always"),
projects: [],
quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
reportSlowTests: takeFirst(userConfig.reportSlowTests, {
max: 5,
threshold: 3e5
/* 5 minutes */
}),
// @ts-expect-error runAgents is hidden
runAgents: takeFirst(configCLIOverrides.runAgents, "none"),
shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
tags: globalTags,
updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, "missing"),
updateSourceMethod: takeFirst(configCLIOverrides.updateSourceMethod, userConfig.updateSourceMethod, "patch"),
version: require("../../package.json").version,
workers: resolveWorkers(takeFirst(configCLIOverrides.debug || configCLIOverrides.pause ? 1 : void 0, configCLIOverrides.workers, userConfig.workers, "50%")),
webServer: null
};
for (const key in userConfig) {
if (key.startsWith("@"))
this.config[key] = userConfig[key];
}
this.config[configInternalSymbol] = this;
const webServers = takeFirst(userConfig.webServer, null);
if (Array.isArray(webServers)) {
this.config.webServer = null;
this.webServers = webServers;
} else if (webServers) {
this.config.webServer = webServers;
this.webServers = [webServers];
} else {
this.webServers = [];
}
const projectConfigs = configCLIOverrides.projects || userConfig.projects || [{ ...userConfig, workers: void 0 }];
this.projects = projectConfigs.map((p) => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir));
resolveProjectDependencies(this.projects);
this._assignUniqueProjectIds(this.projects);
this.config.projects = this.projects.map((p) => p.project);
}
_assignUniqueProjectIds(projects) {
const usedNames = /* @__PURE__ */ new Set();
for (const p of projects) {
const name = p.project.name || "";
for (let i = 0; i < projects.length; ++i) {
const candidate = name + (i ? i : "");
if (usedNames.has(candidate))
continue;
p.id = candidate;
p.project.__projectId = p.id;
usedNames.add(candidate);
break;
}
}
}
}
class FullProjectInternal {
constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, packageJsonDir) {
this.id = "";
this.deps = [];
this.fullConfig = fullConfig;
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate);
this.project = {
grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), import_path.default.join(packageJsonDir, "test-results")),
// Note: we either apply the cli override for repeatEach or not, depending on whether the
// project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils.
repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1),
retries: takeFirst(configCLIOverrides.retries, projectConfig.retries, config.retries, 0),
metadata: takeFirst(projectConfig.metadata, config.metadata, {}),
name: takeFirst(projectConfig.name, config.name, ""),
testDir,
snapshotDir: takeFirst(pathResolve(configDir, projectConfig.snapshotDir), pathResolve(configDir, config.snapshotDir), testDir),
testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []),
testMatch: takeFirst(projectConfig.testMatch, config.testMatch, "**/*.@(spec|test).?(c|m)[jt]s?(x)"),
timeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout),
use: (0, import_util.mergeObjects)(config.use, projectConfig.use, configCLIOverrides.use),
dependencies: projectConfig.dependencies || [],
teardown: projectConfig.teardown
};
this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, void 0);
this.expect = takeFirst(projectConfig.expect, config.expect, {});
if (this.expect.toHaveScreenshot?.stylePath) {
const stylePaths = Array.isArray(this.expect.toHaveScreenshot.stylePath) ? this.expect.toHaveScreenshot.stylePath : [this.expect.toHaveScreenshot.stylePath];
this.expect.toHaveScreenshot.stylePath = stylePaths.map((stylePath) => import_path.default.resolve(configDir, stylePath));
}
this.respectGitIgnore = takeFirst(projectConfig.respectGitIgnore, config.respectGitIgnore, !projectConfig.testDir && !config.testDir);
this.ignoreSnapshots = takeFirst(configCLIOverrides.ignoreSnapshots, projectConfig.ignoreSnapshots, config.ignoreSnapshots, false);
this.workers = projectConfig.workers ? resolveWorkers(projectConfig.workers) : void 0;
if (configCLIOverrides.debug && this.workers)
this.workers = 1;
}
}
function takeFirst(...args) {
for (const arg of args) {
if (arg !== void 0)
return arg;
}
return void 0;
}
function pathResolve(baseDir, relative) {
if (!relative)
return void 0;
return import_path.default.resolve(baseDir, relative);
}
function resolveReporters(reporters, rootDir) {
return toReporters(reporters)?.map(([id, arg]) => {
if (builtInReporters.includes(id))
return [id, arg];
return [require.resolve(id, { paths: [rootDir] }), arg];
});
}
function resolveWorkers(workers) {
if (typeof workers === "string") {
if (workers.endsWith("%")) {
const cpus = import_os.default.cpus().length;
return Math.max(1, Math.floor(cpus * (parseInt(workers, 10) / 100)));
}
const parsedWorkers = parseInt(workers, 10);
if (isNaN(parsedWorkers))
throw new Error(`Workers ${workers} must be a number or percentage.`);
return parsedWorkers;
}
return workers;
}
function resolveProjectDependencies(projects) {
const teardownSet = /* @__PURE__ */ new Set();
for (const project of projects) {
for (const dependencyName of project.project.dependencies) {
const dependencies = projects.filter((p) => p.project.name === dependencyName);
if (!dependencies.length)
throw new Error(`Project '${project.project.name}' depends on unknown project '${dependencyName}'`);
if (dependencies.length > 1)
throw new Error(`Project dependencies should have unique names, reading ${dependencyName}`);
project.deps.push(...dependencies);
}
if (project.project.teardown) {
const teardowns = projects.filter((p) => p.project.name === project.project.teardown);
if (!teardowns.length)
throw new Error(`Project '${project.project.name}' has unknown teardown project '${project.project.teardown}'`);
if (teardowns.length > 1)
throw new Error(`Project teardowns should have unique names, reading ${project.project.teardown}`);
const teardown = teardowns[0];
project.teardown = teardown;
teardownSet.add(teardown);
}
}
for (const teardown of teardownSet) {
if (teardown.deps.length)
throw new Error(`Teardown project ${teardown.project.name} must not have dependencies`);
}
for (const project of projects) {
for (const dep of project.deps) {
if (teardownSet.has(dep))
throw new Error(`Project ${project.project.name} must not depend on a teardown project ${dep.project.name}`);
}
}
}
function toReporters(reporters) {
if (!reporters)
return;
if (typeof reporters === "string")
return [[reporters]];
return reporters;
}
const builtInReporters = ["list", "line", "dot", "json", "junit", "null", "github", "html", "blob"];
function resolveScript(id, rootDir) {
if (!id)
return void 0;
const localPath = import_path.default.resolve(rootDir, id);
if (import_fs.default.existsSync(localPath))
return localPath;
return require.resolve(id, { paths: [rootDir] });
}
const defaultGrep = /.*/;
const defaultReporter = process.env.CI ? "dot" : "list";
const configInternalSymbol = Symbol("configInternalSymbol");
function getProjectId(project) {
return project.__projectId;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
FullConfigInternal,
FullProjectInternal,
builtInReporters,
defaultGrep,
defaultReporter,
defaultTimeout,
getProjectId,
takeFirst,
toReporters
});

View file

@ -0,0 +1,344 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var configLoader_exports = {};
__export(configLoader_exports, {
defineConfig: () => defineConfig,
deserializeConfig: () => deserializeConfig,
loadConfig: () => loadConfig,
loadConfigFromFile: () => loadConfigFromFile,
loadEmptyConfigForMergeReports: () => loadEmptyConfigForMergeReports,
resolveConfigLocation: () => resolveConfigLocation
});
module.exports = __toCommonJS(configLoader_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_utils = require("playwright-core/lib/utils");
var import_transform = require("../transform/transform");
var import_util = require("../util");
var import_config = require("./config");
var import_esmLoaderHost = require("./esmLoaderHost");
var import_compilationCache = require("../transform/compilationCache");
const kDefineConfigWasUsed = Symbol("defineConfigWasUsed");
const defineConfig = (...configs) => {
let result = configs[0];
for (let i = 1; i < configs.length; ++i) {
const config = configs[i];
const prevProjects = result.projects;
result = {
...result,
...config,
expect: {
...result.expect,
...config.expect
},
use: {
...result.use,
...config.use
},
build: {
...result.build,
...config.build
},
webServer: [
...Array.isArray(result.webServer) ? result.webServer : result.webServer ? [result.webServer] : [],
...Array.isArray(config.webServer) ? config.webServer : config.webServer ? [config.webServer] : []
]
};
if (!result.projects && !config.projects)
continue;
const projectOverrides = /* @__PURE__ */ new Map();
for (const project of config.projects || [])
projectOverrides.set(project.name, project);
const projects = [];
for (const project of prevProjects || []) {
const projectOverride = projectOverrides.get(project.name);
if (projectOverride) {
projects.push({
...project,
...projectOverride,
use: {
...project.use,
...projectOverride.use
}
});
projectOverrides.delete(project.name);
} else {
projects.push(project);
}
}
projects.push(...projectOverrides.values());
result.projects = projects;
}
result[kDefineConfigWasUsed] = true;
return result;
};
async function deserializeConfig(data) {
if (data.compilationCache)
(0, import_compilationCache.addToCompilationCache)(data.compilationCache);
return await loadConfig(data.location, data.configCLIOverrides, void 0, data.metadata ? JSON.parse(data.metadata) : void 0);
}
async function loadUserConfig(location) {
let object = location.resolvedConfigFile ? await (0, import_transform.requireOrImport)(location.resolvedConfigFile) : {};
if (object && typeof object === "object" && "default" in object)
object = object["default"];
return object;
}
async function loadConfig(location, overrides, ignoreProjectDependencies = false, metadata) {
if (!(0, import_esmLoaderHost.registerESMLoader)()) {
if (location.resolvedConfigFile && (0, import_util.fileIsModule)(location.resolvedConfigFile))
throw (0, import_util.errorWithFile)(location.resolvedConfigFile, `Playwright requires Node.js 18.19 or higher to load esm modules. Please update your version of Node.js.`);
}
(0, import_transform.setSingleTSConfig)(overrides?.tsconfig);
await (0, import_esmLoaderHost.configureESMLoader)();
const userConfig = await loadUserConfig(location);
validateConfig(location.resolvedConfigFile || "<default config>", userConfig);
const fullConfig = new import_config.FullConfigInternal(location, userConfig, overrides || {}, metadata);
fullConfig.defineConfigWasUsed = !!userConfig[kDefineConfigWasUsed];
if (ignoreProjectDependencies) {
for (const project of fullConfig.projects) {
project.deps = [];
project.teardown = void 0;
}
}
const babelPlugins = userConfig["@playwright/test"]?.babelPlugins || [];
const external = userConfig.build?.external || [];
(0, import_transform.setTransformConfig)({ babelPlugins, external });
if (!overrides?.tsconfig)
(0, import_transform.setSingleTSConfig)(fullConfig?.singleTSConfigPath);
await (0, import_esmLoaderHost.configureESMLoaderTransformConfig)();
return fullConfig;
}
function validateConfig(file, config) {
if (typeof config !== "object" || !config)
throw (0, import_util.errorWithFile)(file, `Configuration file must export a single object`);
validateProject(file, config, "config");
if ("forbidOnly" in config && config.forbidOnly !== void 0) {
if (typeof config.forbidOnly !== "boolean")
throw (0, import_util.errorWithFile)(file, `config.forbidOnly must be a boolean`);
}
if ("globalSetup" in config && config.globalSetup !== void 0) {
if (Array.isArray(config.globalSetup)) {
config.globalSetup.forEach((item, index) => {
if (typeof item !== "string")
throw (0, import_util.errorWithFile)(file, `config.globalSetup[${index}] must be a string`);
});
} else if (typeof config.globalSetup !== "string") {
throw (0, import_util.errorWithFile)(file, `config.globalSetup must be a string`);
}
}
if ("globalTeardown" in config && config.globalTeardown !== void 0) {
if (Array.isArray(config.globalTeardown)) {
config.globalTeardown.forEach((item, index) => {
if (typeof item !== "string")
throw (0, import_util.errorWithFile)(file, `config.globalTeardown[${index}] must be a string`);
});
} else if (typeof config.globalTeardown !== "string") {
throw (0, import_util.errorWithFile)(file, `config.globalTeardown must be a string`);
}
}
if ("globalTimeout" in config && config.globalTimeout !== void 0) {
if (typeof config.globalTimeout !== "number" || config.globalTimeout < 0)
throw (0, import_util.errorWithFile)(file, `config.globalTimeout must be a non-negative number`);
}
if ("grep" in config && config.grep !== void 0) {
if (Array.isArray(config.grep)) {
config.grep.forEach((item, index) => {
if (!(0, import_utils.isRegExp)(item))
throw (0, import_util.errorWithFile)(file, `config.grep[${index}] must be a RegExp`);
});
} else if (!(0, import_utils.isRegExp)(config.grep)) {
throw (0, import_util.errorWithFile)(file, `config.grep must be a RegExp`);
}
}
if ("grepInvert" in config && config.grepInvert !== void 0) {
if (Array.isArray(config.grepInvert)) {
config.grepInvert.forEach((item, index) => {
if (!(0, import_utils.isRegExp)(item))
throw (0, import_util.errorWithFile)(file, `config.grepInvert[${index}] must be a RegExp`);
});
} else if (!(0, import_utils.isRegExp)(config.grepInvert)) {
throw (0, import_util.errorWithFile)(file, `config.grepInvert must be a RegExp`);
}
}
if ("maxFailures" in config && config.maxFailures !== void 0) {
if (typeof config.maxFailures !== "number" || config.maxFailures < 0)
throw (0, import_util.errorWithFile)(file, `config.maxFailures must be a non-negative number`);
}
if ("preserveOutput" in config && config.preserveOutput !== void 0) {
if (typeof config.preserveOutput !== "string" || !["always", "never", "failures-only"].includes(config.preserveOutput))
throw (0, import_util.errorWithFile)(file, `config.preserveOutput must be one of "always", "never" or "failures-only"`);
}
if ("projects" in config && config.projects !== void 0) {
if (!Array.isArray(config.projects))
throw (0, import_util.errorWithFile)(file, `config.projects must be an array`);
config.projects.forEach((project, index) => {
validateProject(file, project, `config.projects[${index}]`);
});
}
if ("quiet" in config && config.quiet !== void 0) {
if (typeof config.quiet !== "boolean")
throw (0, import_util.errorWithFile)(file, `config.quiet must be a boolean`);
}
if ("reporter" in config && config.reporter !== void 0) {
if (Array.isArray(config.reporter)) {
config.reporter.forEach((item, index) => {
if (!Array.isArray(item) || item.length <= 0 || item.length > 2 || typeof item[0] !== "string")
throw (0, import_util.errorWithFile)(file, `config.reporter[${index}] must be a tuple [name, optionalArgument]`);
});
} else if (typeof config.reporter !== "string") {
throw (0, import_util.errorWithFile)(file, `config.reporter must be a string`);
}
}
if ("reportSlowTests" in config && config.reportSlowTests !== void 0 && config.reportSlowTests !== null) {
if (!config.reportSlowTests || typeof config.reportSlowTests !== "object")
throw (0, import_util.errorWithFile)(file, `config.reportSlowTests must be an object`);
if (!("max" in config.reportSlowTests) || typeof config.reportSlowTests.max !== "number" || config.reportSlowTests.max < 0)
throw (0, import_util.errorWithFile)(file, `config.reportSlowTests.max must be a non-negative number`);
if (!("threshold" in config.reportSlowTests) || typeof config.reportSlowTests.threshold !== "number" || config.reportSlowTests.threshold < 0)
throw (0, import_util.errorWithFile)(file, `config.reportSlowTests.threshold must be a non-negative number`);
}
if ("shard" in config && config.shard !== void 0 && config.shard !== null) {
if (!config.shard || typeof config.shard !== "object")
throw (0, import_util.errorWithFile)(file, `config.shard must be an object`);
if (!("total" in config.shard) || typeof config.shard.total !== "number" || config.shard.total < 1)
throw (0, import_util.errorWithFile)(file, `config.shard.total must be a positive number`);
if (!("current" in config.shard) || typeof config.shard.current !== "number" || config.shard.current < 1 || config.shard.current > config.shard.total)
throw (0, import_util.errorWithFile)(file, `config.shard.current must be a positive number, not greater than config.shard.total`);
}
if ("updateSnapshots" in config && config.updateSnapshots !== void 0) {
if (typeof config.updateSnapshots !== "string" || !["all", "changed", "missing", "none"].includes(config.updateSnapshots))
throw (0, import_util.errorWithFile)(file, `config.updateSnapshots must be one of "all", "changed", "missing" or "none"`);
}
if ("tsconfig" in config && config.tsconfig !== void 0) {
if (typeof config.tsconfig !== "string")
throw (0, import_util.errorWithFile)(file, `config.tsconfig must be a string`);
if (!import_fs.default.existsSync(import_path.default.resolve(file, "..", config.tsconfig)))
throw (0, import_util.errorWithFile)(file, `config.tsconfig does not exist`);
}
}
function validateProject(file, project, title) {
if (typeof project !== "object" || !project)
throw (0, import_util.errorWithFile)(file, `${title} must be an object`);
if ("name" in project && project.name !== void 0) {
if (typeof project.name !== "string")
throw (0, import_util.errorWithFile)(file, `${title}.name must be a string`);
}
if ("outputDir" in project && project.outputDir !== void 0) {
if (typeof project.outputDir !== "string")
throw (0, import_util.errorWithFile)(file, `${title}.outputDir must be a string`);
}
if ("repeatEach" in project && project.repeatEach !== void 0) {
if (typeof project.repeatEach !== "number" || project.repeatEach < 0)
throw (0, import_util.errorWithFile)(file, `${title}.repeatEach must be a non-negative number`);
}
if ("retries" in project && project.retries !== void 0) {
if (typeof project.retries !== "number" || project.retries < 0)
throw (0, import_util.errorWithFile)(file, `${title}.retries must be a non-negative number`);
}
if ("testDir" in project && project.testDir !== void 0) {
if (typeof project.testDir !== "string")
throw (0, import_util.errorWithFile)(file, `${title}.testDir must be a string`);
}
for (const prop of ["testIgnore", "testMatch"]) {
if (prop in project && project[prop] !== void 0) {
const value = project[prop];
if (Array.isArray(value)) {
value.forEach((item, index) => {
if (typeof item !== "string" && !(0, import_utils.isRegExp)(item))
throw (0, import_util.errorWithFile)(file, `${title}.${prop}[${index}] must be a string or a RegExp`);
});
} else if (typeof value !== "string" && !(0, import_utils.isRegExp)(value)) {
throw (0, import_util.errorWithFile)(file, `${title}.${prop} must be a string or a RegExp`);
}
}
}
if ("timeout" in project && project.timeout !== void 0) {
if (typeof project.timeout !== "number" || project.timeout < 0)
throw (0, import_util.errorWithFile)(file, `${title}.timeout must be a non-negative number`);
}
if ("use" in project && project.use !== void 0) {
if (!project.use || typeof project.use !== "object")
throw (0, import_util.errorWithFile)(file, `${title}.use must be an object`);
}
if ("ignoreSnapshots" in project && project.ignoreSnapshots !== void 0) {
if (typeof project.ignoreSnapshots !== "boolean")
throw (0, import_util.errorWithFile)(file, `${title}.ignoreSnapshots must be a boolean`);
}
if ("workers" in project && project.workers !== void 0) {
if (typeof project.workers === "number" && project.workers <= 0)
throw (0, import_util.errorWithFile)(file, `${title}.workers must be a positive number`);
else if (typeof project.workers === "string" && !project.workers.endsWith("%"))
throw (0, import_util.errorWithFile)(file, `${title}.workers must be a number or percentage`);
}
}
function resolveConfigLocation(configFile) {
const configFileOrDirectory = configFile ? import_path.default.resolve(process.cwd(), configFile) : process.cwd();
const resolvedConfigFile = resolveConfigFile(configFileOrDirectory);
return {
resolvedConfigFile,
configDir: resolvedConfigFile ? import_path.default.dirname(resolvedConfigFile) : configFileOrDirectory
};
}
function resolveConfigFile(configFileOrDirectory) {
const resolveConfig = (configFile) => {
if (import_fs.default.existsSync(configFile))
return configFile;
};
const resolveConfigFileFromDirectory = (directory) => {
for (const ext of [".ts", ".js", ".mts", ".mjs", ".cts", ".cjs"]) {
const configFile = resolveConfig(import_path.default.resolve(directory, "playwright.config" + ext));
if (configFile)
return configFile;
}
};
if (!import_fs.default.existsSync(configFileOrDirectory))
throw new Error(`${configFileOrDirectory} does not exist`);
if (import_fs.default.statSync(configFileOrDirectory).isDirectory()) {
const configFile = resolveConfigFileFromDirectory(configFileOrDirectory);
if (configFile)
return configFile;
return void 0;
}
return configFileOrDirectory;
}
async function loadConfigFromFile(configFile, overrides, ignoreDeps) {
return await loadConfig(resolveConfigLocation(configFile), overrides, ignoreDeps);
}
async function loadEmptyConfigForMergeReports() {
return await loadConfig({ configDir: process.cwd() });
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
defineConfig,
deserializeConfig,
loadConfig,
loadConfigFromFile,
loadEmptyConfigForMergeReports,
resolveConfigLocation
});

View file

@ -0,0 +1,104 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var esmLoaderHost_exports = {};
__export(esmLoaderHost_exports, {
configureESMLoader: () => configureESMLoader,
configureESMLoaderTransformConfig: () => configureESMLoaderTransformConfig,
incorporateCompilationCache: () => incorporateCompilationCache,
registerESMLoader: () => registerESMLoader,
startCollectingFileDeps: () => startCollectingFileDeps,
stopCollectingFileDeps: () => stopCollectingFileDeps
});
module.exports = __toCommonJS(esmLoaderHost_exports);
var import_url = __toESM(require("url"));
var import_compilationCache = require("../transform/compilationCache");
var import_portTransport = require("../transform/portTransport");
var import_transform = require("../transform/transform");
let loaderChannel;
function registerESMLoader() {
if (process.env.PW_DISABLE_TS_ESM)
return true;
if ("Bun" in globalThis)
return true;
if (loaderChannel)
return true;
const register = require("node:module").register;
if (!register)
return false;
const { port1, port2 } = new MessageChannel();
register(import_url.default.pathToFileURL(require.resolve("../transform/esmLoader")), {
data: { port: port2 },
transferList: [port2]
});
loaderChannel = createPortTransport(port1);
return true;
}
function createPortTransport(port) {
return new import_portTransport.PortTransport(port, async (method, params) => {
if (method === "pushToCompilationCache")
(0, import_compilationCache.addToCompilationCache)(params.cache);
});
}
async function startCollectingFileDeps() {
if (!loaderChannel)
return;
await loaderChannel.send("startCollectingFileDeps", {});
}
async function stopCollectingFileDeps(file) {
if (!loaderChannel)
return;
await loaderChannel.send("stopCollectingFileDeps", { file });
}
async function incorporateCompilationCache() {
if (!loaderChannel)
return;
const result = await loaderChannel.send("getCompilationCache", {});
(0, import_compilationCache.addToCompilationCache)(result.cache);
}
async function configureESMLoader() {
if (!loaderChannel)
return;
await loaderChannel.send("setSingleTSConfig", { tsconfig: (0, import_transform.singleTSConfig)() });
await loaderChannel.send("addToCompilationCache", { cache: (0, import_compilationCache.serializeCompilationCache)() });
}
async function configureESMLoaderTransformConfig() {
if (!loaderChannel)
return;
await loaderChannel.send("setSingleTSConfig", { tsconfig: (0, import_transform.singleTSConfig)() });
await loaderChannel.send("setTransformConfig", { config: (0, import_transform.transformConfig)() });
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
configureESMLoader,
configureESMLoaderTransformConfig,
incorporateCompilationCache,
registerESMLoader,
startCollectingFileDeps,
stopCollectingFileDeps
});

View file

@ -0,0 +1,28 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var expectBundle_exports = {};
__export(expectBundle_exports, {
expect: () => expect
});
module.exports = __toCommonJS(expectBundle_exports);
const expect = require("./expectBundleImpl").expect;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
expect
});

File diff suppressed because one or more lines are too long

302
backend/node_modules/playwright/lib/common/fixtures.js generated vendored Normal file
View file

@ -0,0 +1,302 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var fixtures_exports = {};
__export(fixtures_exports, {
FixturePool: () => FixturePool,
fixtureParameterNames: () => fixtureParameterNames,
formatPotentiallyInternalLocation: () => formatPotentiallyInternalLocation,
inheritFixtureNames: () => inheritFixtureNames
});
module.exports = __toCommonJS(fixtures_exports);
var import_crypto = __toESM(require("crypto"));
var import_util = require("../util");
const kScopeOrder = ["test", "worker"];
function isFixtureTuple(value) {
return Array.isArray(value) && typeof value[1] === "object";
}
function isFixtureOption(value) {
return isFixtureTuple(value) && !!value[1].option;
}
class FixturePool {
constructor(fixturesList, onLoadError, parentPool, disallowWorkerFixtures, optionOverrides) {
this._registrations = new Map(parentPool ? parentPool._registrations : []);
this._onLoadError = onLoadError;
const allOverrides = optionOverrides?.overrides ?? {};
const overrideKeys = new Set(Object.keys(allOverrides));
for (const list of fixturesList) {
this._appendFixtureList(list, !!disallowWorkerFixtures, false);
const selectedOverrides = {};
for (const [key, value] of Object.entries(list.fixtures)) {
if (isFixtureOption(value) && overrideKeys.has(key))
selectedOverrides[key] = [allOverrides[key], value[1]];
}
if (Object.entries(selectedOverrides).length)
this._appendFixtureList({ fixtures: selectedOverrides, location: optionOverrides.location }, !!disallowWorkerFixtures, true);
}
this.digest = this.validate();
}
_appendFixtureList(list, disallowWorkerFixtures, isOptionsOverride) {
const { fixtures, location } = list;
for (const entry of Object.entries(fixtures)) {
const name = entry[0];
let value = entry[1];
let options;
if (isFixtureTuple(value)) {
options = {
auto: value[1].auto ?? false,
scope: value[1].scope || "test",
option: !!value[1].option,
timeout: value[1].timeout,
customTitle: value[1].title,
box: value[1].box
};
value = value[0];
}
let fn = value;
const previous = this._registrations.get(name);
if (previous && options) {
if (previous.scope !== options.scope) {
this._addLoadError(`Fixture "${name}" has already been registered as a { scope: '${previous.scope}' } fixture defined in ${(0, import_util.formatLocation)(previous.location)}.`, location);
continue;
}
if (previous.auto !== options.auto) {
this._addLoadError(`Fixture "${name}" has already been registered as a { auto: '${previous.scope}' } fixture defined in ${(0, import_util.formatLocation)(previous.location)}.`, location);
continue;
}
} else if (previous) {
options = { auto: previous.auto, scope: previous.scope, option: previous.option, timeout: previous.timeout, customTitle: previous.customTitle };
} else if (!options) {
options = { auto: false, scope: "test", option: false, timeout: void 0 };
}
if (!kScopeOrder.includes(options.scope)) {
this._addLoadError(`Fixture "${name}" has unknown { scope: '${options.scope}' }.`, location);
continue;
}
if (options.scope === "worker" && disallowWorkerFixtures) {
this._addLoadError(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.
Make it top-level in the test file or put in the configuration file.`, location);
continue;
}
if (fn === void 0 && options.option && previous) {
let original = previous;
while (!original.optionOverride && original.super)
original = original.super;
fn = original.fn;
}
const deps = fixtureParameterNames(fn, location, (e) => this._onLoadError(e));
const registration = { id: "", name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, customTitle: options.customTitle, box: options.box, deps, super: previous, optionOverride: isOptionsOverride };
registrationId(registration);
this._registrations.set(name, registration);
}
}
validate() {
const markers = /* @__PURE__ */ new Map();
const stack = [];
let hasDependencyErrors = false;
const addDependencyError = (message, location) => {
hasDependencyErrors = true;
this._addLoadError(message, location);
};
const visit = (registration, boxedOnly) => {
markers.set(registration, "visiting");
stack.push(registration);
for (const name of registration.deps) {
const dep = this.resolve(name, registration);
if (!dep) {
if (name === registration.name)
addDependencyError(`Fixture "${registration.name}" references itself, but does not have a base implementation.`, registration.location);
else
addDependencyError(`Fixture "${registration.name}" has unknown parameter "${name}".`, registration.location);
continue;
}
if (kScopeOrder.indexOf(registration.scope) > kScopeOrder.indexOf(dep.scope)) {
addDependencyError(`${registration.scope} fixture "${registration.name}" cannot depend on a ${dep.scope} fixture "${name}" defined in ${formatPotentiallyInternalLocation(dep.location)}.`, registration.location);
continue;
}
if (!markers.has(dep)) {
visit(dep, boxedOnly);
} else if (markers.get(dep) === "visiting") {
const index = stack.indexOf(dep);
const allRegs = stack.slice(index, stack.length);
const filteredRegs = allRegs.filter((r) => !r.box);
const regs = boxedOnly ? filteredRegs : allRegs;
const names2 = regs.map((r) => `"${r.name}"`);
addDependencyError(`Fixtures ${names2.join(" -> ")} -> "${dep.name}" form a dependency cycle: ${regs.map((r) => formatPotentiallyInternalLocation(r.location)).join(" -> ")} -> ${formatPotentiallyInternalLocation(dep.location)}`, dep.location);
continue;
}
}
markers.set(registration, "visited");
stack.pop();
};
const names = Array.from(this._registrations.keys()).sort();
for (const name of names) {
const registration = this._registrations.get(name);
if (!registration.box)
visit(registration, true);
}
if (!hasDependencyErrors) {
for (const name of names) {
const registration = this._registrations.get(name);
if (registration.box)
visit(registration, false);
}
}
const hash = import_crypto.default.createHash("sha1");
for (const name of names) {
const registration = this._registrations.get(name);
if (registration.scope === "worker")
hash.update(registration.id + ";");
}
return hash.digest("hex");
}
validateFunction(fn, prefix, location) {
for (const name of fixtureParameterNames(fn, location, (e) => this._onLoadError(e))) {
const registration = this._registrations.get(name);
if (!registration)
this._addLoadError(`${prefix} has unknown parameter "${name}".`, location);
}
}
resolve(name, forFixture) {
if (name === forFixture?.name)
return forFixture.super;
return this._registrations.get(name);
}
autoFixtures() {
return [...this._registrations.values()].filter((r) => r.auto !== false);
}
_addLoadError(message, location) {
this._onLoadError({ message, location });
}
}
const signatureSymbol = Symbol("signature");
function formatPotentiallyInternalLocation(location) {
const isUserFixture = location && (0, import_util.filterStackFile)(location.file);
return isUserFixture ? (0, import_util.formatLocation)(location) : "<builtin>";
}
function fixtureParameterNames(fn, location, onError) {
if (typeof fn !== "function")
return [];
if (!fn[signatureSymbol])
fn[signatureSymbol] = innerFixtureParameterNames(fn, location, onError);
return fn[signatureSymbol];
}
function inheritFixtureNames(from, to) {
to[signatureSymbol] = from[signatureSymbol];
}
function innerFixtureParameterNames(fn, location, onError) {
const text = filterOutComments(fn.toString());
const match = text.match(/(?:async)?(?:\s+function)?[^(]*\(([^)]*)/);
if (!match)
return [];
const trimmedParams = match[1].trim();
if (!trimmedParams)
return [];
const [firstParam] = splitByComma(trimmedParams);
if (firstParam[0] !== "{" || firstParam[firstParam.length - 1] !== "}") {
onError({ message: "First argument must use the object destructuring pattern: " + firstParam, location });
return [];
}
const props = splitByComma(firstParam.substring(1, firstParam.length - 1)).map((prop) => {
const colon = prop.indexOf(":");
return colon === -1 ? prop.trim() : prop.substring(0, colon).trim();
});
const restProperty = props.find((prop) => prop.startsWith("..."));
if (restProperty) {
onError({ message: `Rest property "${restProperty}" is not supported. List all used fixtures explicitly, separated by comma.`, location });
return [];
}
return props;
}
function filterOutComments(s) {
const result = [];
let commentState = "none";
for (let i = 0; i < s.length; ++i) {
if (commentState === "singleline") {
if (s[i] === "\n")
commentState = "none";
} else if (commentState === "multiline") {
if (s[i - 1] === "*" && s[i] === "/")
commentState = "none";
} else if (commentState === "none") {
if (s[i] === "/" && s[i + 1] === "/") {
commentState = "singleline";
} else if (s[i] === "/" && s[i + 1] === "*") {
commentState = "multiline";
i += 2;
} else {
result.push(s[i]);
}
}
}
return result.join("");
}
function splitByComma(s) {
const result = [];
const stack = [];
let start = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === "{" || s[i] === "[") {
stack.push(s[i] === "{" ? "}" : "]");
} else if (s[i] === stack[stack.length - 1]) {
stack.pop();
} else if (!stack.length && s[i] === ",") {
const token = s.substring(start, i).trim();
if (token)
result.push(token);
start = i + 1;
}
}
const lastToken = s.substring(start).trim();
if (lastToken)
result.push(lastToken);
return result;
}
const registrationIdMap = /* @__PURE__ */ new Map();
let lastId = 0;
function registrationId(registration) {
if (registration.id)
return registration.id;
const key = registration.name + "@@@" + (registration.super ? registrationId(registration.super) : "");
let map = registrationIdMap.get(key);
if (!map) {
map = /* @__PURE__ */ new Map();
registrationIdMap.set(key, map);
}
if (!map.has(registration.fn))
map.set(registration.fn, String(lastId++));
registration.id = map.get(registration.fn);
return registration.id;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
FixturePool,
fixtureParameterNames,
formatPotentiallyInternalLocation,
inheritFixtureNames
});

58
backend/node_modules/playwright/lib/common/globals.js generated vendored Normal file
View file

@ -0,0 +1,58 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var globals_exports = {};
__export(globals_exports, {
currentTestInfo: () => currentTestInfo,
currentlyLoadingFileSuite: () => currentlyLoadingFileSuite,
isWorkerProcess: () => isWorkerProcess,
setCurrentTestInfo: () => setCurrentTestInfo,
setCurrentlyLoadingFileSuite: () => setCurrentlyLoadingFileSuite,
setIsWorkerProcess: () => setIsWorkerProcess
});
module.exports = __toCommonJS(globals_exports);
let currentTestInfoValue = null;
function setCurrentTestInfo(testInfo) {
currentTestInfoValue = testInfo;
}
function currentTestInfo() {
return currentTestInfoValue;
}
let currentFileSuite;
function setCurrentlyLoadingFileSuite(suite) {
currentFileSuite = suite;
}
function currentlyLoadingFileSuite() {
return currentFileSuite;
}
let _isWorkerProcess = false;
function setIsWorkerProcess() {
_isWorkerProcess = true;
}
function isWorkerProcess() {
return _isWorkerProcess;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
currentTestInfo,
currentlyLoadingFileSuite,
isWorkerProcess,
setCurrentTestInfo,
setCurrentlyLoadingFileSuite,
setIsWorkerProcess
});

60
backend/node_modules/playwright/lib/common/ipc.js generated vendored Normal file
View file

@ -0,0 +1,60 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ipc_exports = {};
__export(ipc_exports, {
serializeConfig: () => serializeConfig,
stdioChunkToParams: () => stdioChunkToParams
});
module.exports = __toCommonJS(ipc_exports);
var import_util = __toESM(require("util"));
var import_compilationCache = require("../transform/compilationCache");
function serializeConfig(config, passCompilationCache) {
const result = {
location: { configDir: config.configDir, resolvedConfigFile: config.config.configFile },
configCLIOverrides: config.configCLIOverrides,
compilationCache: passCompilationCache ? (0, import_compilationCache.serializeCompilationCache)() : void 0
};
try {
result.metadata = JSON.stringify(config.config.metadata);
} catch (error) {
}
return result;
}
function stdioChunkToParams(chunk) {
if (chunk instanceof Uint8Array)
return { buffer: Buffer.from(chunk).toString("base64") };
if (typeof chunk !== "string")
return { text: import_util.default.inspect(chunk) };
return { text: chunk };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
serializeConfig,
stdioChunkToParams
});

View file

@ -0,0 +1,85 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var poolBuilder_exports = {};
__export(poolBuilder_exports, {
PoolBuilder: () => PoolBuilder
});
module.exports = __toCommonJS(poolBuilder_exports);
var import_fixtures = require("./fixtures");
var import_util = require("../util");
class PoolBuilder {
constructor(type, project) {
this._testTypePools = /* @__PURE__ */ new Map();
this._type = type;
this._project = project;
}
static createForLoader() {
return new PoolBuilder("loader");
}
static createForWorker(project) {
return new PoolBuilder("worker", project);
}
buildPools(suite, testErrors) {
suite.forEachTest((test) => {
const pool = this._buildPoolForTest(test, testErrors);
if (this._type === "loader")
test._poolDigest = pool.digest;
if (this._type === "worker")
test._pool = pool;
});
}
_buildPoolForTest(test, testErrors) {
let pool = this._buildTestTypePool(test._testType, testErrors);
const parents = [];
for (let parent = test.parent; parent; parent = parent.parent)
parents.push(parent);
parents.reverse();
for (const parent of parents) {
if (parent._use.length)
pool = new import_fixtures.FixturePool(parent._use, (e) => this._handleLoadError(e, testErrors), pool, parent._type === "describe");
for (const hook of parent._hooks)
pool.validateFunction(hook.fn, hook.type + " hook", hook.location);
for (const modifier of parent._modifiers)
pool.validateFunction(modifier.fn, modifier.type + " modifier", modifier.location);
}
pool.validateFunction(test.fn, "Test", test.location);
return pool;
}
_buildTestTypePool(testType, testErrors) {
if (!this._testTypePools.has(testType)) {
const optionOverrides = {
overrides: this._project?.project?.use ?? {},
location: { file: `project#${this._project?.id}`, line: 1, column: 1 }
};
const pool = new import_fixtures.FixturePool(testType.fixtures, (e) => this._handleLoadError(e, testErrors), void 0, void 0, optionOverrides);
this._testTypePools.set(testType, pool);
}
return this._testTypePools.get(testType);
}
_handleLoadError(e, testErrors) {
if (testErrors)
testErrors.push(e);
else
throw new Error(`${(0, import_util.formatLocation)(e.location)}: ${e.message}`);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
PoolBuilder
});

132
backend/node_modules/playwright/lib/common/process.js generated vendored Normal file
View file

@ -0,0 +1,132 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var process_exports = {};
__export(process_exports, {
ProcessRunner: () => ProcessRunner
});
module.exports = __toCommonJS(process_exports);
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
class ProcessRunner {
async gracefullyClose() {
}
dispatchEvent(method, params) {
const response = { method, params };
sendMessageToParent({ method: "__dispatch__", params: response });
}
async sendRequest(method, params) {
return await sendRequestToParent(method, params);
}
async sendMessageNoReply(method, params) {
void sendRequestToParent(method, params).catch(() => {
});
}
}
let gracefullyCloseCalled = false;
let forceExitInitiated = false;
sendMessageToParent({ method: "ready" });
process.on("disconnect", () => gracefullyCloseAndExit(true));
process.on("SIGINT", () => {
});
process.on("SIGTERM", () => {
});
let processRunner;
let processName;
const startingEnv = { ...process.env };
process.on("message", async (message) => {
if (message.method === "__init__") {
const { processParams, runnerParams, runnerScript } = message.params;
void (0, import_utils.startProfiling)();
(0, import_utils.setTimeOrigin)(processParams.timeOrigin);
const { create } = require(runnerScript);
processRunner = create(runnerParams);
processName = processParams.processName;
return;
}
if (message.method === "__stop__") {
const keys = /* @__PURE__ */ new Set([...Object.keys(process.env), ...Object.keys(startingEnv)]);
const producedEnv = [...keys].filter((key) => startingEnv[key] !== process.env[key]).map((key) => [key, process.env[key] ?? null]);
sendMessageToParent({ method: "__env_produced__", params: producedEnv });
await gracefullyCloseAndExit(false);
return;
}
if (message.method === "__dispatch__") {
const { id, method, params } = message.params;
try {
const result = await processRunner[method](params);
const response = { id, result };
sendMessageToParent({ method: "__dispatch__", params: response });
} catch (e) {
const response = { id, error: (0, import_util.serializeError)(e) };
sendMessageToParent({ method: "__dispatch__", params: response });
}
}
if (message.method === "__response__")
handleResponseFromParent(message.params);
});
const kForceExitTimeout = +(process.env.PWTEST_FORCE_EXIT_TIMEOUT || 3e4);
async function gracefullyCloseAndExit(forceExit) {
if (forceExit && !forceExitInitiated) {
forceExitInitiated = true;
setTimeout(() => process.exit(0), kForceExitTimeout);
}
if (!gracefullyCloseCalled) {
gracefullyCloseCalled = true;
await processRunner?.gracefullyClose().catch(() => {
});
if (processName)
await (0, import_utils.stopProfiling)(processName).catch(() => {
});
process.exit(0);
}
}
function sendMessageToParent(message) {
try {
process.send(message);
} catch (e) {
try {
JSON.stringify(message);
} catch {
throw e;
}
}
}
let lastId = 0;
const requestCallbacks = /* @__PURE__ */ new Map();
async function sendRequestToParent(method, params) {
const id = ++lastId;
sendMessageToParent({ method: "__request__", params: { id, method, params } });
const promise = new import_utils.ManualPromise();
requestCallbacks.set(id, promise);
return promise;
}
function handleResponseFromParent(response) {
const promise = requestCallbacks.get(response.id);
if (!promise)
return;
requestCallbacks.delete(response.id);
if (response.error)
promise.reject(new Error(response.error.message));
else
promise.resolve(response.result);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ProcessRunner
});

View file

@ -0,0 +1,140 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var suiteUtils_exports = {};
__export(suiteUtils_exports, {
applyRepeatEachIndex: () => applyRepeatEachIndex,
bindFileSuiteToProject: () => bindFileSuiteToProject,
filterByFocusedLine: () => filterByFocusedLine,
filterOnly: () => filterOnly,
filterSuite: () => filterSuite,
filterTestsRemoveEmptySuites: () => filterTestsRemoveEmptySuites
});
module.exports = __toCommonJS(suiteUtils_exports);
var import_path = __toESM(require("path"));
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
function filterSuite(suite, suiteFilter, testFilter) {
for (const child of suite.suites) {
if (!suiteFilter(child))
filterSuite(child, suiteFilter, testFilter);
}
const filteredTests = suite.tests.filter(testFilter);
const entries = /* @__PURE__ */ new Set([...suite.suites, ...filteredTests]);
suite._entries = suite._entries.filter((e) => entries.has(e));
}
function filterTestsRemoveEmptySuites(suite, filter) {
const filteredSuites = suite.suites.filter((child) => filterTestsRemoveEmptySuites(child, filter));
const filteredTests = suite.tests.filter(filter);
const entries = /* @__PURE__ */ new Set([...filteredSuites, ...filteredTests]);
suite._entries = suite._entries.filter((e) => entries.has(e));
return !!suite._entries.length;
}
function bindFileSuiteToProject(project, suite) {
const relativeFile = import_path.default.relative(project.project.testDir, suite.location.file);
const fileId = (0, import_utils.calculateSha1)((0, import_utils.toPosixPath)(relativeFile)).slice(0, 20);
const result = suite._deepClone();
result._fileId = fileId;
result.forEachTest((test, suite2) => {
suite2._fileId = fileId;
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${project.id}]${(0, import_utils.toPosixPath)(file)}${titles.join("")}`;
const testId = fileId + "-" + (0, import_utils.calculateSha1)(testIdExpression).slice(0, 20);
test.id = testId;
test._projectId = project.id;
let inheritedRetries;
let inheritedTimeout;
for (let parentSuite = suite2; parentSuite; parentSuite = parentSuite.parent) {
if (parentSuite._staticAnnotations.length)
test.annotations.unshift(...parentSuite._staticAnnotations);
if (inheritedRetries === void 0 && parentSuite._retries !== void 0)
inheritedRetries = parentSuite._retries;
if (inheritedTimeout === void 0 && parentSuite._timeout !== void 0)
inheritedTimeout = parentSuite._timeout;
}
test.retries = inheritedRetries ?? project.project.retries;
test.timeout = inheritedTimeout ?? project.project.timeout;
if (test.annotations.some((a) => a.type === "skip" || a.type === "fixme"))
test.expectedStatus = "skipped";
if (test._poolDigest)
test._workerHash = `${project.id}-${test._poolDigest}-0`;
});
return result;
}
function applyRepeatEachIndex(project, fileSuite, repeatEachIndex) {
fileSuite.forEachTest((test, suite) => {
if (repeatEachIndex) {
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${project.id}]${(0, import_utils.toPosixPath)(file)}${titles.join("")} (repeat:${repeatEachIndex})`;
const testId = suite._fileId + "-" + (0, import_utils.calculateSha1)(testIdExpression).slice(0, 20);
test.id = testId;
test.repeatEachIndex = repeatEachIndex;
if (test._poolDigest)
test._workerHash = `${project.id}-${test._poolDigest}-${repeatEachIndex}`;
}
});
}
function filterOnly(suite) {
if (!suite._getOnlyItems().length)
return;
const suiteFilter = (suite2) => suite2._only;
const testFilter = (test) => test._only;
return filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter);
}
function filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter) {
const onlySuites = suite.suites.filter((child) => filterSuiteWithOnlySemantics(child, suiteFilter, testFilter) || suiteFilter(child));
const onlyTests = suite.tests.filter(testFilter);
const onlyEntries = /* @__PURE__ */ new Set([...onlySuites, ...onlyTests]);
if (onlyEntries.size) {
suite._entries = suite._entries.filter((e) => onlyEntries.has(e));
return true;
}
return false;
}
function filterByFocusedLine(suite, focusedTestFileLines) {
if (!focusedTestFileLines.length)
return;
const matchers = focusedTestFileLines.map(createFileMatcherFromFilter);
const testFileLineMatches = (testFileName, testLine, testColumn) => matchers.some((m) => m(testFileName, testLine, testColumn));
const suiteFilter = (suite2) => !!suite2.location && testFileLineMatches(suite2.location.file, suite2.location.line, suite2.location.column);
const testFilter = (test) => testFileLineMatches(test.location.file, test.location.line, test.location.column);
return filterSuite(suite, suiteFilter, testFilter);
}
function createFileMatcherFromFilter(filter) {
const fileMatcher = (0, import_util.createFileMatcher)(filter.re || filter.exact || "");
return (testFileName, testLine, testColumn) => fileMatcher(testFileName) && (filter.line === testLine || filter.line === null) && (filter.column === testColumn || filter.column === null);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
applyRepeatEachIndex,
bindFileSuiteToProject,
filterByFocusedLine,
filterOnly,
filterSuite,
filterTestsRemoveEmptySuites
});

321
backend/node_modules/playwright/lib/common/test.js generated vendored Normal file
View file

@ -0,0 +1,321 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var test_exports = {};
__export(test_exports, {
Suite: () => Suite,
TestCase: () => TestCase
});
module.exports = __toCommonJS(test_exports);
var import_testType = require("./testType");
var import_teleReceiver = require("../isomorphic/teleReceiver");
class Base {
constructor(title) {
this._only = false;
this._requireFile = "";
this.title = title;
}
}
class Suite extends Base {
constructor(title, type) {
super(title);
this._use = [];
this._entries = [];
this._hooks = [];
// Annotations known statically before running the test, e.g. `test.describe.skip()` or `test.describe({ annotation }, body)`.
this._staticAnnotations = [];
// Explicitly declared tags that are not a part of the title.
this._tags = [];
this._modifiers = [];
this._parallelMode = "none";
this._type = type;
}
get type() {
return this._type;
}
entries() {
return this._entries;
}
get suites() {
return this._entries.filter((entry) => entry instanceof Suite);
}
get tests() {
return this._entries.filter((entry) => entry instanceof TestCase);
}
_addTest(test) {
test.parent = this;
this._entries.push(test);
}
_addSuite(suite) {
suite.parent = this;
this._entries.push(suite);
}
_prependSuite(suite) {
suite.parent = this;
this._entries.unshift(suite);
}
allTests() {
const result = [];
const visit = (suite) => {
for (const entry of suite._entries) {
if (entry instanceof Suite)
visit(entry);
else
result.push(entry);
}
};
visit(this);
return result;
}
_hasTests() {
let result = false;
const visit = (suite) => {
for (const entry of suite._entries) {
if (result)
return;
if (entry instanceof Suite)
visit(entry);
else
result = true;
}
};
visit(this);
return result;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
if (this.title || this._type !== "describe")
titlePath.push(this.title);
return titlePath;
}
_collectGrepTitlePath(path) {
if (this.parent)
this.parent._collectGrepTitlePath(path);
if (this.title || this._type !== "describe")
path.push(this.title);
path.push(...this._tags);
}
_getOnlyItems() {
const items = [];
if (this._only)
items.push(this);
for (const suite of this.suites)
items.push(...suite._getOnlyItems());
items.push(...this.tests.filter((test) => test._only));
return items;
}
_deepClone() {
const suite = this._clone();
for (const entry of this._entries) {
if (entry instanceof Suite)
suite._addSuite(entry._deepClone());
else
suite._addTest(entry._clone());
}
return suite;
}
_deepSerialize() {
const suite = this._serialize();
suite.entries = [];
for (const entry of this._entries) {
if (entry instanceof Suite)
suite.entries.push(entry._deepSerialize());
else
suite.entries.push(entry._serialize());
}
return suite;
}
static _deepParse(data) {
const suite = Suite._parse(data);
for (const entry of data.entries) {
if (entry.kind === "suite")
suite._addSuite(Suite._deepParse(entry));
else
suite._addTest(TestCase._parse(entry));
}
return suite;
}
forEachTest(visitor) {
for (const entry of this._entries) {
if (entry instanceof Suite)
entry.forEachTest(visitor);
else
visitor(entry, this);
}
}
_serialize() {
return {
kind: "suite",
title: this.title,
type: this._type,
location: this.location,
only: this._only,
requireFile: this._requireFile,
timeout: this._timeout,
retries: this._retries,
staticAnnotations: this._staticAnnotations.slice(),
tags: this._tags.slice(),
modifiers: this._modifiers.slice(),
parallelMode: this._parallelMode,
hooks: this._hooks.map((h) => ({ type: h.type, location: h.location, title: h.title })),
fileId: this._fileId
};
}
static _parse(data) {
const suite = new Suite(data.title, data.type);
suite.location = data.location;
suite._only = data.only;
suite._requireFile = data.requireFile;
suite._timeout = data.timeout;
suite._retries = data.retries;
suite._staticAnnotations = data.staticAnnotations;
suite._tags = data.tags;
suite._modifiers = data.modifiers;
suite._parallelMode = data.parallelMode;
suite._hooks = data.hooks.map((h) => ({ type: h.type, location: h.location, title: h.title, fn: () => {
} }));
suite._fileId = data.fileId;
return suite;
}
_clone() {
const data = this._serialize();
const suite = Suite._parse(data);
suite._use = this._use.slice();
suite._hooks = this._hooks.slice();
suite._fullProject = this._fullProject;
return suite;
}
project() {
return this._fullProject?.project || this.parent?.project();
}
}
class TestCase extends Base {
constructor(title, fn, testType, location) {
super(title);
this.results = [];
this.type = "test";
this.expectedStatus = "passed";
this.timeout = 0;
this.annotations = [];
this.retries = 0;
this.repeatEachIndex = 0;
this.id = "";
this._poolDigest = "";
this._workerHash = "";
this._projectId = "";
// Explicitly declared tags that are not a part of the title.
this._tags = [];
this.fn = fn;
this._testType = testType;
this.location = location;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
titlePath.push(this.title);
return titlePath;
}
outcome() {
return (0, import_teleReceiver.computeTestCaseOutcome)(this);
}
ok() {
const status = this.outcome();
return status === "expected" || status === "flaky" || status === "skipped";
}
get tags() {
const titleTags = this._grepBaseTitlePath().join(" ").match(/@[\S]+/g) || [];
return [
...titleTags,
...this._tags
];
}
_serialize() {
return {
kind: "test",
id: this.id,
title: this.title,
retries: this.retries,
timeout: this.timeout,
expectedStatus: this.expectedStatus,
location: this.location,
only: this._only,
requireFile: this._requireFile,
poolDigest: this._poolDigest,
workerHash: this._workerHash,
annotations: this.annotations.slice(),
tags: this._tags.slice(),
projectId: this._projectId
};
}
static _parse(data) {
const test = new TestCase(data.title, () => {
}, import_testType.rootTestType, data.location);
test.id = data.id;
test.retries = data.retries;
test.timeout = data.timeout;
test.expectedStatus = data.expectedStatus;
test._only = data.only;
test._requireFile = data.requireFile;
test._poolDigest = data.poolDigest;
test._workerHash = data.workerHash;
test.annotations = data.annotations;
test._tags = data.tags;
test._projectId = data.projectId;
return test;
}
_clone() {
const data = this._serialize();
const test = TestCase._parse(data);
test._testType = this._testType;
test.fn = this.fn;
return test;
}
_appendTestResult() {
const result = {
retry: this.results.length,
parallelIndex: -1,
workerIndex: -1,
duration: 0,
startTime: /* @__PURE__ */ new Date(),
stdout: [],
stderr: [],
attachments: [],
status: "skipped",
steps: [],
errors: [],
annotations: []
};
this.results.push(result);
return result;
}
_grepBaseTitlePath() {
const path = [];
this.parent._collectGrepTitlePath(path);
path.push(this.title);
return path;
}
_grepTitleWithTags() {
const path = this._grepBaseTitlePath();
path.push(...this._tags);
return path.join(" ");
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Suite,
TestCase
});

View file

@ -0,0 +1,101 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var testLoader_exports = {};
__export(testLoader_exports, {
defaultTimeout: () => defaultTimeout,
loadTestFile: () => loadTestFile
});
module.exports = __toCommonJS(testLoader_exports);
var import_path = __toESM(require("path"));
var import_util = __toESM(require("util"));
var esmLoaderHost = __toESM(require("./esmLoaderHost"));
var import_globals = require("./globals");
var import_test = require("./test");
var import_compilationCache = require("../transform/compilationCache");
var import_transform = require("../transform/transform");
var import_util2 = require("../util");
const defaultTimeout = 3e4;
const cachedFileSuites = /* @__PURE__ */ new Map();
async function loadTestFile(file, config, testErrors) {
if (cachedFileSuites.has(file))
return cachedFileSuites.get(file);
const suite = new import_test.Suite(import_path.default.relative(config.config.rootDir, file) || import_path.default.basename(file), "file");
suite._requireFile = file;
suite.location = { file, line: 0, column: 0 };
suite._tags = [...config.config.tags];
(0, import_globals.setCurrentlyLoadingFileSuite)(suite);
if (!(0, import_globals.isWorkerProcess)()) {
(0, import_compilationCache.startCollectingFileDeps)();
await esmLoaderHost.startCollectingFileDeps();
}
try {
await (0, import_transform.requireOrImport)(file);
cachedFileSuites.set(file, suite);
} catch (e) {
if (!testErrors)
throw e;
testErrors.push(serializeLoadError(file, e));
} finally {
(0, import_globals.setCurrentlyLoadingFileSuite)(void 0);
if (!(0, import_globals.isWorkerProcess)()) {
(0, import_compilationCache.stopCollectingFileDeps)(file);
await esmLoaderHost.stopCollectingFileDeps(file);
}
}
{
const files = /* @__PURE__ */ new Set();
suite.allTests().map((t) => files.add(t.location.file));
if (files.size === 1) {
const mappedFile = files.values().next().value;
if (suite.location.file !== mappedFile) {
if (import_path.default.extname(mappedFile) !== import_path.default.extname(suite.location.file))
suite.location.file = mappedFile;
}
}
}
return suite;
}
function serializeLoadError(file, error) {
if (error instanceof Error) {
const result = (0, import_util2.filterStackTrace)(error);
const loc = error.loc;
result.location = loc ? {
file,
line: loc.line || 0,
column: loc.column || 0
} : void 0;
return result;
}
return { value: import_util.default.inspect(error) };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
defaultTimeout,
loadTestFile
});

298
backend/node_modules/playwright/lib/common/testType.js generated vendored Normal file
View file

@ -0,0 +1,298 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var testType_exports = {};
__export(testType_exports, {
TestTypeImpl: () => TestTypeImpl,
mergeTests: () => mergeTests,
rootTestType: () => rootTestType
});
module.exports = __toCommonJS(testType_exports);
var import_playwright_core = require("playwright-core");
var import_utils = require("playwright-core/lib/utils");
var import_globals = require("./globals");
var import_test = require("./test");
var import_expect = require("../matchers/expect");
var import_transform = require("../transform/transform");
var import_validators = require("./validators");
const testTypeSymbol = Symbol("testType");
class TestTypeImpl {
constructor(fixtures) {
this.fixtures = fixtures;
const test = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "default"));
test[testTypeSymbol] = this;
test.expect = import_expect.expect;
test.only = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "only"));
test.describe = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "default"));
test.describe.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "only"));
test.describe.configure = (0, import_transform.wrapFunctionWithLocation)(this._configure.bind(this));
test.describe.fixme = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "fixme"));
test.describe.parallel = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "parallel"));
test.describe.parallel.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "parallel.only"));
test.describe.serial = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "serial"));
test.describe.serial.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "serial.only"));
test.describe.skip = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "skip"));
test.beforeEach = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "beforeEach"));
test.afterEach = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "afterEach"));
test.beforeAll = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "beforeAll"));
test.afterAll = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "afterAll"));
test.skip = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "skip"));
test.fixme = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "fixme"));
test.fail = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "fail"));
test.fail.only = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "fail.only"));
test.slow = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "slow"));
test.setTimeout = (0, import_transform.wrapFunctionWithLocation)(this._setTimeout.bind(this));
test.step = this._step.bind(this, "pass");
test.step.skip = this._step.bind(this, "skip");
test.use = (0, import_transform.wrapFunctionWithLocation)(this._use.bind(this));
test.extend = (0, import_transform.wrapFunctionWithLocation)(this._extend.bind(this));
test.info = () => {
const result = (0, import_globals.currentTestInfo)();
if (!result)
throw new Error("test.info() can only be called while test is running");
return result;
};
this.test = test;
}
_currentSuite(location, title) {
const suite = (0, import_globals.currentlyLoadingFileSuite)();
if (!suite) {
throw new Error([
`Playwright Test did not expect ${title} to be called here.`,
`Most common reasons include:`,
`- You are calling ${title} in a configuration file.`,
`- You are calling ${title} in a file that is imported by the configuration file.`,
`- You have two different versions of @playwright/test. This usually happens`,
` when one of the dependencies in your package.json depends on @playwright/test.`
].join("\n"));
}
return suite;
}
_createTest(type, location, title, fnOrDetails, fn) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, "test()");
if (!suite)
return;
let details;
let body;
if (typeof fnOrDetails === "function") {
body = fnOrDetails;
details = {};
} else {
body = fn;
details = fnOrDetails;
}
const validatedDetails = (0, import_validators.validateTestDetails)(details, location);
const test = new import_test.TestCase(title, body, this, location);
test._requireFile = suite._requireFile;
test.annotations.push(...validatedDetails.annotations);
test._tags.push(...validatedDetails.tags);
suite._addTest(test);
if (type === "only" || type === "fail.only")
test._only = true;
if (type === "skip" || type === "fixme" || type === "fail")
test.annotations.push({ type, location });
else if (type === "fail.only")
test.annotations.push({ type: "fail", location });
}
_describe(type, location, titleOrFn, fnOrDetails, fn) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, "test.describe()");
if (!suite)
return;
let title;
let body;
let details;
if (typeof titleOrFn === "function") {
title = "";
details = {};
body = titleOrFn;
} else if (typeof fnOrDetails === "function") {
title = titleOrFn;
details = {};
body = fnOrDetails;
} else {
title = titleOrFn;
details = fnOrDetails;
body = fn;
}
const validatedDetails = (0, import_validators.validateTestDetails)(details, location);
const child = new import_test.Suite(title, "describe");
child._requireFile = suite._requireFile;
child.location = location;
child._staticAnnotations.push(...validatedDetails.annotations);
child._tags.push(...validatedDetails.tags);
suite._addSuite(child);
if (type === "only" || type === "serial.only" || type === "parallel.only")
child._only = true;
if (type === "serial" || type === "serial.only")
child._parallelMode = "serial";
if (type === "parallel" || type === "parallel.only")
child._parallelMode = "parallel";
if (type === "skip" || type === "fixme")
child._staticAnnotations.push({ type, location });
for (let parent = suite; parent; parent = parent.parent) {
if (parent._parallelMode === "serial" && child._parallelMode === "parallel")
throw new Error("describe.parallel cannot be nested inside describe.serial");
if (parent._parallelMode === "default" && child._parallelMode === "parallel")
throw new Error("describe.parallel cannot be nested inside describe with default mode");
}
(0, import_globals.setCurrentlyLoadingFileSuite)(child);
body();
(0, import_globals.setCurrentlyLoadingFileSuite)(suite);
}
_hook(name, location, title, fn) {
const suite = this._currentSuite(location, `test.${name}()`);
if (!suite)
return;
if (typeof title === "function") {
fn = title;
title = `${name} hook`;
}
suite._hooks.push({ type: name, fn, title, location });
}
_configure(location, options) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, `test.describe.configure()`);
if (!suite)
return;
if (options.timeout !== void 0)
suite._timeout = options.timeout;
if (options.retries !== void 0)
suite._retries = options.retries;
if (options.mode !== void 0) {
if (suite._parallelMode !== "none")
throw new Error(`"${suite._parallelMode}" mode is already assigned for the enclosing scope.`);
suite._parallelMode = options.mode;
for (let parent = suite.parent; parent; parent = parent.parent) {
if (parent._parallelMode === "serial" && suite._parallelMode === "parallel")
throw new Error("describe with parallel mode cannot be nested inside describe with serial mode");
if (parent._parallelMode === "default" && suite._parallelMode === "parallel")
throw new Error("describe with parallel mode cannot be nested inside describe with default mode");
}
}
}
_modifier(type, location, ...modifierArgs) {
const suite = (0, import_globals.currentlyLoadingFileSuite)();
if (suite) {
if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "function" && (type === "skip" || type === "fixme" || type === "fail")) {
this._createTest(type, location, modifierArgs[0], modifierArgs[1]);
return;
}
if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "object" && typeof modifierArgs[2] === "function" && (type === "skip" || type === "fixme" || type === "fail")) {
this._createTest(type, location, modifierArgs[0], modifierArgs[1], modifierArgs[2]);
return;
}
if (typeof modifierArgs[0] === "function") {
suite._modifiers.push({ type, fn: modifierArgs[0], location, description: modifierArgs[1] });
} else {
if (modifierArgs.length >= 1 && !modifierArgs[0])
return;
const description = modifierArgs[1];
suite._staticAnnotations.push({ type, description, location });
}
return;
}
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`test.${type}() can only be called inside test, describe block or fixture`);
if (typeof modifierArgs[0] === "function")
throw new Error(`test.${type}() with a function can only be called inside describe block`);
testInfo._modifier(type, location, modifierArgs);
}
_setTimeout(location, timeout) {
const suite = (0, import_globals.currentlyLoadingFileSuite)();
if (suite) {
suite._timeout = timeout;
return;
}
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`test.setTimeout() can only be called from a test`);
testInfo.setTimeout(timeout);
}
_use(location, fixtures) {
const suite = this._currentSuite(location, `test.use()`);
if (!suite)
return;
suite._use.push({ fixtures, location });
}
async _step(expectation, title, body, options = {}) {
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`test.step() can only be called from a test`);
const step = testInfo._addStep({ category: "test.step", title, location: options.location, box: options.box });
return await (0, import_utils.currentZone)().with("stepZone", step).run(async () => {
try {
let result = void 0;
result = await (0, import_utils.raceAgainstDeadline)(async () => {
try {
return await step.info._runStepBody(expectation === "skip", body, step.location);
} catch (e) {
if (result?.timedOut)
testInfo._failWithError(e);
throw e;
}
}, options.timeout ? (0, import_utils.monotonicTime)() + options.timeout : 0);
if (result.timedOut)
throw new import_playwright_core.errors.TimeoutError(`Step timeout of ${options.timeout}ms exceeded.`);
step.complete({});
return result.result;
} catch (error) {
step.complete({ error });
throw error;
}
});
}
_extend(location, fixtures) {
if (fixtures[testTypeSymbol])
throw new Error(`test.extend() accepts fixtures object, not a test object.
Did you mean to call mergeTests()?`);
const fixturesWithLocation = { fixtures, location };
return new TestTypeImpl([...this.fixtures, fixturesWithLocation]).test;
}
}
function throwIfRunningInsideJest() {
if (process.env.JEST_WORKER_ID) {
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
throw new Error(
`Playwright Test needs to be invoked via '${packageManagerCommand} playwright test' and excluded from Jest test runs.
Creating one directory for Playwright tests and one for Jest is the recommended way of doing it.
See https://playwright.dev/docs/intro for more information about Playwright Test.`
);
}
}
const rootTestType = new TestTypeImpl([]);
function mergeTests(...tests) {
let result = rootTestType;
for (const t of tests) {
const testTypeImpl = t[testTypeSymbol];
if (!testTypeImpl)
throw new Error(`mergeTests() accepts "test" functions as parameters.
Did you mean to call test.extend() with fixtures instead?`);
const newFixtures = testTypeImpl.fixtures.filter((theirs) => !result.fixtures.find((ours) => ours.fixtures === theirs.fixtures));
result = new TestTypeImpl([...result.fixtures, ...newFixtures]);
}
return result.test;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TestTypeImpl,
mergeTests,
rootTestType
});

View file

@ -0,0 +1,68 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var validators_exports = {};
__export(validators_exports, {
validateTestAnnotation: () => validateTestAnnotation,
validateTestDetails: () => validateTestDetails
});
module.exports = __toCommonJS(validators_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
const testAnnotationSchema = import_mcpBundle.z.object({
type: import_mcpBundle.z.string(),
description: import_mcpBundle.z.string().optional()
});
const testDetailsSchema = import_mcpBundle.z.object({
tag: import_mcpBundle.z.union([
import_mcpBundle.z.string().optional(),
import_mcpBundle.z.array(import_mcpBundle.z.string())
]).transform((val) => Array.isArray(val) ? val : val !== void 0 ? [val] : []).refine((val) => val.every((v) => v.startsWith("@")), {
message: "Tag must start with '@'"
}),
annotation: import_mcpBundle.z.union([
testAnnotationSchema,
import_mcpBundle.z.array(testAnnotationSchema).optional()
]).transform((val) => Array.isArray(val) ? val : val !== void 0 ? [val] : [])
});
function validateTestAnnotation(annotation) {
try {
return testAnnotationSchema.parse(annotation);
} catch (error) {
throwZodError(error);
}
}
function validateTestDetails(details, location) {
try {
const parsedDetails = testDetailsSchema.parse(details);
return {
annotations: parsedDetails.annotation.map((a) => ({ ...a, location })),
tags: parsedDetails.tag,
location
};
} catch (error) {
throwZodError(error);
}
}
function throwZodError(error) {
throw new Error(error.issues.map((i) => i.message).join("\n"));
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
validateTestAnnotation,
validateTestDetails
});

67
backend/node_modules/playwright/lib/fsWatcher.js generated vendored Normal file
View file

@ -0,0 +1,67 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var fsWatcher_exports = {};
__export(fsWatcher_exports, {
Watcher: () => Watcher
});
module.exports = __toCommonJS(fsWatcher_exports);
var import_utilsBundle = require("./utilsBundle");
class Watcher {
constructor(onChange) {
this._watchedPaths = [];
this._ignoredFolders = [];
this._collector = [];
this._onChange = onChange;
}
async update(watchedPaths, ignoredFolders, reportPending) {
if (JSON.stringify([this._watchedPaths, this._ignoredFolders]) === JSON.stringify([watchedPaths, ignoredFolders]))
return;
if (reportPending)
this._reportEventsIfAny();
this._watchedPaths = watchedPaths;
this._ignoredFolders = ignoredFolders;
void this._fsWatcher?.close();
this._fsWatcher = void 0;
this._collector.length = 0;
clearTimeout(this._throttleTimer);
this._throttleTimer = void 0;
if (!this._watchedPaths.length)
return;
const ignored = [...this._ignoredFolders, "**/node_modules/**"];
this._fsWatcher = import_utilsBundle.chokidar.watch(watchedPaths, { ignoreInitial: true, ignored }).on("all", async (event, file) => {
if (this._throttleTimer)
clearTimeout(this._throttleTimer);
this._collector.push({ event, file });
this._throttleTimer = setTimeout(() => this._reportEventsIfAny(), 250);
});
await new Promise((resolve, reject) => this._fsWatcher.once("ready", resolve).once("error", reject));
}
async close() {
await this._fsWatcher?.close();
}
_reportEventsIfAny() {
if (this._collector.length)
this._onChange(this._collector.slice());
this._collector.length = 0;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Watcher
});

726
backend/node_modules/playwright/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,726 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var index_exports = {};
__export(index_exports, {
_baseTest: () => _baseTest,
defineConfig: () => import_configLoader.defineConfig,
expect: () => import_expect.expect,
mergeExpects: () => import_expect2.mergeExpects,
mergeTests: () => import_testType2.mergeTests,
test: () => test
});
module.exports = __toCommonJS(index_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var playwrightLibrary = __toESM(require("playwright-core"));
var import_utils = require("playwright-core/lib/utils");
var import_globals = require("./common/globals");
var import_testType = require("./common/testType");
var import_browserBackend = require("./mcp/test/browserBackend");
var import_expect = require("./matchers/expect");
var import_configLoader = require("./common/configLoader");
var import_testType2 = require("./common/testType");
var import_expect2 = require("./matchers/expect");
const _baseTest = import_testType.rootTestType.test;
(0, import_utils.setBoxedStackPrefixes)([import_path.default.dirname(require.resolve("../package.json"))]);
if (process["__pw_initiator__"]) {
const originalStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 200;
try {
throw new Error("Requiring @playwright/test second time, \nFirst:\n" + process["__pw_initiator__"] + "\n\nSecond: ");
} finally {
Error.stackTraceLimit = originalStackTraceLimit;
}
} else {
process["__pw_initiator__"] = new Error().stack;
}
const playwrightFixtures = {
defaultBrowserType: ["chromium", { scope: "worker", option: true, box: true }],
browserName: [({ defaultBrowserType }, use) => use(defaultBrowserType), { scope: "worker", option: true, box: true }],
playwright: [async ({}, use) => {
await use(require("playwright-core"));
}, { scope: "worker", box: true }],
headless: [({ launchOptions }, use) => use(launchOptions.headless ?? true), { scope: "worker", option: true, box: true }],
channel: [({ launchOptions }, use) => use(launchOptions.channel), { scope: "worker", option: true, box: true }],
launchOptions: [{}, { scope: "worker", option: true, box: true }],
connectOptions: [async ({ _optionConnectOptions }, use) => {
await use(connectOptionsFromEnv() || _optionConnectOptions);
}, { scope: "worker", option: true, box: true }],
screenshot: ["off", { scope: "worker", option: true, box: true }],
video: ["off", { scope: "worker", option: true, box: true }],
trace: ["off", { scope: "worker", option: true, box: true }],
_browserOptions: [async ({ playwright, headless, channel, launchOptions }, use) => {
const options = {
handleSIGINT: false,
...launchOptions,
tracesDir: tracing().tracesDir()
};
if (headless !== void 0)
options.headless = headless;
if (channel !== void 0)
options.channel = channel;
playwright._defaultLaunchOptions = options;
await use(options);
playwright._defaultLaunchOptions = void 0;
}, { scope: "worker", auto: true, box: true }],
browser: [async ({ playwright, browserName, _browserOptions, connectOptions }, use) => {
if (!["chromium", "firefox", "webkit"].includes(browserName))
throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
if (connectOptions) {
const browser2 = await playwright[browserName].connect({
...connectOptions,
exposeNetwork: connectOptions.exposeNetwork ?? connectOptions._exposeNetwork,
headers: {
// HTTP headers are ASCII only (not UTF-8).
"x-playwright-launch-options": (0, import_utils.jsonStringifyForceASCII)(_browserOptions),
...connectOptions.headers
}
});
await use(browser2);
await browser2.close({ reason: "Test ended." });
return;
}
const browser = await playwright[browserName].launch();
await use(browser);
await browser.close({ reason: "Test ended." });
}, { scope: "worker", timeout: 0 }],
acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true, box: true }],
bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP ?? false), { option: true, box: true }],
colorScheme: [({ contextOptions }, use) => use(contextOptions.colorScheme === void 0 ? "light" : contextOptions.colorScheme), { option: true, box: true }],
deviceScaleFactor: [({ contextOptions }, use) => use(contextOptions.deviceScaleFactor), { option: true, box: true }],
extraHTTPHeaders: [({ contextOptions }, use) => use(contextOptions.extraHTTPHeaders), { option: true, box: true }],
geolocation: [({ contextOptions }, use) => use(contextOptions.geolocation), { option: true, box: true }],
hasTouch: [({ contextOptions }, use) => use(contextOptions.hasTouch ?? false), { option: true, box: true }],
httpCredentials: [({ contextOptions }, use) => use(contextOptions.httpCredentials), { option: true, box: true }],
ignoreHTTPSErrors: [({ contextOptions }, use) => use(contextOptions.ignoreHTTPSErrors ?? false), { option: true, box: true }],
isMobile: [({ contextOptions }, use) => use(contextOptions.isMobile ?? false), { option: true, box: true }],
javaScriptEnabled: [({ contextOptions }, use) => use(contextOptions.javaScriptEnabled ?? true), { option: true, box: true }],
locale: [({ contextOptions }, use) => use(contextOptions.locale ?? "en-US"), { option: true, box: true }],
offline: [({ contextOptions }, use) => use(contextOptions.offline ?? false), { option: true, box: true }],
permissions: [({ contextOptions }, use) => use(contextOptions.permissions), { option: true, box: true }],
proxy: [({ contextOptions }, use) => use(contextOptions.proxy), { option: true, box: true }],
storageState: [({ contextOptions }, use) => use(contextOptions.storageState), { option: true, box: true }],
clientCertificates: [({ contextOptions }, use) => use(contextOptions.clientCertificates), { option: true, box: true }],
timezoneId: [({ contextOptions }, use) => use(contextOptions.timezoneId), { option: true, box: true }],
userAgent: [({ contextOptions }, use) => use(contextOptions.userAgent), { option: true, box: true }],
viewport: [({ contextOptions }, use) => use(contextOptions.viewport === void 0 ? { width: 1280, height: 720 } : contextOptions.viewport), { option: true, box: true }],
actionTimeout: [0, { option: true, box: true }],
testIdAttribute: ["data-testid", { option: true, box: true }],
navigationTimeout: [0, { option: true, box: true }],
baseURL: [async ({}, use) => {
await use(process.env.PLAYWRIGHT_TEST_BASE_URL);
}, { option: true, box: true }],
serviceWorkers: [({ contextOptions }, use) => use(contextOptions.serviceWorkers ?? "allow"), { option: true, box: true }],
contextOptions: [{}, { option: true, box: true }],
agentOptions: [void 0, { option: true, box: true }],
_combinedContextOptions: [async ({
acceptDownloads,
bypassCSP,
clientCertificates,
colorScheme,
deviceScaleFactor,
extraHTTPHeaders,
hasTouch,
geolocation,
httpCredentials,
ignoreHTTPSErrors,
isMobile,
javaScriptEnabled,
locale,
offline,
permissions,
proxy,
storageState,
viewport,
timezoneId,
userAgent,
baseURL,
contextOptions,
serviceWorkers
}, use, testInfo) => {
const options = {};
if (acceptDownloads !== void 0)
options.acceptDownloads = acceptDownloads;
if (bypassCSP !== void 0)
options.bypassCSP = bypassCSP;
if (colorScheme !== void 0)
options.colorScheme = colorScheme;
if (deviceScaleFactor !== void 0)
options.deviceScaleFactor = deviceScaleFactor;
if (extraHTTPHeaders !== void 0)
options.extraHTTPHeaders = extraHTTPHeaders;
if (geolocation !== void 0)
options.geolocation = geolocation;
if (hasTouch !== void 0)
options.hasTouch = hasTouch;
if (httpCredentials !== void 0)
options.httpCredentials = httpCredentials;
if (ignoreHTTPSErrors !== void 0)
options.ignoreHTTPSErrors = ignoreHTTPSErrors;
if (isMobile !== void 0)
options.isMobile = isMobile;
if (javaScriptEnabled !== void 0)
options.javaScriptEnabled = javaScriptEnabled;
if (locale !== void 0)
options.locale = locale;
if (offline !== void 0)
options.offline = offline;
if (permissions !== void 0)
options.permissions = permissions;
if (proxy !== void 0)
options.proxy = proxy;
if (storageState !== void 0)
options.storageState = storageState;
if (clientCertificates?.length)
options.clientCertificates = resolveClientCerticates(clientCertificates);
if (timezoneId !== void 0)
options.timezoneId = timezoneId;
if (userAgent !== void 0)
options.userAgent = userAgent;
if (viewport !== void 0)
options.viewport = viewport;
if (baseURL !== void 0)
options.baseURL = baseURL;
if (serviceWorkers !== void 0)
options.serviceWorkers = serviceWorkers;
await use({
...contextOptions,
...options
});
}, { box: true }],
_setupContextOptions: [async ({ playwright, actionTimeout, navigationTimeout, testIdAttribute }, use, testInfo) => {
if (testIdAttribute)
playwrightLibrary.selectors.setTestIdAttribute(testIdAttribute);
testInfo.snapshotSuffix = process.platform;
if ((0, import_utils.debugMode)() === "inspector")
testInfo._setDebugMode();
playwright._defaultContextTimeout = actionTimeout || 0;
playwright._defaultContextNavigationTimeout = navigationTimeout || 0;
await use();
playwright._defaultContextTimeout = void 0;
playwright._defaultContextNavigationTimeout = void 0;
}, { auto: "all-hooks-included", title: "context configuration", box: true }],
_setupArtifacts: [async ({ playwright, screenshot, _combinedContextOptions }, use, testInfo) => {
testInfo.setTimeout(testInfo.project.timeout);
const artifactsRecorder = new ArtifactsRecorder(playwright, tracing().artifactsDir(), screenshot);
await artifactsRecorder.willStartTest(testInfo);
const tracingGroupSteps = [];
const csiListener = {
onApiCallBegin: (data, channel) => {
const testInfo2 = (0, import_globals.currentTestInfo)();
if (!testInfo2 || data.apiName.includes("setTestIdAttribute") || data.apiName === "tracing.groupEnd")
return;
const zone = (0, import_utils.currentZone)().data("stepZone");
const isExpectCall = data.apiName === "locator._expect" || data.apiName === "frame._expect" || data.apiName === "page._expectScreenshot";
if (zone && zone.category === "expect" && isExpectCall) {
if (zone.apiName)
data.apiName = zone.apiName;
if (zone.shortTitle || zone.title)
data.title = zone.shortTitle ?? zone.title;
data.stepId = zone.stepId;
return;
}
const step = testInfo2._addStep({
location: data.frames[0],
category: "pw:api",
title: renderTitle(channel.type, channel.method, channel.params, data.title),
apiName: data.apiName,
params: channel.params,
group: (0, import_utils.getActionGroup)({ type: channel.type, method: channel.method })
}, tracingGroupSteps[tracingGroupSteps.length - 1]);
data.userData = step;
data.stepId = step.stepId;
if (data.apiName === "tracing.group")
tracingGroupSteps.push(step);
},
onApiCallEnd: (data) => {
if (data.apiName === "tracing.group")
return;
if (data.apiName === "tracing.groupEnd") {
const step2 = tracingGroupSteps.pop();
step2?.complete({ error: data.error });
return;
}
const step = data.userData;
step?.complete({ error: data.error });
},
onWillPause: ({ keepTestTimeout }) => {
if (!keepTestTimeout)
(0, import_globals.currentTestInfo)()?._setDebugMode();
},
runBeforeCreateBrowserContext: async (options) => {
for (const [key, value] of Object.entries(_combinedContextOptions)) {
if (!(key in options))
options[key] = value;
}
},
runBeforeCreateRequestContext: async (options) => {
for (const [key, value] of Object.entries(_combinedContextOptions)) {
if (!(key in options))
options[key] = value;
}
},
runAfterCreateBrowserContext: async (context) => {
await artifactsRecorder.didCreateBrowserContext(context);
const testInfo2 = (0, import_globals.currentTestInfo)();
if (testInfo2)
attachConnectedHeaderIfNeeded(testInfo2, context.browser());
},
runAfterCreateRequestContext: async (context) => {
await artifactsRecorder.didCreateRequestContext(context);
},
runBeforeCloseBrowserContext: async (context) => {
await artifactsRecorder.willCloseBrowserContext(context);
},
runBeforeCloseRequestContext: async (context) => {
await artifactsRecorder.willCloseRequestContext(context);
}
};
const clientInstrumentation = playwright._instrumentation;
clientInstrumentation.addListener(csiListener);
await use();
clientInstrumentation.removeListener(csiListener);
await artifactsRecorder.didFinishTest();
}, { auto: "all-hooks-included", title: "trace recording", box: true, timeout: 0 }],
_contextFactory: [async ({
browser,
video,
_reuseContext,
_combinedContextOptions
/** mitigate dep-via-auto lack of traceability */
}, use, testInfo) => {
const testInfoImpl = testInfo;
const videoMode = normalizeVideoMode(video);
const captureVideo = shouldCaptureVideo(videoMode, testInfo) && !_reuseContext;
const contexts = /* @__PURE__ */ new Map();
let counter = 0;
await use(async (options) => {
const hook = testInfoImpl._currentHookType();
if (hook === "beforeAll" || hook === "afterAll") {
throw new Error([
`"context" and "page" fixtures are not supported in "${hook}" since they are created on a per-test basis.`,
`If you would like to reuse a single page between tests, create context manually with browser.newContext(). See https://aka.ms/playwright/reuse-page for details.`,
`If you would like to configure your page before each test, do that in beforeEach hook instead.`
].join("\n"));
}
const videoOptions = captureVideo ? {
recordVideo: {
dir: tracing().artifactsDir(),
size: typeof video === "string" ? void 0 : video.size
}
} : {};
const context = await browser.newContext({ ...videoOptions, ...options });
if (process.env.PW_CLOCK === "frozen") {
await context._wrapApiCall(async () => {
await context.clock.install({ time: 0 });
await context.clock.pauseAt(1e3);
}, { internal: true });
} else if (process.env.PW_CLOCK === "realtime") {
await context._wrapApiCall(async () => {
await context.clock.install({ time: 0 });
}, { internal: true });
}
let closed = false;
const close = async () => {
if (closed)
return;
closed = true;
const closeReason = testInfo.status === "timedOut" ? "Test timeout of " + testInfo.timeout + "ms exceeded." : "Test ended.";
await context.close({ reason: closeReason });
const testFailed = testInfo.status !== testInfo.expectedStatus;
const preserveVideo = captureVideo && (videoMode === "on" || testFailed && videoMode === "retain-on-failure" || videoMode === "on-first-retry" && testInfo.retry === 1);
if (preserveVideo) {
const { pagesWithVideo: pagesForVideo } = contexts.get(context);
const videos = pagesForVideo.map((p) => p.video()).filter((video2) => !!video2);
await Promise.all(videos.map(async (v) => {
try {
const savedPath = testInfo.outputPath(`video${counter ? "-" + counter : ""}.webm`);
++counter;
await v.saveAs(savedPath);
testInfo.attachments.push({ name: "video", path: savedPath, contentType: "video/webm" });
} catch (e) {
}
}));
}
};
const contextData = { close, pagesWithVideo: [] };
if (captureVideo)
context.on("page", (page) => contextData.pagesWithVideo.push(page));
contexts.set(context, contextData);
return { context, close };
});
await Promise.all([...contexts.values()].map((data) => data.close()));
}, { scope: "test", title: "context", box: true }],
_optionContextReuseMode: ["none", { scope: "worker", option: true, box: true }],
_optionConnectOptions: [void 0, { scope: "worker", option: true, box: true }],
_reuseContext: [async ({ video, _optionContextReuseMode }, use) => {
let mode = _optionContextReuseMode;
if (process.env.PW_TEST_REUSE_CONTEXT)
mode = "when-possible";
const reuse = mode === "when-possible" && normalizeVideoMode(video) === "off";
await use(reuse);
}, { scope: "worker", title: "context", box: true }],
context: async ({ browser, _reuseContext, _contextFactory }, use, testInfo) => {
const browserImpl = browser;
attachConnectedHeaderIfNeeded(testInfo, browserImpl);
if (!_reuseContext) {
const { context: context2, close } = await _contextFactory();
testInfo._onCustomMessageCallback = (0, import_browserBackend.createCustomMessageHandler)(testInfo, context2);
await use(context2);
await close();
return;
}
const context = await browserImpl._wrapApiCall(() => browserImpl._newContextForReuse(), { internal: true });
testInfo._onCustomMessageCallback = (0, import_browserBackend.createCustomMessageHandler)(testInfo, context);
await use(context);
const closeReason = testInfo.status === "timedOut" ? "Test timeout of " + testInfo.timeout + "ms exceeded." : "Test ended.";
await browserImpl._wrapApiCall(() => browserImpl._disconnectFromReusedContext(closeReason), { internal: true });
},
page: async ({ context, _reuseContext }, use) => {
if (!_reuseContext) {
await use(await context.newPage());
return;
}
let [page] = context.pages();
if (!page)
page = await context.newPage();
await use(page);
},
agent: async ({ page, agentOptions }, use, testInfo) => {
const testInfoImpl = testInfo;
const cachePathTemplate = agentOptions?.cachePathTemplate ?? "{testDir}/{testFilePath}-cache.json";
const resolvedCacheFile = testInfoImpl._applyPathTemplate(cachePathTemplate, "", ".json");
const cacheFile = testInfoImpl.config.runAgents === "all" ? void 0 : await testInfoImpl._cloneStorage(resolvedCacheFile);
const cacheOutFile = import_path.default.join(testInfoImpl.artifactsDir(), "agent-cache-" + (0, import_utils.createGuid)() + ".json");
const provider = agentOptions?.provider && testInfo.config.runAgents !== "none" ? agentOptions.provider : void 0;
if (provider)
testInfo.setTimeout(0);
const cache = {
cacheFile,
cacheOutFile
};
const agent = await page.agent({
provider,
cache,
limits: agentOptions?.limits,
secrets: agentOptions?.secrets,
systemPrompt: agentOptions?.systemPrompt,
expect: {
timeout: testInfoImpl._projectInternal.expect?.timeout
}
});
await use(agent);
const usage = await agent.usage();
if (usage.turns > 0)
await testInfoImpl.attach("agent-usage", { contentType: "application/json", body: Buffer.from(JSON.stringify(usage, null, 2)) });
if (!resolvedCacheFile || !cacheOutFile)
return;
if (testInfo.status !== "passed")
return;
await testInfoImpl._upstreamStorage(resolvedCacheFile, cacheOutFile);
},
request: async ({ playwright }, use) => {
const request = await playwright.request.newContext();
await use(request);
const hook = test.info()._currentHookType();
if (hook === "beforeAll") {
await request.dispose({ reason: [
`Fixture { request } from beforeAll cannot be reused in a test.`,
` - Recommended fix: use a separate { request } in the test.`,
` - Alternatively, manually create APIRequestContext in beforeAll and dispose it in afterAll.`,
`See https://playwright.dev/docs/api-testing#sending-api-requests-from-ui-tests for more details.`
].join("\n") });
} else {
await request.dispose();
}
}
};
function normalizeVideoMode(video) {
if (!video)
return "off";
let videoMode = typeof video === "string" ? video : video.mode;
if (videoMode === "retry-with-video")
videoMode = "on-first-retry";
return videoMode;
}
function shouldCaptureVideo(videoMode, testInfo) {
return videoMode === "on" || videoMode === "retain-on-failure" || videoMode === "on-first-retry" && testInfo.retry === 1;
}
function normalizeScreenshotMode(screenshot) {
if (!screenshot)
return "off";
return typeof screenshot === "string" ? screenshot : screenshot.mode;
}
function attachConnectedHeaderIfNeeded(testInfo, browser) {
const connectHeaders = browser?._connection.headers;
if (!connectHeaders)
return;
for (const header of connectHeaders) {
if (header.name !== "x-playwright-attachment")
continue;
const [name, value] = header.value.split("=");
if (!name || !value)
continue;
if (testInfo.attachments.some((attachment) => attachment.name === name))
continue;
testInfo.attachments.push({ name, contentType: "text/plain", body: Buffer.from(value) });
}
}
function resolveFileToConfig(file) {
const config = test.info().config.configFile;
if (!config || !file)
return file;
if (import_path.default.isAbsolute(file))
return file;
return import_path.default.resolve(import_path.default.dirname(config), file);
}
function resolveClientCerticates(clientCertificates) {
for (const cert of clientCertificates) {
cert.certPath = resolveFileToConfig(cert.certPath);
cert.keyPath = resolveFileToConfig(cert.keyPath);
cert.pfxPath = resolveFileToConfig(cert.pfxPath);
}
return clientCertificates;
}
const kTracingStarted = Symbol("kTracingStarted");
function connectOptionsFromEnv() {
const wsEndpoint = process.env.PW_TEST_CONNECT_WS_ENDPOINT;
if (!wsEndpoint)
return void 0;
const headers = process.env.PW_TEST_CONNECT_HEADERS ? JSON.parse(process.env.PW_TEST_CONNECT_HEADERS) : void 0;
return {
wsEndpoint,
headers,
exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK
};
}
class SnapshotRecorder {
constructor(_artifactsRecorder, _mode, _name, _contentType, _extension, _doSnapshot) {
this._artifactsRecorder = _artifactsRecorder;
this._mode = _mode;
this._name = _name;
this._contentType = _contentType;
this._extension = _extension;
this._doSnapshot = _doSnapshot;
this._ordinal = 0;
this._temporary = [];
}
fixOrdinal() {
this._ordinal = this.testInfo.attachments.filter((a) => a.name === this._name).length;
}
shouldCaptureUponFinish() {
return this._mode === "on" || this._mode === "only-on-failure" && this.testInfo._isFailure() || this._mode === "on-first-failure" && this.testInfo._isFailure() && this.testInfo.retry === 0;
}
async maybeCapture() {
if (!this.shouldCaptureUponFinish())
return;
await Promise.all(this._artifactsRecorder._playwright._allPages().map((page) => this._snapshotPage(page, false)));
}
async persistTemporary() {
if (this.shouldCaptureUponFinish()) {
await Promise.all(this._temporary.map(async (file) => {
try {
const path2 = this._createAttachmentPath();
await import_fs.default.promises.rename(file, path2);
this._attach(path2);
} catch {
}
}));
}
}
async captureTemporary(context) {
if (this._mode === "on" || this._mode === "only-on-failure" || this._mode === "on-first-failure" && this.testInfo.retry === 0)
await Promise.all(context.pages().map((page) => this._snapshotPage(page, true)));
}
_attach(screenshotPath) {
this.testInfo.attachments.push({ name: this._name, path: screenshotPath, contentType: this._contentType });
}
_createAttachmentPath() {
const testFailed = this.testInfo._isFailure();
const index = this._ordinal + 1;
++this._ordinal;
const path2 = this.testInfo.outputPath(`test-${testFailed ? "failed" : "finished"}-${index}${this._extension}`);
return path2;
}
_createTemporaryArtifact(...name) {
const file = import_path.default.join(this._artifactsRecorder._artifactsDir, ...name);
return file;
}
async _snapshotPage(page, temporary) {
if (page[this.testInfo._uniqueSymbol])
return;
page[this.testInfo._uniqueSymbol] = true;
try {
const path2 = temporary ? this._createTemporaryArtifact((0, import_utils.createGuid)() + this._extension) : this._createAttachmentPath();
await this._doSnapshot(page, path2);
if (temporary)
this._temporary.push(path2);
else
this._attach(path2);
} catch {
}
}
get testInfo() {
return this._artifactsRecorder._testInfo;
}
}
class ArtifactsRecorder {
constructor(playwright, artifactsDir, screenshot) {
this._playwright = playwright;
this._artifactsDir = artifactsDir;
const screenshotOptions = typeof screenshot === "string" ? void 0 : screenshot;
this._startedCollectingArtifacts = Symbol("startedCollectingArtifacts");
this._screenshotRecorder = new SnapshotRecorder(this, normalizeScreenshotMode(screenshot), "screenshot", "image/png", ".png", async (page, path2) => {
await page._wrapApiCall(async () => {
await page.screenshot({ ...screenshotOptions, timeout: 5e3, path: path2, caret: "initial" });
}, { internal: true });
});
}
async willStartTest(testInfo) {
this._testInfo = testInfo;
testInfo._onDidFinishTestFunctionCallback = () => this.didFinishTestFunction();
this._screenshotRecorder.fixOrdinal();
await Promise.all(this._playwright._allContexts().map((context) => this.didCreateBrowserContext(context)));
const existingApiRequests = Array.from(this._playwright.request._contexts);
await Promise.all(existingApiRequests.map((c) => this.didCreateRequestContext(c)));
}
async didCreateBrowserContext(context) {
await this._startTraceChunkOnContextCreation(context, context.tracing);
}
async willCloseBrowserContext(context) {
await this._stopTracing(context, context.tracing);
await this._screenshotRecorder.captureTemporary(context);
await this._takePageSnapshot(context);
}
async _takePageSnapshot(context) {
if (process.env.PLAYWRIGHT_NO_COPY_PROMPT)
return;
if (this._testInfo.errors.length === 0)
return;
if (this._pageSnapshot)
return;
const page = context.pages()[0];
if (!page)
return;
try {
await page._wrapApiCall(async () => {
this._pageSnapshot = (await page._snapshotForAI({ timeout: 5e3 })).full;
}, { internal: true });
} catch {
}
}
async didCreateRequestContext(context) {
await this._startTraceChunkOnContextCreation(context, context._tracing);
}
async willCloseRequestContext(context) {
await this._stopTracing(context, context._tracing);
}
async didFinishTestFunction() {
await this._screenshotRecorder.maybeCapture();
}
async didFinishTest() {
await this.didFinishTestFunction();
const leftoverContexts = this._playwright._allContexts();
const leftoverApiRequests = Array.from(this._playwright.request._contexts);
await Promise.all(leftoverContexts.map(async (context2) => {
await this._stopTracing(context2, context2.tracing);
}).concat(leftoverApiRequests.map(async (context2) => {
await this._stopTracing(context2, context2._tracing);
})));
await this._screenshotRecorder.persistTemporary();
const context = leftoverContexts[0];
if (context)
await this._takePageSnapshot(context);
if (this._pageSnapshot && this._testInfo.errors.length > 0 && !this._testInfo.attachments.some((a) => a.name === "error-context")) {
const lines = [
"# Page snapshot",
"",
"```yaml",
this._pageSnapshot,
"```"
];
const filePath = this._testInfo.outputPath("error-context.md");
await import_fs.default.promises.writeFile(filePath, lines.join("\n"), "utf8");
this._testInfo._attach({
name: "error-context",
contentType: "text/markdown",
path: filePath
}, void 0);
}
}
async _startTraceChunkOnContextCreation(channelOwner, tracing2) {
await channelOwner._wrapApiCall(async () => {
const options = this._testInfo._tracing.traceOptions();
if (options) {
const title = this._testInfo._tracing.traceTitle();
const name = this._testInfo._tracing.generateNextTraceRecordingName();
if (!tracing2[kTracingStarted]) {
await tracing2.start({ ...options, title, name });
tracing2[kTracingStarted] = true;
} else {
await tracing2.startChunk({ title, name });
}
} else {
if (tracing2[kTracingStarted]) {
tracing2[kTracingStarted] = false;
await tracing2.stop();
}
}
}, { internal: true });
}
async _stopTracing(channelOwner, tracing2) {
await channelOwner._wrapApiCall(async () => {
if (tracing2[this._startedCollectingArtifacts])
return;
tracing2[this._startedCollectingArtifacts] = true;
if (this._testInfo._tracing.traceOptions() && tracing2[kTracingStarted])
await tracing2.stopChunk({ path: this._testInfo._tracing.maybeGenerateNextTraceRecordingPath() });
}, { internal: true });
}
}
function renderTitle(type, method, params, title) {
const prefix = (0, import_utils.renderTitleForCall)({ title, type, method, params });
let selector;
if (params?.["selector"] && typeof params.selector === "string")
selector = (0, import_utils.asLocatorDescription)("javascript", params.selector);
return prefix + (selector ? ` ${selector}` : "");
}
function tracing() {
return test.info()._tracing;
}
const test = _baseTest.extend(playwrightFixtures);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
_baseTest,
defineConfig,
expect,
mergeExpects,
mergeTests,
test
});

View file

@ -0,0 +1,42 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var internalsForTest_exports = {};
__export(internalsForTest_exports, {
fileDependencies: () => fileDependencies
});
module.exports = __toCommonJS(internalsForTest_exports);
var import_path = __toESM(require("path"));
var import_compilationCache = require("./transform/compilationCache");
function fileDependencies() {
return Object.fromEntries([...(0, import_compilationCache.fileDependenciesForTest)().entries()].map((entry) => [import_path.default.basename(entry[0]), [...entry[1]].map((f) => import_path.default.basename(f)).sort()]));
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
fileDependencies
});

View file

@ -0,0 +1,77 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var events_exports = {};
__export(events_exports, {
Disposable: () => Disposable,
EventEmitter: () => EventEmitter
});
module.exports = __toCommonJS(events_exports);
var Disposable;
((Disposable2) => {
function disposeAll(disposables) {
for (const disposable of disposables.splice(0))
disposable.dispose();
}
Disposable2.disposeAll = disposeAll;
})(Disposable || (Disposable = {}));
class EventEmitter {
constructor() {
this._listeners = /* @__PURE__ */ new Set();
this.event = (listener, disposables) => {
this._listeners.add(listener);
let disposed = false;
const self = this;
const result = {
dispose() {
if (!disposed) {
disposed = true;
self._listeners.delete(listener);
}
}
};
if (disposables)
disposables.push(result);
return result;
};
}
fire(event) {
const dispatch = !this._deliveryQueue;
if (!this._deliveryQueue)
this._deliveryQueue = [];
for (const listener of this._listeners)
this._deliveryQueue.push({ listener, event });
if (!dispatch)
return;
for (let index = 0; index < this._deliveryQueue.length; index++) {
const { listener, event: event2 } = this._deliveryQueue[index];
listener.call(null, event2);
}
this._deliveryQueue = void 0;
}
dispose() {
this._listeners.clear();
if (this._deliveryQueue)
this._deliveryQueue = [];
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Disposable,
EventEmitter
});

View file

@ -0,0 +1,30 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var folders_exports = {};
__export(folders_exports, {
artifactsFolderName: () => artifactsFolderName
});
module.exports = __toCommonJS(folders_exports);
function artifactsFolderName(workerIndex) {
return `.playwright-artifacts-${workerIndex}`;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
artifactsFolderName
});

View file

@ -0,0 +1,69 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var stringInternPool_exports = {};
__export(stringInternPool_exports, {
JsonStringInternalizer: () => JsonStringInternalizer,
StringInternPool: () => StringInternPool
});
module.exports = __toCommonJS(stringInternPool_exports);
class StringInternPool {
constructor() {
this._stringCache = /* @__PURE__ */ new Map();
}
internString(s) {
let result = this._stringCache.get(s);
if (!result) {
this._stringCache.set(s, s);
result = s;
}
return result;
}
}
class JsonStringInternalizer {
constructor(pool) {
this._pool = pool;
}
traverse(value) {
if (typeof value !== "object")
return;
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if (typeof value[i] === "string")
value[i] = this.intern(value[i]);
else
this.traverse(value[i]);
}
} else {
for (const name in value) {
if (typeof value[name] === "string")
value[name] = this.intern(value[name]);
else
this.traverse(value[name]);
}
}
}
intern(value) {
return this._pool.internString(value);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
JsonStringInternalizer,
StringInternPool
});

View file

@ -0,0 +1,521 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var teleReceiver_exports = {};
__export(teleReceiver_exports, {
TeleReporterReceiver: () => TeleReporterReceiver,
TeleSuite: () => TeleSuite,
TeleTestCase: () => TeleTestCase,
TeleTestResult: () => TeleTestResult,
baseFullConfig: () => baseFullConfig,
computeTestCaseOutcome: () => computeTestCaseOutcome,
parseRegexPatterns: () => parseRegexPatterns,
serializeRegexPatterns: () => serializeRegexPatterns
});
module.exports = __toCommonJS(teleReceiver_exports);
class TeleReporterReceiver {
constructor(reporter, options = {}) {
this.isListing = false;
this._tests = /* @__PURE__ */ new Map();
this._rootSuite = new TeleSuite("", "root");
this._options = options;
this._reporter = reporter;
}
reset() {
this._rootSuite._entries = [];
this._tests.clear();
}
dispatch(message) {
const { method, params } = message;
if (method === "onConfigure") {
this._onConfigure(params.config);
return;
}
if (method === "onProject") {
this._onProject(params.project);
return;
}
if (method === "onBegin") {
this._onBegin();
return;
}
if (method === "onTestBegin") {
this._onTestBegin(params.testId, params.result);
return;
}
if (method === "onTestPaused") {
this._onTestPaused(params.testId, params.resultId, params.errors);
return;
}
if (method === "onTestEnd") {
this._onTestEnd(params.test, params.result);
return;
}
if (method === "onStepBegin") {
this._onStepBegin(params.testId, params.resultId, params.step);
return;
}
if (method === "onAttach") {
this._onAttach(params.testId, params.resultId, params.attachments);
return;
}
if (method === "onStepEnd") {
this._onStepEnd(params.testId, params.resultId, params.step);
return;
}
if (method === "onError") {
this._onError(params.error);
return;
}
if (method === "onStdIO") {
this._onStdIO(params.type, params.testId, params.resultId, params.data, params.isBase64);
return;
}
if (method === "onEnd")
return this._onEnd(params.result);
if (method === "onExit")
return this._onExit();
}
_onConfigure(config) {
this._rootDir = config.rootDir;
this._config = this._parseConfig(config);
this._reporter.onConfigure?.(this._config);
}
_onProject(project) {
let projectSuite = this._options.mergeProjects ? this._rootSuite.suites.find((suite) => suite.project().name === project.name) : void 0;
if (!projectSuite) {
projectSuite = new TeleSuite(project.name, "project");
this._rootSuite._addSuite(projectSuite);
}
projectSuite._project = this._parseProject(project);
for (const suite of project.suites)
this._mergeSuiteInto(suite, projectSuite);
}
_onBegin() {
this._reporter.onBegin?.(this._rootSuite);
}
_onTestBegin(testId, payload) {
const test = this._tests.get(testId);
if (this._options.clearPreviousResultsWhenTestBegins)
test.results = [];
const testResult = test._createTestResult(payload.id);
testResult.retry = payload.retry;
testResult.workerIndex = payload.workerIndex;
testResult.parallelIndex = payload.parallelIndex;
testResult.setStartTimeNumber(payload.startTime);
this._reporter.onTestBegin?.(test, testResult);
}
_onTestPaused(testId, resultId, errors) {
const test = this._tests.get(testId);
const result = test.results.find((r) => r._id === resultId);
result.errors.push(...errors);
result.error = result.errors[0];
void this._reporter.onTestPaused?.(test, result);
}
_onTestEnd(testEndPayload, payload) {
const test = this._tests.get(testEndPayload.testId);
test.timeout = testEndPayload.timeout;
test.expectedStatus = testEndPayload.expectedStatus;
const result = test.results.find((r) => r._id === payload.id);
result.duration = payload.duration;
result.status = payload.status;
result.errors.push(...payload.errors ?? []);
result.error = result.errors[0];
if (!!payload.attachments)
result.attachments = this._parseAttachments(payload.attachments);
if (payload.annotations) {
this._absoluteAnnotationLocationsInplace(payload.annotations);
result.annotations = payload.annotations;
test.annotations = payload.annotations;
}
this._reporter.onTestEnd?.(test, result);
result._stepMap = /* @__PURE__ */ new Map();
}
_onStepBegin(testId, resultId, payload) {
const test = this._tests.get(testId);
const result = test.results.find((r) => r._id === resultId);
const parentStep = payload.parentStepId ? result._stepMap.get(payload.parentStepId) : void 0;
const location = this._absoluteLocation(payload.location);
const step = new TeleTestStep(payload, parentStep, location, result);
if (parentStep)
parentStep.steps.push(step);
else
result.steps.push(step);
result._stepMap.set(payload.id, step);
this._reporter.onStepBegin?.(test, result, step);
}
_onStepEnd(testId, resultId, payload) {
const test = this._tests.get(testId);
const result = test.results.find((r) => r._id === resultId);
const step = result._stepMap.get(payload.id);
step._endPayload = payload;
step.duration = payload.duration;
step.error = payload.error;
this._reporter.onStepEnd?.(test, result, step);
}
_onAttach(testId, resultId, attachments) {
const test = this._tests.get(testId);
const result = test.results.find((r) => r._id === resultId);
result.attachments.push(...attachments.map((a) => ({
name: a.name,
contentType: a.contentType,
path: a.path,
body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, "base64") : void 0
})));
}
_onError(error) {
this._reporter.onError?.(error);
}
_onStdIO(type, testId, resultId, data, isBase64) {
const chunk = isBase64 ? globalThis.Buffer ? Buffer.from(data, "base64") : atob(data) : data;
const test = testId ? this._tests.get(testId) : void 0;
const result = test && resultId ? test.results.find((r) => r._id === resultId) : void 0;
if (type === "stdout") {
result?.stdout.push(chunk);
this._reporter.onStdOut?.(chunk, test, result);
} else {
result?.stderr.push(chunk);
this._reporter.onStdErr?.(chunk, test, result);
}
}
async _onEnd(result) {
await this._reporter.onEnd?.({
status: result.status,
startTime: new Date(result.startTime),
duration: result.duration
});
}
_onExit() {
return this._reporter.onExit?.();
}
_parseConfig(config) {
const result = { ...baseFullConfig, ...config };
if (this._options.configOverrides) {
result.configFile = this._options.configOverrides.configFile;
result.reportSlowTests = this._options.configOverrides.reportSlowTests;
result.quiet = this._options.configOverrides.quiet;
result.reporter = [...this._options.configOverrides.reporter];
}
return result;
}
_parseProject(project) {
return {
metadata: project.metadata,
name: project.name,
outputDir: this._absolutePath(project.outputDir),
repeatEach: project.repeatEach,
retries: project.retries,
testDir: this._absolutePath(project.testDir),
testIgnore: parseRegexPatterns(project.testIgnore),
testMatch: parseRegexPatterns(project.testMatch),
timeout: project.timeout,
grep: parseRegexPatterns(project.grep),
grepInvert: parseRegexPatterns(project.grepInvert),
dependencies: project.dependencies,
teardown: project.teardown,
snapshotDir: this._absolutePath(project.snapshotDir),
use: project.use
};
}
_parseAttachments(attachments) {
return attachments.map((a) => {
return {
...a,
body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, "base64") : void 0
};
});
}
_mergeSuiteInto(jsonSuite, parent) {
let targetSuite = parent.suites.find((s) => s.title === jsonSuite.title);
if (!targetSuite) {
targetSuite = new TeleSuite(jsonSuite.title, parent.type === "project" ? "file" : "describe");
parent._addSuite(targetSuite);
}
targetSuite.location = this._absoluteLocation(jsonSuite.location);
jsonSuite.entries.forEach((e) => {
if ("testId" in e)
this._mergeTestInto(e, targetSuite);
else
this._mergeSuiteInto(e, targetSuite);
});
}
_mergeTestInto(jsonTest, parent) {
let targetTest = this._options.mergeTestCases ? parent.tests.find((s) => s.title === jsonTest.title && s.repeatEachIndex === jsonTest.repeatEachIndex) : void 0;
if (!targetTest) {
targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location), jsonTest.repeatEachIndex);
parent._addTest(targetTest);
this._tests.set(targetTest.id, targetTest);
}
this._updateTest(jsonTest, targetTest);
}
_updateTest(payload, test) {
test.id = payload.testId;
test.location = this._absoluteLocation(payload.location);
test.retries = payload.retries;
test.tags = payload.tags ?? [];
test.annotations = payload.annotations ?? [];
this._absoluteAnnotationLocationsInplace(test.annotations);
return test;
}
_absoluteAnnotationLocationsInplace(annotations) {
for (const annotation of annotations) {
if (annotation.location)
annotation.location = this._absoluteLocation(annotation.location);
}
}
_absoluteLocation(location) {
if (!location)
return location;
return {
...location,
file: this._absolutePath(location.file)
};
}
_absolutePath(relativePath) {
if (relativePath === void 0)
return;
return this._options.resolvePath ? this._options.resolvePath(this._rootDir, relativePath) : this._rootDir + "/" + relativePath;
}
}
class TeleSuite {
constructor(title, type) {
this._entries = [];
this._requireFile = "";
this._parallelMode = "none";
this.title = title;
this._type = type;
}
get type() {
return this._type;
}
get suites() {
return this._entries.filter((e) => e.type !== "test");
}
get tests() {
return this._entries.filter((e) => e.type === "test");
}
entries() {
return this._entries;
}
allTests() {
const result = [];
const visit = (suite) => {
for (const entry of suite.entries()) {
if (entry.type === "test")
result.push(entry);
else
visit(entry);
}
};
visit(this);
return result;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
if (this.title || this._type !== "describe")
titlePath.push(this.title);
return titlePath;
}
project() {
return this._project ?? this.parent?.project();
}
_addTest(test) {
test.parent = this;
this._entries.push(test);
}
_addSuite(suite) {
suite.parent = this;
this._entries.push(suite);
}
}
class TeleTestCase {
constructor(id, title, location, repeatEachIndex) {
this.fn = () => {
};
this.results = [];
this.type = "test";
this.expectedStatus = "passed";
this.timeout = 0;
this.annotations = [];
this.retries = 0;
this.tags = [];
this.repeatEachIndex = 0;
this.id = id;
this.title = title;
this.location = location;
this.repeatEachIndex = repeatEachIndex;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
titlePath.push(this.title);
return titlePath;
}
outcome() {
return computeTestCaseOutcome(this);
}
ok() {
const status = this.outcome();
return status === "expected" || status === "flaky" || status === "skipped";
}
_createTestResult(id) {
const result = new TeleTestResult(this.results.length, id);
this.results.push(result);
return result;
}
}
class TeleTestStep {
constructor(payload, parentStep, location, result) {
this.duration = -1;
this.steps = [];
this._startTime = 0;
this.title = payload.title;
this.category = payload.category;
this.location = location;
this.parent = parentStep;
this._startTime = payload.startTime;
this._result = result;
}
titlePath() {
const parentPath = this.parent?.titlePath() || [];
return [...parentPath, this.title];
}
get startTime() {
return new Date(this._startTime);
}
set startTime(value) {
this._startTime = +value;
}
get attachments() {
return this._endPayload?.attachments?.map((index) => this._result.attachments[index]) ?? [];
}
get annotations() {
return this._endPayload?.annotations ?? [];
}
}
class TeleTestResult {
constructor(retry, id) {
this.parallelIndex = -1;
this.workerIndex = -1;
this.duration = -1;
this.stdout = [];
this.stderr = [];
this.attachments = [];
this.annotations = [];
this.status = "skipped";
this.steps = [];
this.errors = [];
this._stepMap = /* @__PURE__ */ new Map();
this._startTime = 0;
this.retry = retry;
this._id = id;
}
setStartTimeNumber(startTime) {
this._startTime = startTime;
}
get startTime() {
return new Date(this._startTime);
}
set startTime(value) {
this._startTime = +value;
}
}
const baseFullConfig = {
forbidOnly: false,
fullyParallel: false,
globalSetup: null,
globalTeardown: null,
globalTimeout: 0,
grep: /.*/,
grepInvert: null,
maxFailures: 0,
metadata: {},
preserveOutput: "always",
projects: [],
reporter: [[process.env.CI ? "dot" : "list"]],
reportSlowTests: {
max: 5,
threshold: 3e5
/* 5 minutes */
},
configFile: "",
rootDir: "",
quiet: false,
shard: null,
tags: [],
updateSnapshots: "missing",
updateSourceMethod: "patch",
// @ts-expect-error runAgents is hidden
runAgents: "none",
version: "",
workers: 0,
webServer: null
};
function serializeRegexPatterns(patterns) {
if (!Array.isArray(patterns))
patterns = [patterns];
return patterns.map((s) => {
if (typeof s === "string")
return { s };
return { r: { source: s.source, flags: s.flags } };
});
}
function parseRegexPatterns(patterns) {
return patterns.map((p) => {
if (p.s !== void 0)
return p.s;
return new RegExp(p.r.source, p.r.flags);
});
}
function computeTestCaseOutcome(test) {
let skipped = 0;
let didNotRun = 0;
let expected = 0;
let interrupted = 0;
let unexpected = 0;
for (const result of test.results) {
if (result.status === "interrupted") {
++interrupted;
} else if (result.status === "skipped" && test.expectedStatus === "skipped") {
++skipped;
} else if (result.status === "skipped") {
++didNotRun;
} else if (result.status === test.expectedStatus) {
++expected;
} else {
++unexpected;
}
}
if (expected === 0 && unexpected === 0)
return "skipped";
if (unexpected === 0)
return "expected";
if (expected === 0 && skipped === 0)
return "unexpected";
return "flaky";
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TeleReporterReceiver,
TeleSuite,
TeleTestCase,
TeleTestResult,
baseFullConfig,
computeTestCaseOutcome,
parseRegexPatterns,
serializeRegexPatterns
});

View file

@ -0,0 +1,157 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var teleSuiteUpdater_exports = {};
__export(teleSuiteUpdater_exports, {
TeleSuiteUpdater: () => TeleSuiteUpdater
});
module.exports = __toCommonJS(teleSuiteUpdater_exports);
var import_teleReceiver = require("./teleReceiver");
var import_testTree = require("./testTree");
class TeleSuiteUpdater {
constructor(options) {
this.loadErrors = [];
this.progress = {
total: 0,
passed: 0,
failed: 0,
skipped: 0
};
this._lastRunTestCount = 0;
this._receiver = new import_teleReceiver.TeleReporterReceiver(this._createReporter(), {
mergeProjects: true,
mergeTestCases: true,
resolvePath: createPathResolve(options.pathSeparator),
clearPreviousResultsWhenTestBegins: true
});
this._options = options;
}
_createReporter() {
return {
version: () => "v2",
onConfigure: (config) => {
this.config = config;
this._lastRunReceiver = new import_teleReceiver.TeleReporterReceiver({
version: () => "v2",
onBegin: (suite) => {
this._lastRunTestCount = suite.allTests().length;
this._lastRunReceiver = void 0;
}
}, {
mergeProjects: true,
mergeTestCases: false,
resolvePath: createPathResolve(this._options.pathSeparator)
});
void this._lastRunReceiver.dispatch({ method: "onConfigure", params: { config } });
},
onBegin: (suite) => {
if (!this.rootSuite)
this.rootSuite = suite;
if (this._testResultsSnapshot) {
for (const test of this.rootSuite.allTests())
test.results = this._testResultsSnapshot?.get(test.id) || test.results;
this._testResultsSnapshot = void 0;
}
this.progress.total = this._lastRunTestCount;
this.progress.passed = 0;
this.progress.failed = 0;
this.progress.skipped = 0;
this._options.onUpdate(true);
},
onEnd: () => {
this._options.onUpdate(true);
},
onTestBegin: (test, testResult) => {
testResult[import_testTree.statusEx] = "running";
this._options.onUpdate();
},
onTestEnd: (test, testResult) => {
if (test.outcome() === "skipped")
++this.progress.skipped;
else if (test.outcome() === "unexpected")
++this.progress.failed;
else
++this.progress.passed;
testResult[import_testTree.statusEx] = testResult.status;
this._options.onUpdate();
},
onError: (error) => this._handleOnError(error),
printsToStdio: () => false
};
}
processGlobalReport(report) {
const receiver = new import_teleReceiver.TeleReporterReceiver({
version: () => "v2",
onConfigure: (c) => {
this.config = c;
},
onError: (error) => this._handleOnError(error)
});
for (const message of report)
void receiver.dispatch(message);
}
processListReport(report) {
const tests = this.rootSuite?.allTests() || [];
this._testResultsSnapshot = new Map(tests.map((test) => [test.id, test.results]));
this._receiver.reset();
for (const message of report)
void this._receiver.dispatch(message);
}
processTestReportEvent(message) {
this._lastRunReceiver?.dispatch(message)?.catch(() => {
});
this._receiver.dispatch(message)?.catch(() => {
});
}
_handleOnError(error) {
this.loadErrors.push(error);
this._options.onError?.(error);
this._options.onUpdate();
}
asModel() {
return {
rootSuite: this.rootSuite || new import_teleReceiver.TeleSuite("", "root"),
config: this.config,
loadErrors: this.loadErrors,
progress: this.progress
};
}
}
function createPathResolve(pathSeparator) {
return (rootDir, relativePath) => {
const segments = [];
for (const segment of [...rootDir.split(pathSeparator), ...relativePath.split(pathSeparator)]) {
const isAfterDrive = pathSeparator === "\\" && segments.length === 1 && segments[0].endsWith(":");
const isFirst = !segments.length;
if (!segment && !isFirst && !isAfterDrive)
continue;
if (segment === ".")
continue;
if (segment === "..") {
segments.pop();
continue;
}
segments.push(segment);
}
return segments.join(pathSeparator);
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TeleSuiteUpdater
});

View file

@ -0,0 +1,225 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var testServerConnection_exports = {};
__export(testServerConnection_exports, {
TestServerConnection: () => TestServerConnection,
TestServerConnectionClosedError: () => TestServerConnectionClosedError,
WebSocketTestServerTransport: () => WebSocketTestServerTransport
});
module.exports = __toCommonJS(testServerConnection_exports);
var events = __toESM(require("./events"));
class TestServerConnectionClosedError extends Error {
constructor() {
super("Test server connection closed");
}
}
class WebSocketTestServerTransport {
constructor(url) {
this._ws = new WebSocket(url);
}
onmessage(listener) {
this._ws.addEventListener("message", (event) => listener(event.data.toString()));
}
onopen(listener) {
this._ws.addEventListener("open", listener);
}
onerror(listener) {
this._ws.addEventListener("error", listener);
}
onclose(listener) {
this._ws.addEventListener("close", listener);
}
send(data) {
this._ws.send(data);
}
close() {
this._ws.close();
}
}
class TestServerConnection {
constructor(transport) {
this._onCloseEmitter = new events.EventEmitter();
this._onReportEmitter = new events.EventEmitter();
this._onStdioEmitter = new events.EventEmitter();
this._onTestFilesChangedEmitter = new events.EventEmitter();
this._onLoadTraceRequestedEmitter = new events.EventEmitter();
this._onTestPausedEmitter = new events.EventEmitter();
this._lastId = 0;
this._callbacks = /* @__PURE__ */ new Map();
this._isClosed = false;
this.onClose = this._onCloseEmitter.event;
this.onReport = this._onReportEmitter.event;
this.onStdio = this._onStdioEmitter.event;
this.onTestFilesChanged = this._onTestFilesChangedEmitter.event;
this.onLoadTraceRequested = this._onLoadTraceRequestedEmitter.event;
this.onTestPaused = this._onTestPausedEmitter.event;
this._transport = transport;
this._transport.onmessage((data) => {
const message = JSON.parse(data);
const { id, result, error, method, params } = message;
if (id) {
const callback = this._callbacks.get(id);
if (!callback)
return;
this._callbacks.delete(id);
if (error)
callback.reject(new Error(error));
else
callback.resolve(result);
} else {
this._dispatchEvent(method, params);
}
});
const pingInterval = setInterval(() => this._sendMessage("ping").catch(() => {
}), 3e4);
this._connectedPromise = new Promise((f, r) => {
this._transport.onopen(f);
this._transport.onerror(r);
});
this._transport.onclose(() => {
this._isClosed = true;
this._onCloseEmitter.fire();
clearInterval(pingInterval);
for (const callback of this._callbacks.values())
callback.reject(new TestServerConnectionClosedError());
this._callbacks.clear();
});
}
isClosed() {
return this._isClosed;
}
async _sendMessage(method, params) {
const logForTest = globalThis.__logForTest;
logForTest?.({ method, params });
await this._connectedPromise;
const id = ++this._lastId;
const message = { id, method, params };
this._transport.send(JSON.stringify(message));
return new Promise((resolve, reject) => {
this._callbacks.set(id, { resolve, reject });
});
}
_sendMessageNoReply(method, params) {
this._sendMessage(method, params).catch(() => {
});
}
_dispatchEvent(method, params) {
if (method === "report")
this._onReportEmitter.fire(params);
else if (method === "stdio")
this._onStdioEmitter.fire(params);
else if (method === "testFilesChanged")
this._onTestFilesChangedEmitter.fire(params);
else if (method === "loadTraceRequested")
this._onLoadTraceRequestedEmitter.fire(params);
else if (method === "testPaused")
this._onTestPausedEmitter.fire(params);
}
async initialize(params) {
await this._sendMessage("initialize", params);
}
async ping(params) {
await this._sendMessage("ping", params);
}
async pingNoReply(params) {
this._sendMessageNoReply("ping", params);
}
async watch(params) {
await this._sendMessage("watch", params);
}
watchNoReply(params) {
this._sendMessageNoReply("watch", params);
}
async open(params) {
await this._sendMessage("open", params);
}
openNoReply(params) {
this._sendMessageNoReply("open", params);
}
async resizeTerminal(params) {
await this._sendMessage("resizeTerminal", params);
}
resizeTerminalNoReply(params) {
this._sendMessageNoReply("resizeTerminal", params);
}
async checkBrowsers(params) {
return await this._sendMessage("checkBrowsers", params);
}
async installBrowsers(params) {
await this._sendMessage("installBrowsers", params);
}
async runGlobalSetup(params) {
return await this._sendMessage("runGlobalSetup", params);
}
async runGlobalTeardown(params) {
return await this._sendMessage("runGlobalTeardown", params);
}
async startDevServer(params) {
return await this._sendMessage("startDevServer", params);
}
async stopDevServer(params) {
return await this._sendMessage("stopDevServer", params);
}
async clearCache(params) {
return await this._sendMessage("clearCache", params);
}
async listFiles(params) {
return await this._sendMessage("listFiles", params);
}
async listTests(params) {
return await this._sendMessage("listTests", params);
}
async runTests(params) {
return await this._sendMessage("runTests", params);
}
async findRelatedTestFiles(params) {
return await this._sendMessage("findRelatedTestFiles", params);
}
async stopTests(params) {
await this._sendMessage("stopTests", params);
}
stopTestsNoReply(params) {
this._sendMessageNoReply("stopTests", params);
}
async closeGracefully(params) {
await this._sendMessage("closeGracefully", params);
}
close() {
try {
this._transport.close();
} catch {
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TestServerConnection,
TestServerConnectionClosedError,
WebSocketTestServerTransport
});

View file

@ -0,0 +1,16 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var testServerInterface_exports = {};
module.exports = __toCommonJS(testServerInterface_exports);

View file

@ -0,0 +1,329 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var testTree_exports = {};
__export(testTree_exports, {
TestTree: () => TestTree,
sortAndPropagateStatus: () => sortAndPropagateStatus,
statusEx: () => statusEx
});
module.exports = __toCommonJS(testTree_exports);
class TestTree {
constructor(rootFolder, rootSuite, loadErrors, projectFilters, pathSeparator, hideFiles) {
this._treeItemById = /* @__PURE__ */ new Map();
this._treeItemByTestId = /* @__PURE__ */ new Map();
const filterProjects = projectFilters && [...projectFilters.values()].some(Boolean);
this.pathSeparator = pathSeparator;
this.rootItem = {
kind: "group",
subKind: "folder",
id: rootFolder,
title: "",
location: { file: "", line: 0, column: 0 },
duration: 0,
parent: void 0,
children: [],
status: "none",
hasLoadErrors: false
};
this._treeItemById.set(rootFolder, this.rootItem);
const visitSuite = (project, parentSuite, parentGroup, mode) => {
for (const suite of mode === "tests" ? [] : parentSuite.suites) {
if (!suite.title) {
visitSuite(project, suite, parentGroup, "all");
continue;
}
let group = parentGroup.children.find((item) => item.kind === "group" && item.title === suite.title);
if (!group) {
group = {
kind: "group",
subKind: "describe",
id: "suite:" + parentSuite.titlePath().join("") + "" + suite.title,
// account for anonymous suites
title: suite.title,
location: suite.location,
duration: 0,
parent: parentGroup,
children: [],
status: "none",
hasLoadErrors: false
};
this._addChild(parentGroup, group);
}
visitSuite(project, suite, group, "all");
}
for (const test of mode === "suites" ? [] : parentSuite.tests) {
const title = test.title;
let testCaseItem = parentGroup.children.find((t) => t.kind !== "group" && t.title === title);
if (!testCaseItem) {
testCaseItem = {
kind: "case",
id: "test:" + test.titlePath().join(""),
title,
parent: parentGroup,
children: [],
tests: [],
location: test.location,
duration: 0,
status: "none",
project: void 0,
test: void 0,
tags: test.tags
};
this._addChild(parentGroup, testCaseItem);
}
const result = test.results[0];
let status = "none";
if (result?.[statusEx] === "scheduled")
status = "scheduled";
else if (result?.[statusEx] === "running")
status = "running";
else if (result?.status === "skipped")
status = "skipped";
else if (result?.status === "interrupted")
status = "none";
else if (result && test.outcome() !== "expected")
status = "failed";
else if (result && test.outcome() === "expected")
status = "passed";
testCaseItem.tests.push(test);
const testItem = {
kind: "test",
id: test.id,
title: project.name,
location: test.location,
test,
parent: testCaseItem,
children: [],
status,
duration: test.results.length ? Math.max(0, test.results[0].duration) : 0,
project
};
this._addChild(testCaseItem, testItem);
this._treeItemByTestId.set(test.id, testItem);
testCaseItem.duration = testCaseItem.children.reduce((a, b) => a + b.duration, 0);
}
};
for (const projectSuite of rootSuite?.suites || []) {
if (filterProjects && !projectFilters.get(projectSuite.title))
continue;
for (const fileSuite of projectSuite.suites) {
if (hideFiles) {
visitSuite(projectSuite.project(), fileSuite, this.rootItem, "suites");
if (fileSuite.tests.length) {
const defaultDescribeItem = this._defaultDescribeItem();
visitSuite(projectSuite.project(), fileSuite, defaultDescribeItem, "tests");
}
} else {
const fileItem = this._fileItem(fileSuite.location.file.split(pathSeparator), true);
visitSuite(projectSuite.project(), fileSuite, fileItem, "all");
}
}
}
for (const loadError of loadErrors) {
if (!loadError.location)
continue;
const fileItem = this._fileItem(loadError.location.file.split(pathSeparator), true);
fileItem.hasLoadErrors = true;
}
}
_addChild(parent, child) {
parent.children.push(child);
child.parent = parent;
this._treeItemById.set(child.id, child);
}
filterTree(filterText, statusFilters, runningTestIds) {
const tokens = filterText.trim().toLowerCase().split(" ");
const filtersStatuses = [...statusFilters.values()].some(Boolean);
const filter = (testCase) => {
const titleWithTags = [...testCase.tests[0].titlePath(), ...testCase.tests[0].tags].join(" ").toLowerCase();
if (!tokens.every((token) => titleWithTags.includes(token)) && !testCase.tests.some((t) => runningTestIds?.has(t.id)))
return false;
testCase.children = testCase.children.filter((test) => {
return !filtersStatuses || runningTestIds?.has(test.test.id) || statusFilters.get(test.status);
});
testCase.tests = testCase.children.map((c) => c.test);
return !!testCase.children.length;
};
const visit = (treeItem) => {
const newChildren = [];
for (const child of treeItem.children) {
if (child.kind === "case") {
if (filter(child))
newChildren.push(child);
} else {
visit(child);
if (child.children.length || child.hasLoadErrors)
newChildren.push(child);
}
}
treeItem.children = newChildren;
};
visit(this.rootItem);
}
_fileItem(filePath, isFile) {
if (filePath.length === 0)
return this.rootItem;
const fileName = filePath.join(this.pathSeparator);
const existingFileItem = this._treeItemById.get(fileName);
if (existingFileItem)
return existingFileItem;
const parentFileItem = this._fileItem(filePath.slice(0, filePath.length - 1), false);
const fileItem = {
kind: "group",
subKind: isFile ? "file" : "folder",
id: fileName,
title: filePath[filePath.length - 1],
location: { file: fileName, line: 0, column: 0 },
duration: 0,
parent: parentFileItem,
children: [],
status: "none",
hasLoadErrors: false
};
this._addChild(parentFileItem, fileItem);
return fileItem;
}
_defaultDescribeItem() {
let defaultDescribeItem = this._treeItemById.get("<anonymous>");
if (!defaultDescribeItem) {
defaultDescribeItem = {
kind: "group",
subKind: "describe",
id: "<anonymous>",
title: "<anonymous>",
location: { file: "", line: 0, column: 0 },
duration: 0,
parent: this.rootItem,
children: [],
status: "none",
hasLoadErrors: false
};
this._addChild(this.rootItem, defaultDescribeItem);
}
return defaultDescribeItem;
}
sortAndPropagateStatus() {
sortAndPropagateStatus(this.rootItem);
}
flattenForSingleProject() {
const visit = (treeItem) => {
if (treeItem.kind === "case" && treeItem.children.length === 1) {
treeItem.project = treeItem.children[0].project;
treeItem.test = treeItem.children[0].test;
treeItem.children = [];
this._treeItemByTestId.set(treeItem.test.id, treeItem);
} else {
treeItem.children.forEach(visit);
}
};
visit(this.rootItem);
}
shortenRoot() {
let shortRoot = this.rootItem;
while (shortRoot.children.length === 1 && shortRoot.children[0].kind === "group" && shortRoot.children[0].subKind === "folder")
shortRoot = shortRoot.children[0];
shortRoot.location = this.rootItem.location;
this.rootItem = shortRoot;
}
fileNames() {
const result = /* @__PURE__ */ new Set();
const visit = (treeItem) => {
if (treeItem.kind === "group" && treeItem.subKind === "file")
result.add(treeItem.id);
else
treeItem.children.forEach(visit);
};
visit(this.rootItem);
return [...result];
}
flatTreeItems() {
const result = [];
const visit = (treeItem) => {
result.push(treeItem);
treeItem.children.forEach(visit);
};
visit(this.rootItem);
return result;
}
treeItemById(id) {
return this._treeItemById.get(id);
}
collectTestIds(treeItem) {
return collectTestIds(treeItem);
}
}
function sortAndPropagateStatus(treeItem) {
for (const child of treeItem.children)
sortAndPropagateStatus(child);
if (treeItem.kind === "group") {
treeItem.children.sort((a, b) => {
const fc = a.location.file.localeCompare(b.location.file);
return fc || a.location.line - b.location.line;
});
}
let allPassed = treeItem.children.length > 0;
let allSkipped = treeItem.children.length > 0;
let hasFailed = false;
let hasRunning = false;
let hasScheduled = false;
for (const child of treeItem.children) {
allSkipped = allSkipped && child.status === "skipped";
allPassed = allPassed && (child.status === "passed" || child.status === "skipped");
hasFailed = hasFailed || child.status === "failed";
hasRunning = hasRunning || child.status === "running";
hasScheduled = hasScheduled || child.status === "scheduled";
}
if (hasRunning)
treeItem.status = "running";
else if (hasScheduled)
treeItem.status = "scheduled";
else if (hasFailed)
treeItem.status = "failed";
else if (allSkipped)
treeItem.status = "skipped";
else if (allPassed)
treeItem.status = "passed";
}
function collectTestIds(treeItem) {
const testIds = /* @__PURE__ */ new Set();
const locations = /* @__PURE__ */ new Set();
const visit = (treeItem2) => {
if (treeItem2.kind !== "test" && treeItem2.kind !== "case") {
treeItem2.children.forEach(visit);
return;
}
let fileItem = treeItem2;
while (fileItem && fileItem.parent && !(fileItem.kind === "group" && fileItem.subKind === "file"))
fileItem = fileItem.parent;
locations.add(fileItem.location.file);
if (treeItem2.kind === "case")
treeItem2.tests.forEach((test) => testIds.add(test.id));
else
testIds.add(treeItem2.id);
};
visit(treeItem);
return { testIds, locations };
}
const statusEx = Symbol("statusEx");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
TestTree,
sortAndPropagateStatus,
statusEx
});

View file

@ -0,0 +1,16 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var types_d_exports = {};
module.exports = __toCommonJS(types_d_exports);

View file

@ -0,0 +1,59 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var loaderMain_exports = {};
__export(loaderMain_exports, {
LoaderMain: () => LoaderMain,
create: () => create
});
module.exports = __toCommonJS(loaderMain_exports);
var import_configLoader = require("../common/configLoader");
var import_esmLoaderHost = require("../common/esmLoaderHost");
var import_poolBuilder = require("../common/poolBuilder");
var import_process = require("../common/process");
var import_testLoader = require("../common/testLoader");
var import_compilationCache = require("../transform/compilationCache");
class LoaderMain extends import_process.ProcessRunner {
constructor(serializedConfig) {
super();
this._poolBuilder = import_poolBuilder.PoolBuilder.createForLoader();
this._serializedConfig = serializedConfig;
}
_config() {
if (!this._configPromise)
this._configPromise = (0, import_configLoader.deserializeConfig)(this._serializedConfig);
return this._configPromise;
}
async loadTestFile(params) {
const testErrors = [];
const config = await this._config();
const fileSuite = await (0, import_testLoader.loadTestFile)(params.file, config, testErrors);
this._poolBuilder.buildPools(fileSuite);
return { fileSuite: fileSuite._deepSerialize(), testErrors };
}
async getCompilationCacheFromLoader() {
await (0, import_esmLoaderHost.incorporateCompilationCache)();
return (0, import_compilationCache.serializeCompilationCache)();
}
}
const create = (config) => new LoaderMain(config);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
LoaderMain,
create
});

311
backend/node_modules/playwright/lib/matchers/expect.js generated vendored Normal file
View file

@ -0,0 +1,311 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var expect_exports = {};
__export(expect_exports, {
expect: () => expect,
mergeExpects: () => mergeExpects
});
module.exports = __toCommonJS(expect_exports);
var import_utils = require("playwright-core/lib/utils");
var import_matcherHint = require("./matcherHint");
var import_matchers = require("./matchers");
var import_toMatchAriaSnapshot = require("./toMatchAriaSnapshot");
var import_toMatchSnapshot = require("./toMatchSnapshot");
var import_expectBundle = require("../common/expectBundle");
var import_globals = require("../common/globals");
var import_util = require("../util");
var import_testInfo = require("../worker/testInfo");
function createMatchers(actual, info, prefix) {
return new Proxy((0, import_expectBundle.expect)(actual), new ExpectMetaInfoProxyHandler(actual, info, prefix));
}
const userMatchersSymbol = Symbol("userMatchers");
function qualifiedMatcherName(qualifier, matcherName) {
return qualifier.join(":") + "$" + matcherName;
}
function createExpect(info, prefix, userMatchers) {
const expectInstance = new Proxy(import_expectBundle.expect, {
apply: function(target, thisArg, argumentsList) {
const [actual, messageOrOptions] = argumentsList;
const message = (0, import_utils.isString)(messageOrOptions) ? messageOrOptions : messageOrOptions?.message || info.message;
const newInfo = { ...info, message };
if (newInfo.poll) {
if (typeof actual !== "function")
throw new Error("`expect.poll()` accepts only function as a first argument");
newInfo.poll.generator = actual;
}
return createMatchers(actual, newInfo, prefix);
},
get: function(target, property) {
if (property === "configure")
return configure;
if (property === "extend") {
return (matchers) => {
const qualifier = [...prefix, (0, import_utils.createGuid)()];
const wrappedMatchers = {};
for (const [name, matcher] of Object.entries(matchers)) {
wrappedMatchers[name] = wrapPlaywrightMatcherToPassNiceThis(matcher);
const key = qualifiedMatcherName(qualifier, name);
wrappedMatchers[key] = wrappedMatchers[name];
Object.defineProperty(wrappedMatchers[key], "name", { value: name });
}
import_expectBundle.expect.extend(wrappedMatchers);
return createExpect(info, qualifier, { ...userMatchers, ...matchers });
};
}
if (property === "soft") {
return (actual, messageOrOptions) => {
return configure({ soft: true })(actual, messageOrOptions);
};
}
if (property === userMatchersSymbol)
return userMatchers;
if (property === "poll") {
return (actual, messageOrOptions) => {
const poll = (0, import_utils.isString)(messageOrOptions) ? {} : messageOrOptions || {};
return configure({ _poll: poll })(actual, messageOrOptions);
};
}
return import_expectBundle.expect[property];
}
});
const configure = (configuration) => {
const newInfo = { ...info };
if ("message" in configuration)
newInfo.message = configuration.message;
if ("timeout" in configuration)
newInfo.timeout = configuration.timeout;
if ("soft" in configuration)
newInfo.isSoft = configuration.soft;
if ("_poll" in configuration) {
newInfo.poll = configuration._poll ? { ...info.poll, generator: () => {
} } : void 0;
if (typeof configuration._poll === "object") {
newInfo.poll.timeout = configuration._poll.timeout ?? newInfo.poll.timeout;
newInfo.poll.intervals = configuration._poll.intervals ?? newInfo.poll.intervals;
}
}
return createExpect(newInfo, prefix, userMatchers);
};
return expectInstance;
}
let matcherCallContext;
function setMatcherCallContext(context) {
matcherCallContext = context;
}
function takeMatcherCallContext() {
try {
return matcherCallContext;
} finally {
matcherCallContext = void 0;
}
}
const defaultExpectTimeout = 5e3;
function wrapPlaywrightMatcherToPassNiceThis(matcher) {
return function(...args) {
const { isNot, promise, utils } = this;
const context = takeMatcherCallContext();
const timeout = context?.expectInfo.timeout ?? context?.testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout;
const newThis = {
isNot,
promise,
utils,
timeout,
_stepInfo: context?.step
};
newThis.equals = throwUnsupportedExpectMatcherError;
return matcher.call(newThis, ...args);
};
}
function throwUnsupportedExpectMatcherError() {
throw new Error("It looks like you are using custom expect matchers that are not compatible with Playwright. See https://aka.ms/playwright/expect-compatibility");
}
import_expectBundle.expect.setState({ expand: false });
const customAsyncMatchers = {
toBeAttached: import_matchers.toBeAttached,
toBeChecked: import_matchers.toBeChecked,
toBeDisabled: import_matchers.toBeDisabled,
toBeEditable: import_matchers.toBeEditable,
toBeEmpty: import_matchers.toBeEmpty,
toBeEnabled: import_matchers.toBeEnabled,
toBeFocused: import_matchers.toBeFocused,
toBeHidden: import_matchers.toBeHidden,
toBeInViewport: import_matchers.toBeInViewport,
toBeOK: import_matchers.toBeOK,
toBeVisible: import_matchers.toBeVisible,
toContainText: import_matchers.toContainText,
toContainClass: import_matchers.toContainClass,
toHaveAccessibleDescription: import_matchers.toHaveAccessibleDescription,
toHaveAccessibleName: import_matchers.toHaveAccessibleName,
toHaveAccessibleErrorMessage: import_matchers.toHaveAccessibleErrorMessage,
toHaveAttribute: import_matchers.toHaveAttribute,
toHaveClass: import_matchers.toHaveClass,
toHaveCount: import_matchers.toHaveCount,
toHaveCSS: import_matchers.toHaveCSS,
toHaveId: import_matchers.toHaveId,
toHaveJSProperty: import_matchers.toHaveJSProperty,
toHaveRole: import_matchers.toHaveRole,
toHaveText: import_matchers.toHaveText,
toHaveTitle: import_matchers.toHaveTitle,
toHaveURL: import_matchers.toHaveURL,
toHaveValue: import_matchers.toHaveValue,
toHaveValues: import_matchers.toHaveValues,
toHaveScreenshot: import_toMatchSnapshot.toHaveScreenshot,
toMatchAriaSnapshot: import_toMatchAriaSnapshot.toMatchAriaSnapshot,
toPass: import_matchers.toPass
};
const customMatchers = {
...customAsyncMatchers,
toMatchSnapshot: import_toMatchSnapshot.toMatchSnapshot
};
class ExpectMetaInfoProxyHandler {
constructor(actual, info, prefix) {
this._actual = actual;
this._info = { ...info };
this._prefix = prefix;
}
get(target, matcherName, receiver) {
if (matcherName === "toThrowError")
matcherName = "toThrow";
let matcher = Reflect.get(target, matcherName, receiver);
if (typeof matcherName !== "string")
return matcher;
let resolvedMatcherName = matcherName;
for (let i = this._prefix.length; i > 0; i--) {
const qualifiedName = qualifiedMatcherName(this._prefix.slice(0, i), matcherName);
if (Reflect.has(target, qualifiedName)) {
matcher = Reflect.get(target, qualifiedName, receiver);
resolvedMatcherName = qualifiedName;
break;
}
}
if (matcher === void 0)
throw new Error(`expect: Property '${matcherName}' not found.`);
if (typeof matcher !== "function") {
if (matcherName === "not")
this._info.isNot = !this._info.isNot;
return new Proxy(matcher, this);
}
if (this._info.poll) {
if (customAsyncMatchers[matcherName] || matcherName === "resolves" || matcherName === "rejects")
throw new Error(`\`expect.poll()\` does not support "${matcherName}" matcher.`);
matcher = (...args) => pollMatcher(resolvedMatcherName, this._info, this._prefix, ...args);
}
return (...args) => {
const testInfo = (0, import_globals.currentTestInfo)();
setMatcherCallContext({ expectInfo: this._info, testInfo });
if (!testInfo)
return matcher.call(target, ...args);
const customMessage = this._info.message || "";
const suffixes = (0, import_matchers.computeMatcherTitleSuffix)(matcherName, this._actual, args);
const defaultTitle = `${this._info.poll ? "poll " : ""}${this._info.isSoft ? "soft " : ""}${this._info.isNot ? "not " : ""}${matcherName}${suffixes.short || ""}`;
const shortTitle = customMessage || `Expect ${(0, import_utils.escapeWithQuotes)(defaultTitle, '"')}`;
const longTitle = shortTitle + (suffixes.long || "");
const apiName = `expect${this._info.poll ? ".poll " : ""}${this._info.isSoft ? ".soft " : ""}${this._info.isNot ? ".not" : ""}.${matcherName}${suffixes.short || ""}`;
const stackFrames = (0, import_util.filteredStackTrace)((0, import_utils.captureRawStack)());
const stepInfo = {
category: "expect",
apiName,
title: longTitle,
shortTitle,
params: args[0] ? { expected: args[0] } : void 0,
infectParentStepsWithError: this._info.isSoft
};
const step = testInfo._addStep(stepInfo);
const reportStepError = (e) => {
const jestError = (0, import_matcherHint.isJestError)(e) ? e : null;
const expectError = jestError ? new import_matcherHint.ExpectError(jestError, customMessage, stackFrames) : void 0;
if (jestError?.matcherResult.suggestedRebaseline) {
step.complete({ suggestedRebaseline: jestError?.matcherResult.suggestedRebaseline });
return;
}
const error = expectError ?? e;
step.complete({ error });
if (this._info.isSoft)
testInfo._failWithError(error);
else
throw error;
};
const finalizer = () => {
step.complete({});
};
try {
setMatcherCallContext({ expectInfo: this._info, testInfo, step: step.info });
const callback = () => matcher.call(target, ...args);
const result = (0, import_utils.currentZone)().with("stepZone", step).run(callback);
if (result instanceof Promise)
return result.then(finalizer).catch(reportStepError);
finalizer();
return result;
} catch (e) {
void reportStepError(e);
}
};
}
}
async function pollMatcher(qualifiedMatcherName2, info, prefix, ...args) {
const testInfo = (0, import_globals.currentTestInfo)();
const poll = info.poll;
const timeout = poll.timeout ?? info.timeout ?? testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout;
const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : import_testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
const result = await (0, import_utils.pollAgainstDeadline)(async () => {
if (testInfo && (0, import_globals.currentTestInfo)() !== testInfo)
return { continuePolling: false, result: void 0 };
const innerInfo = {
...info,
isSoft: false,
// soft is outside of poll, not inside
poll: void 0
};
const value = await poll.generator();
try {
let matchers = createMatchers(value, innerInfo, prefix);
if (info.isNot)
matchers = matchers.not;
matchers[qualifiedMatcherName2](...args);
return { continuePolling: false, result: void 0 };
} catch (error) {
return { continuePolling: true, result: error };
}
}, deadline, poll.intervals ?? [100, 250, 500, 1e3]);
if (result.timedOut) {
const message = result.result ? [
result.result.message,
"",
`Call Log:`,
`- ${timeoutMessage}`
].join("\n") : timeoutMessage;
throw new Error(message);
}
}
const expect = createExpect({}, [], {}).extend(customMatchers);
function mergeExpects(...expects) {
let merged = expect;
for (const e of expects) {
const internals = e[userMatchersSymbol];
if (!internals)
continue;
merged = merged.extend(internals);
}
return merged;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
expect,
mergeExpects
});

View file

@ -0,0 +1,44 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var matcherHint_exports = {};
__export(matcherHint_exports, {
ExpectError: () => ExpectError,
isJestError: () => isJestError
});
module.exports = __toCommonJS(matcherHint_exports);
var import_utils = require("playwright-core/lib/utils");
class ExpectError extends Error {
constructor(jestError, customMessage, stackFrames) {
super("");
this.name = jestError.name;
this.message = jestError.message;
this.matcherResult = jestError.matcherResult;
if (customMessage)
this.message = customMessage + "\n\n" + this.message;
this.stack = this.name + ": " + this.message + "\n" + (0, import_utils.stringifyStackFrames)(stackFrames).join("\n");
}
}
function isJestError(e) {
return e instanceof Error && "matcherResult" in e && !!e.matcherResult;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ExpectError,
isJestError
});

View file

@ -0,0 +1,383 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var matchers_exports = {};
__export(matchers_exports, {
computeMatcherTitleSuffix: () => computeMatcherTitleSuffix,
toBeAttached: () => toBeAttached,
toBeChecked: () => toBeChecked,
toBeDisabled: () => toBeDisabled,
toBeEditable: () => toBeEditable,
toBeEmpty: () => toBeEmpty,
toBeEnabled: () => toBeEnabled,
toBeFocused: () => toBeFocused,
toBeHidden: () => toBeHidden,
toBeInViewport: () => toBeInViewport,
toBeOK: () => toBeOK,
toBeVisible: () => toBeVisible,
toContainClass: () => toContainClass,
toContainText: () => toContainText,
toHaveAccessibleDescription: () => toHaveAccessibleDescription,
toHaveAccessibleErrorMessage: () => toHaveAccessibleErrorMessage,
toHaveAccessibleName: () => toHaveAccessibleName,
toHaveAttribute: () => toHaveAttribute,
toHaveCSS: () => toHaveCSS,
toHaveClass: () => toHaveClass,
toHaveCount: () => toHaveCount,
toHaveId: () => toHaveId,
toHaveJSProperty: () => toHaveJSProperty,
toHaveRole: () => toHaveRole,
toHaveText: () => toHaveText,
toHaveTitle: () => toHaveTitle,
toHaveURL: () => toHaveURL,
toHaveValue: () => toHaveValue,
toHaveValues: () => toHaveValues,
toPass: () => toPass
});
module.exports = __toCommonJS(matchers_exports);
var import_utils = require("playwright-core/lib/utils");
var import_utils2 = require("playwright-core/lib/utils");
var import_util = require("../util");
var import_toBeTruthy = require("./toBeTruthy");
var import_toEqual = require("./toEqual");
var import_toHaveURL = require("./toHaveURL");
var import_toMatchText = require("./toMatchText");
var import_toMatchSnapshot = require("./toMatchSnapshot");
var import_config = require("../common/config");
var import_globals = require("../common/globals");
var import_testInfo = require("../worker/testInfo");
function toBeAttached(locator, options) {
const attached = !options || options.attached === void 0 || options.attached;
const expected = attached ? "attached" : "detached";
const arg = attached ? "" : "{ attached: false }";
return import_toBeTruthy.toBeTruthy.call(this, "toBeAttached", locator, "Locator", expected, arg, async (isNot, timeout) => {
return await locator._expect(attached ? "to.be.attached" : "to.be.detached", { isNot, timeout });
}, options);
}
function toBeChecked(locator, options) {
const checked = options?.checked;
const indeterminate = options?.indeterminate;
const expectedValue = {
checked,
indeterminate
};
let expected;
let arg;
if (options?.indeterminate) {
expected = "indeterminate";
arg = `{ indeterminate: true }`;
} else {
expected = options?.checked === false ? "unchecked" : "checked";
arg = options?.checked === false ? `{ checked: false }` : "";
}
return import_toBeTruthy.toBeTruthy.call(this, "toBeChecked", locator, "Locator", expected, arg, async (isNot, timeout) => {
return await locator._expect("to.be.checked", { isNot, timeout, expectedValue });
}, options);
}
function toBeDisabled(locator, options) {
return import_toBeTruthy.toBeTruthy.call(this, "toBeDisabled", locator, "Locator", "disabled", "", async (isNot, timeout) => {
return await locator._expect("to.be.disabled", { isNot, timeout });
}, options);
}
function toBeEditable(locator, options) {
const editable = !options || options.editable === void 0 || options.editable;
const expected = editable ? "editable" : "readOnly";
const arg = editable ? "" : "{ editable: false }";
return import_toBeTruthy.toBeTruthy.call(this, "toBeEditable", locator, "Locator", expected, arg, async (isNot, timeout) => {
return await locator._expect(editable ? "to.be.editable" : "to.be.readonly", { isNot, timeout });
}, options);
}
function toBeEmpty(locator, options) {
return import_toBeTruthy.toBeTruthy.call(this, "toBeEmpty", locator, "Locator", "empty", "", async (isNot, timeout) => {
return await locator._expect("to.be.empty", { isNot, timeout });
}, options);
}
function toBeEnabled(locator, options) {
const enabled = !options || options.enabled === void 0 || options.enabled;
const expected = enabled ? "enabled" : "disabled";
const arg = enabled ? "" : "{ enabled: false }";
return import_toBeTruthy.toBeTruthy.call(this, "toBeEnabled", locator, "Locator", expected, arg, async (isNot, timeout) => {
return await locator._expect(enabled ? "to.be.enabled" : "to.be.disabled", { isNot, timeout });
}, options);
}
function toBeFocused(locator, options) {
return import_toBeTruthy.toBeTruthy.call(this, "toBeFocused", locator, "Locator", "focused", "", async (isNot, timeout) => {
return await locator._expect("to.be.focused", { isNot, timeout });
}, options);
}
function toBeHidden(locator, options) {
return import_toBeTruthy.toBeTruthy.call(this, "toBeHidden", locator, "Locator", "hidden", "", async (isNot, timeout) => {
return await locator._expect("to.be.hidden", { isNot, timeout });
}, options);
}
function toBeVisible(locator, options) {
const visible = !options || options.visible === void 0 || options.visible;
const expected = visible ? "visible" : "hidden";
const arg = visible ? "" : "{ visible: false }";
return import_toBeTruthy.toBeTruthy.call(this, "toBeVisible", locator, "Locator", expected, arg, async (isNot, timeout) => {
return await locator._expect(visible ? "to.be.visible" : "to.be.hidden", { isNot, timeout });
}, options);
}
function toBeInViewport(locator, options) {
return import_toBeTruthy.toBeTruthy.call(this, "toBeInViewport", locator, "Locator", "in viewport", "", async (isNot, timeout) => {
return await locator._expect("to.be.in.viewport", { isNot, expectedNumber: options?.ratio, timeout });
}, options);
}
function toContainText(locator, expected, options = {}) {
if (Array.isArray(expected)) {
return import_toEqual.toEqual.call(this, "toContainText", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)(expected, { matchSubstring: true, normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
return await locator._expect("to.contain.text.array", { expectedText, isNot, useInnerText: options.useInnerText, timeout });
}, expected, { ...options, contains: true });
} else {
return import_toMatchText.toMatchText.call(this, "toContainText", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { matchSubstring: true, normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
return await locator._expect("to.have.text", { expectedText, isNot, useInnerText: options.useInnerText, timeout });
}, expected, { ...options, matchSubstring: true });
}
}
function toHaveAccessibleDescription(locator, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveAccessibleDescription", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
return await locator._expect("to.have.accessible.description", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveAccessibleName(locator, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveAccessibleName", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
return await locator._expect("to.have.accessible.name", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveAccessibleErrorMessage(locator, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveAccessibleErrorMessage", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
return await locator._expect("to.have.accessible.error.message", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveAttribute(locator, name, expected, options) {
if (!options) {
if (typeof expected === "object" && !(0, import_utils.isRegExp)(expected)) {
options = expected;
expected = void 0;
}
}
if (expected === void 0) {
return import_toBeTruthy.toBeTruthy.call(this, "toHaveAttribute", locator, "Locator", "have attribute", "", async (isNot, timeout) => {
return await locator._expect("to.have.attribute", { expressionArg: name, isNot, timeout });
}, options);
}
return import_toMatchText.toMatchText.call(this, "toHaveAttribute", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase });
return await locator._expect("to.have.attribute.value", { expressionArg: name, expectedText, isNot, timeout });
}, expected, options);
}
function toHaveClass(locator, expected, options) {
if (Array.isArray(expected)) {
return import_toEqual.toEqual.call(this, "toHaveClass", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
return await locator._expect("to.have.class.array", { expectedText, isNot, timeout });
}, expected, options);
} else {
return import_toMatchText.toMatchText.call(this, "toHaveClass", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.have.class", { expectedText, isNot, timeout });
}, expected, options);
}
}
function toContainClass(locator, expected, options) {
if (Array.isArray(expected)) {
if (expected.some((e) => (0, import_utils.isRegExp)(e)))
throw new Error(`"expected" argument in toContainClass cannot contain RegExp values`);
return import_toEqual.toEqual.call(this, "toContainClass", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
return await locator._expect("to.contain.class.array", { expectedText, isNot, timeout });
}, expected, options);
} else {
if ((0, import_utils.isRegExp)(expected))
throw new Error(`"expected" argument in toContainClass cannot be a RegExp value`);
return import_toMatchText.toMatchText.call(this, "toContainClass", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.contain.class", { expectedText, isNot, timeout });
}, expected, options);
}
}
function toHaveCount(locator, expected, options) {
return import_toEqual.toEqual.call(this, "toHaveCount", locator, "Locator", async (isNot, timeout) => {
return await locator._expect("to.have.count", { expectedNumber: expected, isNot, timeout });
}, expected, options);
}
function toHaveCSS(locator, name, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveCSS", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.have.css", { expressionArg: name, expectedText, isNot, timeout });
}, expected, options);
}
function toHaveId(locator, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveId", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.have.id", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveJSProperty(locator, name, expected, options) {
return import_toEqual.toEqual.call(this, "toHaveJSProperty", locator, "Locator", async (isNot, timeout) => {
return await locator._expect("to.have.property", { expressionArg: name, expectedValue: expected, isNot, timeout });
}, expected, options);
}
function toHaveRole(locator, expected, options) {
if (!(0, import_utils.isString)(expected))
throw new Error(`"role" argument in toHaveRole must be a string`);
return import_toMatchText.toMatchText.call(this, "toHaveRole", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.have.role", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveText(locator, expected, options = {}) {
if (Array.isArray(expected)) {
return import_toEqual.toEqual.call(this, "toHaveText", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)(expected, { normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
return await locator._expect("to.have.text.array", { expectedText, isNot, useInnerText: options?.useInnerText, timeout });
}, expected, options);
} else {
return import_toMatchText.toMatchText.call(this, "toHaveText", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
return await locator._expect("to.have.text", { expectedText, isNot, useInnerText: options?.useInnerText, timeout });
}, expected, options);
}
}
function toHaveValue(locator, expected, options) {
return import_toMatchText.toMatchText.call(this, "toHaveValue", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
return await locator._expect("to.have.value", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveValues(locator, expected, options) {
return import_toEqual.toEqual.call(this, "toHaveValues", locator, "Locator", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
return await locator._expect("to.have.values", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveTitle(page, expected, options = {}) {
return import_toMatchText.toMatchText.call(this, "toHaveTitle", page, "Page", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { normalizeWhiteSpace: true });
return await page.mainFrame()._expect("to.have.title", { expectedText, isNot, timeout });
}, expected, options);
}
function toHaveURL(page, expected, options) {
if (typeof expected === "function")
return import_toHaveURL.toHaveURLWithPredicate.call(this, page, expected, options);
const baseURL = page.context()._options.baseURL;
expected = typeof expected === "string" ? (0, import_utils.constructURLBasedOnBaseURL)(baseURL, expected) : expected;
return import_toMatchText.toMatchText.call(this, "toHaveURL", page, "Page", async (isNot, timeout) => {
const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase });
return await page.mainFrame()._expect("to.have.url", { expectedText, isNot, timeout });
}, expected, options);
}
async function toBeOK(response) {
const matcherName = "toBeOK";
(0, import_util.expectTypes)(response, ["APIResponse"], matcherName);
const contentType = response.headers()["content-type"];
const isTextEncoding = contentType && (0, import_utils.isTextualMimeType)(contentType);
const [log, text] = this.isNot === response.ok() ? await Promise.all([
response._fetchLog(),
isTextEncoding ? response.text() : null
]) : [];
const message = () => (0, import_utils.formatMatcherMessage)(this.utils, {
isNot: this.isNot,
promise: this.promise,
matcherName,
receiver: "response",
expectation: "",
log
}) + (text === null ? "" : `
Response text:
${import_utils2.colors.dim(text?.substring(0, 1e3) || "")}`);
const pass = response.ok();
return { message, pass };
}
async function toPass(callback, options = {}) {
const testInfo = (0, import_globals.currentTestInfo)();
const timeout = (0, import_config.takeFirst)(options.timeout, testInfo?._projectInternal.expect?.toPass?.timeout, 0);
const intervals = (0, import_config.takeFirst)(options.intervals, testInfo?._projectInternal.expect?.toPass?.intervals, [100, 250, 500, 1e3]);
const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : import_testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
const result = await (0, import_utils.pollAgainstDeadline)(async () => {
if (testInfo && (0, import_globals.currentTestInfo)() !== testInfo)
return { continuePolling: false, result: void 0 };
try {
await callback();
return { continuePolling: !!this.isNot, result: void 0 };
} catch (e) {
return { continuePolling: !this.isNot, result: e };
}
}, deadline, intervals);
if (result.timedOut) {
const message = result.result ? [
result.result.message,
"",
`Call Log:`,
`- ${timeoutMessage}`
].join("\n") : timeoutMessage;
return { message: () => message, pass: !!this.isNot };
}
return { pass: !this.isNot, message: () => "" };
}
function computeMatcherTitleSuffix(matcherName, receiver, args) {
if (matcherName === "toHaveScreenshot") {
const title = (0, import_toMatchSnapshot.toHaveScreenshotStepTitle)(...args);
return { short: title ? `(${title})` : "" };
}
if (receiver && typeof receiver === "object" && receiver.constructor?.name === "Locator") {
try {
return { long: " " + (0, import_utils.asLocatorDescription)("javascript", receiver._selector) };
} catch {
}
}
return {};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
computeMatcherTitleSuffix,
toBeAttached,
toBeChecked,
toBeDisabled,
toBeEditable,
toBeEmpty,
toBeEnabled,
toBeFocused,
toBeHidden,
toBeInViewport,
toBeOK,
toBeVisible,
toContainClass,
toContainText,
toHaveAccessibleDescription,
toHaveAccessibleErrorMessage,
toHaveAccessibleName,
toHaveAttribute,
toHaveCSS,
toHaveClass,
toHaveCount,
toHaveId,
toHaveJSProperty,
toHaveRole,
toHaveText,
toHaveTitle,
toHaveURL,
toHaveValue,
toHaveValues,
toPass
});

View file

@ -0,0 +1,75 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toBeTruthy_exports = {};
__export(toBeTruthy_exports, {
toBeTruthy: () => toBeTruthy
});
module.exports = __toCommonJS(toBeTruthy_exports);
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
async function toBeTruthy(matcherName, locator, receiverType, expected, arg, query, options = {}) {
(0, import_util.expectTypes)(locator, [receiverType], matcherName);
const timeout = options.timeout ?? this.timeout;
const { matches: pass, log, timedOut, received, errorMessage } = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => "",
pass,
expected
};
}
let printedReceived;
let printedExpected;
if (pass) {
printedExpected = `Expected: not ${expected}`;
printedReceived = errorMessage ? "" : `Received: ${expected}`;
} else {
printedExpected = `Expected: ${expected}`;
printedReceived = errorMessage ? "" : `Received: ${received}`;
}
const message = () => {
return (0, import_utils.formatMatcherMessage)(this.utils, {
isNot: this.isNot,
promise: this.promise,
matcherName,
expectation: arg,
locator: locator.toString(),
timeout,
timedOut,
printedExpected,
printedReceived,
errorMessage,
log
});
};
return {
message,
pass,
actual: received,
name: matcherName,
expected,
log,
timeout: timedOut ? timeout : void 0
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toBeTruthy
});

100
backend/node_modules/playwright/lib/matchers/toEqual.js generated vendored Normal file
View file

@ -0,0 +1,100 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toEqual_exports = {};
__export(toEqual_exports, {
toEqual: () => toEqual
});
module.exports = __toCommonJS(toEqual_exports);
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
const EXPECTED_LABEL = "Expected";
const RECEIVED_LABEL = "Received";
async function toEqual(matcherName, locator, receiverType, query, expected, options = {}) {
(0, import_util.expectTypes)(locator, [receiverType], matcherName);
const timeout = options.timeout ?? this.timeout;
const { matches: pass, received, log, timedOut, errorMessage } = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => "",
pass,
expected
};
}
let printedReceived;
let printedExpected;
let printedDiff;
if (pass) {
printedExpected = `Expected: not ${this.utils.printExpected(expected)}`;
printedReceived = errorMessage ? "" : `Received: ${this.utils.printReceived(received)}`;
} else if (errorMessage) {
printedExpected = `Expected: ${this.utils.printExpected(expected)}`;
} else if (Array.isArray(expected) && Array.isArray(received)) {
const normalizedExpected = expected.map((exp, index) => {
const rec = received[index];
if ((0, import_utils.isRegExp)(exp))
return exp.test(rec) ? rec : exp;
return exp;
});
printedDiff = this.utils.printDiffOrStringify(
normalizedExpected,
received,
EXPECTED_LABEL,
RECEIVED_LABEL,
false
);
} else {
printedDiff = this.utils.printDiffOrStringify(
expected,
received,
EXPECTED_LABEL,
RECEIVED_LABEL,
false
);
}
const message = () => {
return (0, import_utils.formatMatcherMessage)(this.utils, {
isNot: this.isNot,
promise: this.promise,
matcherName,
expectation: "expected",
locator: locator.toString(),
timeout,
timedOut,
printedExpected,
printedReceived,
printedDiff,
errorMessage,
log
});
};
return {
actual: received,
expected,
message,
name: matcherName,
pass,
log,
timeout: timedOut ? timeout : void 0
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toEqual
});

View file

@ -0,0 +1,101 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toHaveURL_exports = {};
__export(toHaveURL_exports, {
toHaveURLWithPredicate: () => toHaveURLWithPredicate
});
module.exports = __toCommonJS(toHaveURL_exports);
var import_utils = require("playwright-core/lib/utils");
async function toHaveURLWithPredicate(page, expected, options) {
const matcherName = "toHaveURL";
const timeout = options?.timeout ?? this.timeout;
const baseURL = page.context()._options.baseURL;
let conditionSucceeded = false;
let lastCheckedURLString = void 0;
try {
await page.mainFrame().waitForURL(
(url) => {
lastCheckedURLString = url.toString();
if (options?.ignoreCase) {
return !this.isNot === (0, import_utils.urlMatches)(
baseURL?.toLocaleLowerCase(),
lastCheckedURLString.toLocaleLowerCase(),
expected
);
}
return !this.isNot === (0, import_utils.urlMatches)(baseURL, lastCheckedURLString, expected);
},
{ timeout }
);
conditionSucceeded = true;
} catch (e) {
conditionSucceeded = false;
}
if (conditionSucceeded)
return { name: matcherName, pass: !this.isNot, message: () => "" };
return {
name: matcherName,
pass: this.isNot,
message: () => toHaveURLMessage(
this,
matcherName,
expected,
lastCheckedURLString,
this.isNot,
true,
timeout
),
actual: lastCheckedURLString,
timeout
};
}
function toHaveURLMessage(state, matcherName, expected, received, pass, timedOut, timeout) {
const receivedString = received || "";
let printedReceived;
let printedExpected;
let printedDiff;
if (typeof expected === "function") {
printedExpected = `Expected: predicate to ${!state.isNot ? "succeed" : "fail"}`;
printedReceived = `Received: ${state.utils.printReceived(receivedString)}`;
} else {
if (pass) {
printedExpected = `Expected pattern: not ${state.utils.printExpected(expected)}`;
const formattedReceived = (0, import_utils.printReceivedStringContainExpectedResult)(state.utils, receivedString, null);
printedReceived = `Received string: ${formattedReceived}`;
} else {
const labelExpected = `Expected ${typeof expected === "string" ? "string" : "pattern"}`;
printedDiff = state.utils.printDiffOrStringify(expected, receivedString, labelExpected, "Received string", false);
}
}
return (0, import_utils.formatMatcherMessage)(state.utils, {
isNot: state.isNot,
promise: state.promise,
matcherName,
expectation: "expected",
timeout,
timedOut,
printedExpected,
printedReceived,
printedDiff
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toHaveURLWithPredicate
});

View file

@ -0,0 +1,159 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toMatchAriaSnapshot_exports = {};
__export(toMatchAriaSnapshot_exports, {
toMatchAriaSnapshot: () => toMatchAriaSnapshot
});
module.exports = __toCommonJS(toMatchAriaSnapshot_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
var import_globals = require("../common/globals");
async function toMatchAriaSnapshot(locator, expectedParam, options = {}) {
const matcherName = "toMatchAriaSnapshot";
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`toMatchAriaSnapshot() must be called during the test`);
if (testInfo._projectInternal.ignoreSnapshots)
return { pass: !this.isNot, message: () => "", name: "toMatchAriaSnapshot", expected: "" };
const updateSnapshots = testInfo.config.updateSnapshots;
let expected;
let timeout;
let expectedPath;
if ((0, import_utils.isString)(expectedParam)) {
expected = expectedParam;
timeout = options.timeout ?? this.timeout;
} else {
const legacyPath = testInfo._resolveSnapshotPaths("aria", expectedParam?.name, "dontUpdateSnapshotIndex", ".yml").absoluteSnapshotPath;
expectedPath = testInfo._resolveSnapshotPaths("aria", expectedParam?.name, "updateSnapshotIndex").absoluteSnapshotPath;
if (!await (0, import_util.fileExistsAsync)(expectedPath) && await (0, import_util.fileExistsAsync)(legacyPath))
expectedPath = legacyPath;
expected = await import_fs.default.promises.readFile(expectedPath, "utf8").catch(() => "");
timeout = expectedParam?.timeout ?? this.timeout;
}
const generateMissingBaseline = updateSnapshots === "missing" && !expected;
if (generateMissingBaseline) {
if (this.isNot) {
const message2 = `Matchers using ".not" can't generate new baselines`;
return { pass: this.isNot, message: () => message2, name: "toMatchAriaSnapshot" };
} else {
expected = `- none "Generating new baseline"`;
}
}
expected = unshift(expected);
const { matches: pass, received, log, timedOut, errorMessage } = await locator._expect("to.match.aria", { expectedValue: expected, isNot: this.isNot, timeout });
const typedReceived = received;
const message = () => {
let printedExpected;
let printedReceived;
let printedDiff;
if (errorMessage) {
printedExpected = `Expected: ${this.isNot ? "not " : ""}${this.utils.printExpected(expected)}`;
} else if (pass) {
const receivedString = (0, import_utils.printReceivedStringContainExpectedSubstring)(this.utils, typedReceived.raw, typedReceived.raw.indexOf(expected), expected.length);
printedExpected = `Expected: not ${this.utils.printExpected(expected)}`;
printedReceived = `Received: ${receivedString}`;
} else {
printedDiff = this.utils.printDiffOrStringify(expected, typedReceived.raw, "Expected", "Received", false);
}
return (0, import_utils.formatMatcherMessage)(this.utils, {
isNot: this.isNot,
promise: this.promise,
matcherName,
expectation: "expected",
locator: locator.toString(),
timeout,
timedOut,
printedExpected,
printedReceived,
printedDiff,
errorMessage,
log
});
};
if (errorMessage)
return { pass: this.isNot, message, name: "toMatchAriaSnapshot", expected };
if (!this.isNot) {
if (updateSnapshots === "all" || updateSnapshots === "changed" && pass === this.isNot || generateMissingBaseline) {
if (expectedPath) {
await import_fs.default.promises.mkdir(import_path.default.dirname(expectedPath), { recursive: true });
await import_fs.default.promises.writeFile(expectedPath, typedReceived.regex, "utf8");
const relativePath = import_path.default.relative(process.cwd(), expectedPath);
if (updateSnapshots === "missing") {
const message2 = `A snapshot doesn't exist at ${relativePath}, writing actual.`;
testInfo._hasNonRetriableError = true;
testInfo._failWithError(new Error(message2));
} else {
const message2 = `A snapshot is generated at ${relativePath}.`;
console.log(message2);
}
return { pass: true, message: () => "", name: "toMatchAriaSnapshot" };
} else {
const suggestedRebaseline = `\`
${(0, import_utils.escapeTemplateString)(indent(typedReceived.regex, "{indent} "))}
{indent}\``;
if (updateSnapshots === "missing") {
const message2 = "A snapshot is not provided, generating new baseline.";
testInfo._hasNonRetriableError = true;
testInfo._failWithError(new Error(message2));
}
return { pass: false, message: () => "", name: "toMatchAriaSnapshot", suggestedRebaseline };
}
}
}
return {
name: matcherName,
expected,
message,
pass,
actual: received,
log,
timeout: timedOut ? timeout : void 0
};
}
function unshift(snapshot) {
const lines = snapshot.split("\n");
let whitespacePrefixLength = 100;
for (const line of lines) {
if (!line.trim())
continue;
const match = line.match(/^(\s*)/);
if (match && match[1].length < whitespacePrefixLength)
whitespacePrefixLength = match[1].length;
}
return lines.filter((t) => t.trim()).map((line) => line.substring(whitespacePrefixLength)).join("\n");
}
function indent(snapshot, indent2) {
return snapshot.split("\n").map((line) => indent2 + line).join("\n");
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toMatchAriaSnapshot
});

View file

@ -0,0 +1,342 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toMatchSnapshot_exports = {};
__export(toMatchSnapshot_exports, {
toHaveScreenshot: () => toHaveScreenshot,
toHaveScreenshotStepTitle: () => toHaveScreenshotStepTitle,
toMatchSnapshot: () => toMatchSnapshot
});
module.exports = __toCommonJS(toMatchSnapshot_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_utils = require("playwright-core/lib/utils");
var import_utils2 = require("playwright-core/lib/utils");
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_util = require("../util");
var import_globals = require("../common/globals");
const NonConfigProperties = [
"clip",
"fullPage",
"mask",
"maskColor",
"omitBackground",
"timeout"
];
class SnapshotHelper {
constructor(state, testInfo, matcherName, locator, anonymousSnapshotExtension, configOptions, nameOrOptions, optOptions) {
let name;
if (Array.isArray(nameOrOptions) || typeof nameOrOptions === "string") {
name = nameOrOptions;
this.options = { ...optOptions };
} else {
const { name: nameFromOptions, ...options } = nameOrOptions;
this.options = options;
name = nameFromOptions;
}
this.name = Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
const resolvedPaths = testInfo._resolveSnapshotPaths(matcherName === "toHaveScreenshot" ? "screenshot" : "snapshot", name, "updateSnapshotIndex", anonymousSnapshotExtension);
this.expectedPath = resolvedPaths.absoluteSnapshotPath;
this.attachmentBaseName = resolvedPaths.relativeOutputPath;
const outputBasePath = testInfo._getOutputPath(resolvedPaths.relativeOutputPath);
this.legacyExpectedPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-expected");
this.previousPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-previous");
this.actualPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-actual");
this.diffPath = (0, import_util.addSuffixToFilePath)(outputBasePath, "-diff");
const filteredConfigOptions = { ...configOptions };
for (const prop of NonConfigProperties)
delete filteredConfigOptions[prop];
this.options = {
...filteredConfigOptions,
...this.options
};
if (this.options._comparator) {
this.options.comparator = this.options._comparator;
delete this.options._comparator;
}
if (this.options.maxDiffPixels !== void 0 && this.options.maxDiffPixels < 0)
throw new Error("`maxDiffPixels` option value must be non-negative integer");
if (this.options.maxDiffPixelRatio !== void 0 && (this.options.maxDiffPixelRatio < 0 || this.options.maxDiffPixelRatio > 1))
throw new Error("`maxDiffPixelRatio` option value must be between 0 and 1");
this.matcherName = matcherName;
this.locator = locator;
this.updateSnapshots = testInfo.config.updateSnapshots;
this.mimeType = import_utilsBundle.mime.getType(import_path.default.basename(this.expectedPath)) ?? "application/octet-stream";
this.comparator = (0, import_utils.getComparator)(this.mimeType);
this.testInfo = testInfo;
this.state = state;
this.kind = this.mimeType.startsWith("image/") ? "Screenshot" : "Snapshot";
}
createMatcherResult(message, pass, log) {
const unfiltered = {
name: this.matcherName,
expected: this.expectedPath,
actual: this.actualPath,
diff: this.diffPath,
pass,
message: () => message,
log
};
return Object.fromEntries(Object.entries(unfiltered).filter(([_, v]) => v !== void 0));
}
handleMissingNegated() {
const isWriteMissingMode = this.updateSnapshots !== "none";
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? `, matchers using ".not" won't write them automatically.` : "."}`;
return this.createMatcherResult(message, true);
}
handleDifferentNegated() {
return this.createMatcherResult("", false);
}
handleMatchingNegated() {
const message = [
import_utils2.colors.red(`${this.kind} comparison failed:`),
"",
indent("Expected result should be different from the actual one.", " ")
].join("\n");
return this.createMatcherResult(message, true);
}
handleMissing(actual, step) {
const isWriteMissingMode = this.updateSnapshots !== "none";
if (isWriteMissingMode)
writeFileSync(this.expectedPath, actual);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
writeFileSync(this.actualPath, actual);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ", writing actual." : "."}`;
if (this.updateSnapshots === "all" || this.updateSnapshots === "changed") {
console.log(message);
return this.createMatcherResult(message, true);
}
if (this.updateSnapshots === "missing") {
this.testInfo._hasNonRetriableError = true;
this.testInfo._failWithError(new Error(message));
return this.createMatcherResult("", true);
}
return this.createMatcherResult(message, false);
}
handleDifferent(actual, expected, previous, diff, header, diffError, log, step) {
const output = [`${header}${indent(diffError, " ")}`];
if (this.name) {
output.push("");
output.push(` Snapshot: ${this.name}`);
}
if (expected !== void 0) {
writeFileSync(this.legacyExpectedPath, expected);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-expected"), contentType: this.mimeType, path: this.expectedPath });
}
if (previous !== void 0) {
writeFileSync(this.previousPath, previous);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-previous"), contentType: this.mimeType, path: this.previousPath });
}
if (actual !== void 0) {
writeFileSync(this.actualPath, actual);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-actual"), contentType: this.mimeType, path: this.actualPath });
}
if (diff !== void 0) {
writeFileSync(this.diffPath, diff);
step?._attachToStep({ name: (0, import_util.addSuffixToFilePath)(this.attachmentBaseName, "-diff"), contentType: this.mimeType, path: this.diffPath });
}
if (log?.length)
output.push((0, import_utils.callLogText)(this.state.utils, log));
else
output.push("");
return this.createMatcherResult(output.join("\n"), false, log);
}
handleMatching() {
return this.createMatcherResult("", true);
}
}
function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`toMatchSnapshot() must be called during the test`);
if (received instanceof Promise)
throw new Error("An unresolved Promise was passed to toMatchSnapshot(), make sure to resolve it by adding await to it.");
if (testInfo._projectInternal.ignoreSnapshots)
return { pass: !this.isNot, message: () => "", name: "toMatchSnapshot", expected: nameOrOptions };
const configOptions = testInfo._projectInternal.expect?.toMatchSnapshot || {};
const helper = new SnapshotHelper(
this,
testInfo,
"toMatchSnapshot",
void 0,
"." + determineFileExtension(received),
configOptions,
nameOrOptions,
optOptions
);
if (this.isNot) {
if (!import_fs.default.existsSync(helper.expectedPath))
return helper.handleMissingNegated();
const isDifferent = !!helper.comparator(received, import_fs.default.readFileSync(helper.expectedPath), helper.options);
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
if (!import_fs.default.existsSync(helper.expectedPath))
return helper.handleMissing(received, this._stepInfo);
const expected = import_fs.default.readFileSync(helper.expectedPath);
if (helper.updateSnapshots === "all") {
if (!(0, import_utils.compareBuffersOrStrings)(received, expected))
return helper.handleMatching();
writeFileSync(helper.expectedPath, received);
console.log(helper.expectedPath + " is not the same, writing actual.");
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
}
if (helper.updateSnapshots === "changed") {
const result2 = helper.comparator(received, expected, helper.options);
if (!result2)
return helper.handleMatching();
writeFileSync(helper.expectedPath, received);
console.log(helper.expectedPath + " does not match, writing actual.");
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
}
const result = helper.comparator(received, expected, helper.options);
if (!result)
return helper.handleMatching();
const header = (0, import_utils.formatMatcherMessage)(this.utils, { promise: this.promise, isNot: this.isNot, matcherName: "toMatchSnapshot", receiver: (0, import_utils.isString)(received) ? "string" : "Buffer", expectation: "expected" });
return helper.handleDifferent(received, expected, void 0, result.diff, header, result.errorMessage, void 0, this._stepInfo);
}
function toHaveScreenshotStepTitle(nameOrOptions = {}, optOptions = {}) {
let name;
if (typeof nameOrOptions === "object" && !Array.isArray(nameOrOptions))
name = nameOrOptions.name;
else
name = nameOrOptions;
return Array.isArray(name) ? name.join(import_path.default.sep) : name || "";
}
async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions = {}) {
const testInfo = (0, import_globals.currentTestInfo)();
if (!testInfo)
throw new Error(`toHaveScreenshot() must be called during the test`);
if (testInfo._projectInternal.ignoreSnapshots)
return { pass: !this.isNot, message: () => "", name: "toHaveScreenshot", expected: nameOrOptions };
(0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
const [page, locator] = pageOrLocator.constructor.name === "Page" ? [pageOrLocator, void 0] : [pageOrLocator.page(), pageOrLocator];
const configOptions = testInfo._projectInternal.expect?.toHaveScreenshot || {};
const helper = new SnapshotHelper(this, testInfo, "toHaveScreenshot", locator, void 0, configOptions, nameOrOptions, optOptions);
if (!helper.expectedPath.toLowerCase().endsWith(".png"))
throw new Error(`Screenshot name "${import_path.default.basename(helper.expectedPath)}" must have '.png' extension`);
(0, import_util.expectTypes)(pageOrLocator, ["Page", "Locator"], "toHaveScreenshot");
const style = await loadScreenshotStyles(helper.options.stylePath);
const timeout = helper.options.timeout ?? this.timeout;
const expectScreenshotOptions = {
locator,
animations: helper.options.animations ?? "disabled",
caret: helper.options.caret ?? "hide",
clip: helper.options.clip,
fullPage: helper.options.fullPage,
mask: helper.options.mask,
maskColor: helper.options.maskColor,
omitBackground: helper.options.omitBackground,
scale: helper.options.scale ?? "css",
style,
isNot: !!this.isNot,
timeout,
comparator: helper.options.comparator,
maxDiffPixels: helper.options.maxDiffPixels,
maxDiffPixelRatio: helper.options.maxDiffPixelRatio,
threshold: helper.options.threshold
};
const hasSnapshot = import_fs.default.existsSync(helper.expectedPath);
if (this.isNot) {
if (!hasSnapshot)
return helper.handleMissingNegated();
expectScreenshotOptions.expected = await import_fs.default.promises.readFile(helper.expectedPath);
const isDifferent = !(await page._expectScreenshot(expectScreenshotOptions)).errorMessage;
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
if (helper.updateSnapshots === "none" && !hasSnapshot)
return helper.createMatcherResult(`A snapshot doesn't exist at ${helper.expectedPath}.`, false);
if (!hasSnapshot) {
const { actual: actual2, previous: previous2, diff: diff2, errorMessage: errorMessage2, log: log2, timedOut: timedOut2 } = await page._expectScreenshot(expectScreenshotOptions);
if (errorMessage2) {
const header2 = (0, import_utils.formatMatcherMessage)(this.utils, { promise: this.promise, isNot: this.isNot, matcherName: "toHaveScreenshot", locator: locator?.toString(), expectation: "expected", timeout, timedOut: timedOut2 });
return helper.handleDifferent(actual2, void 0, previous2, diff2, header2, errorMessage2, log2, this._stepInfo);
}
return helper.handleMissing(actual2, this._stepInfo);
}
const expected = await import_fs.default.promises.readFile(helper.expectedPath);
expectScreenshotOptions.expected = helper.updateSnapshots === "all" ? void 0 : expected;
const { actual, previous, diff, errorMessage, log, timedOut } = await page._expectScreenshot(expectScreenshotOptions);
const writeFiles = (actualBuffer) => {
writeFileSync(helper.expectedPath, actualBuffer);
writeFileSync(helper.actualPath, actualBuffer);
console.log(helper.expectedPath + " is re-generated, writing actual.");
return helper.createMatcherResult(helper.expectedPath + " running with --update-snapshots, writing actual.", true);
};
if (!errorMessage) {
if (helper.updateSnapshots === "all" && actual && (0, import_utils.compareBuffersOrStrings)(actual, expected)) {
console.log(helper.expectedPath + " is re-generated, writing actual.");
return writeFiles(actual);
}
return helper.handleMatching();
}
if (helper.updateSnapshots === "changed" || helper.updateSnapshots === "all") {
if (actual)
return writeFiles(actual);
let header2 = (0, import_utils.formatMatcherMessage)(this.utils, { promise: this.promise, isNot: this.isNot, matcherName: "toHaveScreenshot", locator: locator?.toString(), expectation: "expected", timeout, timedOut });
header2 += " Failed to re-generate expected.\n";
return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header2, errorMessage, log, this._stepInfo);
}
const header = (0, import_utils.formatMatcherMessage)(this.utils, { promise: this.promise, isNot: this.isNot, matcherName: "toHaveScreenshot", locator: locator?.toString(), expectation: "expected", timeout, timedOut });
return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log, this._stepInfo);
}
function writeFileSync(aPath, content) {
import_fs.default.mkdirSync(import_path.default.dirname(aPath), { recursive: true });
import_fs.default.writeFileSync(aPath, content);
}
function indent(lines, tab) {
return lines.replace(/^(?=.+$)/gm, tab);
}
function determineFileExtension(file) {
if (typeof file === "string")
return "txt";
if (compareMagicBytes(file, [137, 80, 78, 71, 13, 10, 26, 10]))
return "png";
if (compareMagicBytes(file, [255, 216, 255]))
return "jpg";
return "dat";
}
function compareMagicBytes(file, magicBytes) {
return Buffer.compare(Buffer.from(magicBytes), file.slice(0, magicBytes.length)) === 0;
}
async function loadScreenshotStyles(stylePath) {
if (!stylePath)
return;
const stylePaths = Array.isArray(stylePath) ? stylePath : [stylePath];
const styles = await Promise.all(stylePaths.map(async (stylePath2) => {
const text = await import_fs.default.promises.readFile(stylePath2, "utf8");
return text.trim();
}));
return styles.join("\n").trim() || void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toHaveScreenshot,
toHaveScreenshotStepTitle,
toMatchSnapshot
});

View file

@ -0,0 +1,99 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var toMatchText_exports = {};
__export(toMatchText_exports, {
toMatchText: () => toMatchText
});
module.exports = __toCommonJS(toMatchText_exports);
var import_utils = require("playwright-core/lib/utils");
var import_util = require("../util");
async function toMatchText(matcherName, receiver, receiverType, query, expected, options = {}) {
(0, import_util.expectTypes)(receiver, [receiverType], matcherName);
const locator = receiverType === "Locator" ? receiver : void 0;
if (!(typeof expected === "string") && !(expected && typeof expected.test === "function")) {
const errorMessage2 = `Error: ${this.utils.EXPECTED_COLOR("expected")} value must be a string or regular expression
${this.utils.printWithType("Expected", expected, this.utils.printExpected)}`;
throw new Error((0, import_utils.formatMatcherMessage)(this.utils, { promise: this.promise, isNot: this.isNot, locator: locator?.toString(), matcherName, expectation: "expected", errorMessage: errorMessage2 }));
}
const timeout = options.timeout ?? this.timeout;
const { matches: pass, received, log, timedOut, errorMessage } = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => "",
pass,
expected
};
}
const expectedSuffix = typeof expected === "string" ? options.matchSubstring ? " substring" : "" : " pattern";
const receivedSuffix = typeof expected === "string" ? options.matchSubstring ? " string" : "" : " string";
const receivedString = received || "";
let printedReceived;
let printedExpected;
let printedDiff;
if (pass) {
if (typeof expected === "string") {
printedExpected = `Expected${expectedSuffix}: not ${this.utils.printExpected(expected)}`;
if (!errorMessage) {
const formattedReceived = (0, import_utils.printReceivedStringContainExpectedSubstring)(this.utils, receivedString, receivedString.indexOf(expected), expected.length);
printedReceived = `Received${receivedSuffix}: ${formattedReceived}`;
}
} else {
printedExpected = `Expected${expectedSuffix}: not ${this.utils.printExpected(expected)}`;
if (!errorMessage) {
const formattedReceived = (0, import_utils.printReceivedStringContainExpectedResult)(this.utils, receivedString, typeof expected.exec === "function" ? expected.exec(receivedString) : null);
printedReceived = `Received${receivedSuffix}: ${formattedReceived}`;
}
}
} else {
if (errorMessage)
printedExpected = `Expected${expectedSuffix}: ${this.utils.printExpected(expected)}`;
else
printedDiff = this.utils.printDiffOrStringify(expected, receivedString, `Expected${expectedSuffix}`, `Received${receivedSuffix}`, false);
}
const message = () => {
return (0, import_utils.formatMatcherMessage)(this.utils, {
promise: this.promise,
isNot: this.isNot,
matcherName,
expectation: "expected",
locator: locator?.toString(),
timeout,
timedOut,
printedExpected,
printedReceived,
printedDiff,
log,
errorMessage
});
};
return {
name: matcherName,
expected,
message,
pass,
actual: received,
log,
timeout: timedOut ? timeout : void 0
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
toMatchText
});

View file

@ -0,0 +1,329 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var browserContextFactory_exports = {};
__export(browserContextFactory_exports, {
SharedContextFactory: () => SharedContextFactory,
contextFactory: () => contextFactory,
identityBrowserContextFactory: () => identityBrowserContextFactory
});
module.exports = __toCommonJS(browserContextFactory_exports);
var import_crypto = __toESM(require("crypto"));
var import_fs = __toESM(require("fs"));
var import_net = __toESM(require("net"));
var import_path = __toESM(require("path"));
var playwright = __toESM(require("playwright-core"));
var import_registry = require("playwright-core/lib/server/registry/index");
var import_server = require("playwright-core/lib/server");
var import_log = require("../log");
var import_config = require("./config");
var import_server2 = require("../sdk/server");
function contextFactory(config) {
if (config.sharedBrowserContext)
return SharedContextFactory.create(config);
if (config.browser.remoteEndpoint)
return new RemoteContextFactory(config);
if (config.browser.cdpEndpoint)
return new CdpContextFactory(config);
if (config.browser.isolated)
return new IsolatedContextFactory(config);
return new PersistentContextFactory(config);
}
function identityBrowserContextFactory(browserContext) {
return {
createContext: async (clientInfo, abortSignal, options) => {
return {
browserContext,
close: async () => {
}
};
}
};
}
class BaseContextFactory {
constructor(name, config) {
this._logName = name;
this.config = config;
}
async _obtainBrowser(clientInfo, options) {
if (this._browserPromise)
return this._browserPromise;
(0, import_log.testDebug)(`obtain browser (${this._logName})`);
this._browserPromise = this._doObtainBrowser(clientInfo, options);
void this._browserPromise.then((browser) => {
browser.on("disconnected", () => {
this._browserPromise = void 0;
});
}).catch(() => {
this._browserPromise = void 0;
});
return this._browserPromise;
}
async _doObtainBrowser(clientInfo, options) {
throw new Error("Not implemented");
}
async createContext(clientInfo, _, options) {
(0, import_log.testDebug)(`create browser context (${this._logName})`);
const browser = await this._obtainBrowser(clientInfo, options);
const browserContext = await this._doCreateContext(browser, clientInfo);
await addInitScript(browserContext, this.config.browser.initScript);
return {
browserContext,
close: () => this._closeBrowserContext(browserContext, browser)
};
}
async _doCreateContext(browser, clientInfo) {
throw new Error("Not implemented");
}
async _closeBrowserContext(browserContext, browser) {
(0, import_log.testDebug)(`close browser context (${this._logName})`);
if (browser.contexts().length === 1)
this._browserPromise = void 0;
await browserContext.close().catch(import_log.logUnhandledError);
if (browser.contexts().length === 0) {
(0, import_log.testDebug)(`close browser (${this._logName})`);
await browser.close().catch(import_log.logUnhandledError);
}
}
}
class IsolatedContextFactory extends BaseContextFactory {
constructor(config) {
super("isolated", config);
}
async _doObtainBrowser(clientInfo, options) {
await injectCdpPort(this.config.browser);
const browserType = playwright[this.config.browser.browserName];
const tracesDir = await computeTracesDir(this.config, clientInfo);
if (tracesDir && this.config.saveTrace)
await startTraceServer(this.config, tracesDir);
return browserType.launch({
tracesDir,
...this.config.browser.launchOptions,
handleSIGINT: false,
handleSIGTERM: false,
...options.forceHeadless !== void 0 ? { headless: options.forceHeadless === "headless" } : {}
}).catch((error) => {
if (error.message.includes("Executable doesn't exist"))
throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
throw error;
});
}
async _doCreateContext(browser, clientInfo) {
return browser.newContext(await browserContextOptionsFromConfig(this.config, clientInfo));
}
}
class CdpContextFactory extends BaseContextFactory {
constructor(config) {
super("cdp", config);
}
async _doObtainBrowser() {
return playwright.chromium.connectOverCDP(this.config.browser.cdpEndpoint, {
headers: this.config.browser.cdpHeaders,
timeout: this.config.browser.cdpTimeout
});
}
async _doCreateContext(browser) {
return this.config.browser.isolated ? await browser.newContext() : browser.contexts()[0];
}
}
class RemoteContextFactory extends BaseContextFactory {
constructor(config) {
super("remote", config);
}
async _doObtainBrowser() {
const url = new URL(this.config.browser.remoteEndpoint);
url.searchParams.set("browser", this.config.browser.browserName);
if (this.config.browser.launchOptions)
url.searchParams.set("launch-options", JSON.stringify(this.config.browser.launchOptions));
return playwright[this.config.browser.browserName].connect(String(url));
}
async _doCreateContext(browser) {
return browser.newContext();
}
}
class PersistentContextFactory {
constructor(config) {
this.name = "persistent";
this.description = "Create a new persistent browser context";
this._userDataDirs = /* @__PURE__ */ new Set();
this.config = config;
}
async createContext(clientInfo, abortSignal, options) {
await injectCdpPort(this.config.browser);
(0, import_log.testDebug)("create browser context (persistent)");
const userDataDir = this.config.browser.userDataDir ?? await this._createUserDataDir(clientInfo);
const tracesDir = await computeTracesDir(this.config, clientInfo);
if (tracesDir && this.config.saveTrace)
await startTraceServer(this.config, tracesDir);
this._userDataDirs.add(userDataDir);
(0, import_log.testDebug)("lock user data dir", userDataDir);
const browserType = playwright[this.config.browser.browserName];
for (let i = 0; i < 5; i++) {
const launchOptions = {
tracesDir,
...this.config.browser.launchOptions,
...await browserContextOptionsFromConfig(this.config, clientInfo),
handleSIGINT: false,
handleSIGTERM: false,
ignoreDefaultArgs: [
"--disable-extensions"
],
assistantMode: true,
...options.forceHeadless !== void 0 ? { headless: options.forceHeadless === "headless" } : {}
};
try {
const browserContext = await browserType.launchPersistentContext(userDataDir, launchOptions);
await addInitScript(browserContext, this.config.browser.initScript);
const close = () => this._closeBrowserContext(browserContext, userDataDir);
return { browserContext, close };
} catch (error) {
if (error.message.includes("Executable doesn't exist"))
throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
if (error.message.includes("cannot open shared object file: No such file or directory")) {
const browserName = launchOptions.channel ?? this.config.browser.browserName;
throw new Error(`Missing system dependencies required to run browser ${browserName}. Install them with: sudo npx playwright install-deps ${browserName}`);
}
if (error.message.includes("ProcessSingleton") || // On Windows the process exits silently with code 21 when the profile is in use.
error.message.includes("exitCode=21")) {
await new Promise((resolve) => setTimeout(resolve, 1e3));
continue;
}
throw error;
}
}
throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
}
async _closeBrowserContext(browserContext, userDataDir) {
(0, import_log.testDebug)("close browser context (persistent)");
(0, import_log.testDebug)("release user data dir", userDataDir);
await browserContext.close().catch(() => {
});
this._userDataDirs.delete(userDataDir);
if (process.env.PWMCP_PROFILES_DIR_FOR_TEST && userDataDir.startsWith(process.env.PWMCP_PROFILES_DIR_FOR_TEST))
await import_fs.default.promises.rm(userDataDir, { recursive: true }).catch(import_log.logUnhandledError);
(0, import_log.testDebug)("close browser context complete (persistent)");
}
async _createUserDataDir(clientInfo) {
const dir = process.env.PWMCP_PROFILES_DIR_FOR_TEST ?? import_registry.registryDirectory;
const browserToken = this.config.browser.launchOptions?.channel ?? this.config.browser?.browserName;
const rootPath = (0, import_server2.firstRootPath)(clientInfo);
const rootPathToken = rootPath ? `-${createHash(rootPath)}` : "";
const result = import_path.default.join(dir, `mcp-${browserToken}${rootPathToken}`);
await import_fs.default.promises.mkdir(result, { recursive: true });
return result;
}
}
async function injectCdpPort(browserConfig) {
if (browserConfig.browserName === "chromium")
browserConfig.launchOptions.cdpPort = await findFreePort();
}
async function findFreePort() {
return new Promise((resolve, reject) => {
const server = import_net.default.createServer();
server.listen(0, () => {
const { port } = server.address();
server.close(() => resolve(port));
});
server.on("error", reject);
});
}
async function startTraceServer(config, tracesDir) {
if (!config.saveTrace)
return;
const server = await (0, import_server.startTraceViewerServer)();
const urlPrefix = server.urlPrefix("human-readable");
const url = urlPrefix + "/trace/index.html?trace=" + tracesDir + "/trace.json";
console.error("\nTrace viewer listening on " + url);
}
function createHash(data) {
return import_crypto.default.createHash("sha256").update(data).digest("hex").slice(0, 7);
}
async function addInitScript(browserContext, initScript) {
for (const scriptPath of initScript ?? [])
await browserContext.addInitScript({ path: import_path.default.resolve(scriptPath) });
}
class SharedContextFactory {
static create(config) {
if (SharedContextFactory._instance)
throw new Error("SharedContextFactory already exists");
const baseConfig = { ...config, sharedBrowserContext: false };
const baseFactory = contextFactory(baseConfig);
SharedContextFactory._instance = new SharedContextFactory(baseFactory);
return SharedContextFactory._instance;
}
constructor(baseFactory) {
this._baseFactory = baseFactory;
}
async createContext(clientInfo, abortSignal, options) {
if (!this._contextPromise) {
(0, import_log.testDebug)("create shared browser context");
this._contextPromise = this._baseFactory.createContext(clientInfo, abortSignal, options);
}
const { browserContext } = await this._contextPromise;
(0, import_log.testDebug)(`shared context client connected`);
return {
browserContext,
close: async () => {
(0, import_log.testDebug)(`shared context client disconnected`);
}
};
}
static async dispose() {
await SharedContextFactory._instance?._dispose();
}
async _dispose() {
const contextPromise = this._contextPromise;
this._contextPromise = void 0;
if (!contextPromise)
return;
const { close } = await contextPromise;
await close();
}
}
async function computeTracesDir(config, clientInfo) {
if (!config.saveTrace && !config.capabilities?.includes("tracing"))
return;
return await (0, import_config.outputFile)(config, clientInfo, `traces`, { origin: "code", title: "Collecting trace" });
}
async function browserContextOptionsFromConfig(config, clientInfo) {
const result = { ...config.browser.contextOptions };
if (config.saveVideo) {
const dir = await (0, import_config.outputFile)(config, clientInfo, `videos`, { origin: "code", title: "Saving video" });
result.recordVideo = {
dir,
size: config.saveVideo
};
}
return result;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SharedContextFactory,
contextFactory,
identityBrowserContextFactory
});

View file

@ -0,0 +1,84 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var browserServerBackend_exports = {};
__export(browserServerBackend_exports, {
BrowserServerBackend: () => BrowserServerBackend
});
module.exports = __toCommonJS(browserServerBackend_exports);
var import_context = require("./context");
var import_log = require("../log");
var import_response = require("./response");
var import_sessionLog = require("./sessionLog");
var import_tools = require("./tools");
var import_tool = require("../sdk/tool");
class BrowserServerBackend {
constructor(config, factory) {
this._config = config;
this._browserContextFactory = factory;
this._tools = (0, import_tools.filteredTools)(config);
}
async initialize(clientInfo) {
this._sessionLog = this._config.saveSession ? await import_sessionLog.SessionLog.create(this._config, clientInfo) : void 0;
this._context = new import_context.Context({
config: this._config,
browserContextFactory: this._browserContextFactory,
sessionLog: this._sessionLog,
clientInfo
});
}
async listTools() {
return this._tools.map((tool) => (0, import_tool.toMcpTool)(tool.schema));
}
async callTool(name, rawArguments) {
const tool = this._tools.find((tool2) => tool2.schema.name === name);
if (!tool) {
return {
content: [{ type: "text", text: `### Error
Tool "${name}" not found` }],
isError: true
};
}
const parsedArguments = tool.schema.inputSchema.parse(rawArguments || {});
const context = this._context;
const response = import_response.Response.create(context, name, parsedArguments);
context.setRunningTool(name);
let responseObject;
try {
await tool.handle(context, parsedArguments, response);
responseObject = await response.build();
this._sessionLog?.logResponse(name, parsedArguments, responseObject);
} catch (error) {
return {
content: [{ type: "text", text: `### Error
${String(error)}` }],
isError: true
};
} finally {
context.setRunningTool(void 0);
}
return responseObject;
}
serverClosed() {
void this._context?.dispose().catch(import_log.logUnhandledError);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BrowserServerBackend
});

View file

@ -0,0 +1,421 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var config_exports = {};
__export(config_exports, {
commaSeparatedList: () => commaSeparatedList,
configFromCLIOptions: () => configFromCLIOptions,
defaultConfig: () => defaultConfig,
dotenvFileLoader: () => dotenvFileLoader,
enumParser: () => enumParser,
headerParser: () => headerParser,
numberParser: () => numberParser,
outputDir: () => outputDir,
outputFile: () => outputFile,
resolutionParser: () => resolutionParser,
resolveCLIConfig: () => resolveCLIConfig,
resolveConfig: () => resolveConfig,
semicolonSeparatedList: () => semicolonSeparatedList
});
module.exports = __toCommonJS(config_exports);
var import_fs = __toESM(require("fs"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_playwright_core = require("playwright-core");
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_util = require("../../util");
var import_server = require("../sdk/server");
const defaultConfig = {
browser: {
browserName: "chromium",
launchOptions: {
channel: "chrome",
headless: import_os.default.platform() === "linux" && !process.env.DISPLAY,
chromiumSandbox: true
},
contextOptions: {
viewport: null
}
},
console: {
level: "info"
},
network: {
allowedOrigins: void 0,
blockedOrigins: void 0
},
server: {},
saveTrace: false,
snapshot: {
mode: "incremental",
output: "stdout"
},
timeouts: {
action: 5e3,
navigation: 6e4
}
};
async function resolveConfig(config) {
return mergeConfig(defaultConfig, config);
}
async function resolveCLIConfig(cliOptions) {
const configInFile = await loadConfig(cliOptions.config);
const envOverrides = configFromEnv();
const cliOverrides = configFromCLIOptions(cliOptions);
let result = defaultConfig;
result = mergeConfig(result, configInFile);
result = mergeConfig(result, envOverrides);
result = mergeConfig(result, cliOverrides);
await validateConfig(result);
return result;
}
async function validateConfig(config) {
if (config.browser.initScript) {
for (const script of config.browser.initScript) {
if (!await (0, import_util.fileExistsAsync)(script))
throw new Error(`Init script file does not exist: ${script}`);
}
}
if (config.browser.initPage) {
for (const page of config.browser.initPage) {
if (!await (0, import_util.fileExistsAsync)(page))
throw new Error(`Init page file does not exist: ${page}`);
}
}
if (config.sharedBrowserContext && config.saveVideo)
throw new Error("saveVideo is not supported when sharedBrowserContext is true");
}
function configFromCLIOptions(cliOptions) {
let browserName;
let channel;
switch (cliOptions.browser) {
case "chrome":
case "chrome-beta":
case "chrome-canary":
case "chrome-dev":
case "chromium":
case "msedge":
case "msedge-beta":
case "msedge-canary":
case "msedge-dev":
browserName = "chromium";
channel = cliOptions.browser;
break;
case "firefox":
browserName = "firefox";
break;
case "webkit":
browserName = "webkit";
break;
}
const launchOptions = {
channel,
executablePath: cliOptions.executablePath,
headless: cliOptions.headless
};
if (cliOptions.sandbox === false)
launchOptions.chromiumSandbox = false;
if (cliOptions.proxyServer) {
launchOptions.proxy = {
server: cliOptions.proxyServer
};
if (cliOptions.proxyBypass)
launchOptions.proxy.bypass = cliOptions.proxyBypass;
}
if (cliOptions.device && cliOptions.cdpEndpoint)
throw new Error("Device emulation is not supported with cdpEndpoint.");
const contextOptions = cliOptions.device ? import_playwright_core.devices[cliOptions.device] : {};
if (cliOptions.storageState)
contextOptions.storageState = cliOptions.storageState;
if (cliOptions.userAgent)
contextOptions.userAgent = cliOptions.userAgent;
if (cliOptions.viewportSize)
contextOptions.viewport = cliOptions.viewportSize;
if (cliOptions.ignoreHttpsErrors)
contextOptions.ignoreHTTPSErrors = true;
if (cliOptions.blockServiceWorkers)
contextOptions.serviceWorkers = "block";
if (cliOptions.grantPermissions)
contextOptions.permissions = cliOptions.grantPermissions;
const result = {
browser: {
browserName,
isolated: cliOptions.isolated,
userDataDir: cliOptions.userDataDir,
launchOptions,
contextOptions,
cdpEndpoint: cliOptions.cdpEndpoint,
cdpHeaders: cliOptions.cdpHeader,
initPage: cliOptions.initPage,
initScript: cliOptions.initScript
},
server: {
port: cliOptions.port,
host: cliOptions.host,
allowedHosts: cliOptions.allowedHosts
},
capabilities: cliOptions.caps,
console: {
level: cliOptions.consoleLevel
},
network: {
allowedOrigins: cliOptions.allowedOrigins,
blockedOrigins: cliOptions.blockedOrigins
},
allowUnrestrictedFileAccess: cliOptions.allowUnrestrictedFileAccess,
codegen: cliOptions.codegen,
saveSession: cliOptions.saveSession,
saveTrace: cliOptions.saveTrace,
saveVideo: cliOptions.saveVideo,
secrets: cliOptions.secrets,
sharedBrowserContext: cliOptions.sharedBrowserContext,
snapshot: cliOptions.snapshotMode ? { mode: cliOptions.snapshotMode } : void 0,
outputMode: cliOptions.outputMode,
outputDir: cliOptions.outputDir,
imageResponses: cliOptions.imageResponses,
testIdAttribute: cliOptions.testIdAttribute,
timeouts: {
action: cliOptions.timeoutAction,
navigation: cliOptions.timeoutNavigation
}
};
return result;
}
function configFromEnv() {
const options = {};
options.allowedHosts = commaSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_HOSTNAMES);
options.allowedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_ORIGINS);
options.allowUnrestrictedFileAccess = envToBoolean(process.env.PLAYWRIGHT_MCP_ALLOW_UNRESTRICTED_FILE_ACCESS);
options.blockedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_BLOCKED_ORIGINS);
options.blockServiceWorkers = envToBoolean(process.env.PLAYWRIGHT_MCP_BLOCK_SERVICE_WORKERS);
options.browser = envToString(process.env.PLAYWRIGHT_MCP_BROWSER);
options.caps = commaSeparatedList(process.env.PLAYWRIGHT_MCP_CAPS);
options.cdpEndpoint = envToString(process.env.PLAYWRIGHT_MCP_CDP_ENDPOINT);
options.cdpHeader = headerParser(process.env.PLAYWRIGHT_MCP_CDP_HEADERS, {});
options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);
if (process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL)
options.consoleLevel = enumParser("--console-level", ["error", "warning", "info", "debug"], process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL);
options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);
options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);
options.grantPermissions = commaSeparatedList(process.env.PLAYWRIGHT_MCP_GRANT_PERMISSIONS);
options.headless = envToBoolean(process.env.PLAYWRIGHT_MCP_HEADLESS);
options.host = envToString(process.env.PLAYWRIGHT_MCP_HOST);
options.ignoreHttpsErrors = envToBoolean(process.env.PLAYWRIGHT_MCP_IGNORE_HTTPS_ERRORS);
const initPage = envToString(process.env.PLAYWRIGHT_MCP_INIT_PAGE);
if (initPage)
options.initPage = [initPage];
const initScript = envToString(process.env.PLAYWRIGHT_MCP_INIT_SCRIPT);
if (initScript)
options.initScript = [initScript];
options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);
if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES)
options.imageResponses = enumParser("--image-responses", ["allow", "omit"], process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES);
options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);
options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);
options.port = numberParser(process.env.PLAYWRIGHT_MCP_PORT);
options.proxyBypass = envToString(process.env.PLAYWRIGHT_MCP_PROXY_BYPASS);
options.proxyServer = envToString(process.env.PLAYWRIGHT_MCP_PROXY_SERVER);
options.saveTrace = envToBoolean(process.env.PLAYWRIGHT_MCP_SAVE_TRACE);
options.saveVideo = resolutionParser("--save-video", process.env.PLAYWRIGHT_MCP_SAVE_VIDEO);
options.secrets = dotenvFileLoader(process.env.PLAYWRIGHT_MCP_SECRETS_FILE);
options.storageState = envToString(process.env.PLAYWRIGHT_MCP_STORAGE_STATE);
options.testIdAttribute = envToString(process.env.PLAYWRIGHT_MCP_TEST_ID_ATTRIBUTE);
options.timeoutAction = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_ACTION);
options.timeoutNavigation = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_NAVIGATION);
options.userAgent = envToString(process.env.PLAYWRIGHT_MCP_USER_AGENT);
options.userDataDir = envToString(process.env.PLAYWRIGHT_MCP_USER_DATA_DIR);
options.viewportSize = resolutionParser("--viewport-size", process.env.PLAYWRIGHT_MCP_VIEWPORT_SIZE);
return configFromCLIOptions(options);
}
async function loadConfig(configFile) {
if (!configFile)
return {};
try {
return JSON.parse(await import_fs.default.promises.readFile(configFile, "utf8"));
} catch (error) {
throw new Error(`Failed to load config file: ${configFile}, ${error}`);
}
}
function tmpDir() {
return import_path.default.join(process.env.PW_TMPDIR_FOR_TEST ?? import_os.default.tmpdir(), "playwright-mcp-output");
}
function outputDir(config, clientInfo) {
const rootPath = (0, import_server.firstRootPath)(clientInfo);
return config.outputDir ?? (rootPath ? import_path.default.join(rootPath, ".playwright-mcp") : void 0) ?? import_path.default.join(tmpDir(), String(clientInfo.timestamp));
}
async function outputFile(config, clientInfo, fileName, options) {
const file = await resolveFile(config, clientInfo, fileName, options);
await import_fs.default.promises.mkdir(import_path.default.dirname(file), { recursive: true });
(0, import_utilsBundle.debug)("pw:mcp:file")(options.title, file);
return file;
}
async function resolveFile(config, clientInfo, fileName, options) {
const dir = outputDir(config, clientInfo);
if (options.origin === "code")
return import_path.default.resolve(dir, fileName);
if (options.origin === "llm") {
fileName = fileName.split("\\").join("/");
const resolvedFile = import_path.default.resolve(dir, fileName);
if (!resolvedFile.startsWith(import_path.default.resolve(dir) + import_path.default.sep))
throw new Error(`Resolved file path ${resolvedFile} is outside of the output directory ${dir}. Use relative file names to stay within the output directory.`);
return resolvedFile;
}
return import_path.default.join(dir, sanitizeForFilePath(fileName));
}
function pickDefined(obj) {
return Object.fromEntries(
Object.entries(obj ?? {}).filter(([_, v]) => v !== void 0)
);
}
function mergeConfig(base, overrides) {
const browser = {
...pickDefined(base.browser),
...pickDefined(overrides.browser),
browserName: overrides.browser?.browserName ?? base.browser?.browserName ?? "chromium",
isolated: overrides.browser?.isolated ?? base.browser?.isolated ?? false,
launchOptions: {
...pickDefined(base.browser?.launchOptions),
...pickDefined(overrides.browser?.launchOptions),
...{ assistantMode: true }
},
contextOptions: {
...pickDefined(base.browser?.contextOptions),
...pickDefined(overrides.browser?.contextOptions)
}
};
if (browser.browserName !== "chromium" && browser.launchOptions)
delete browser.launchOptions.channel;
return {
...pickDefined(base),
...pickDefined(overrides),
browser,
console: {
...pickDefined(base.console),
...pickDefined(overrides.console)
},
network: {
...pickDefined(base.network),
...pickDefined(overrides.network)
},
server: {
...pickDefined(base.server),
...pickDefined(overrides.server)
},
snapshot: {
...pickDefined(base.snapshot),
...pickDefined(overrides.snapshot)
},
timeouts: {
...pickDefined(base.timeouts),
...pickDefined(overrides.timeouts)
}
};
}
function semicolonSeparatedList(value) {
if (!value)
return void 0;
return value.split(";").map((v) => v.trim());
}
function commaSeparatedList(value) {
if (!value)
return void 0;
return value.split(",").map((v) => v.trim());
}
function dotenvFileLoader(value) {
if (!value)
return void 0;
return import_utilsBundle.dotenv.parse(import_fs.default.readFileSync(value, "utf8"));
}
function numberParser(value) {
if (!value)
return void 0;
return +value;
}
function resolutionParser(name, value) {
if (!value)
return void 0;
if (value.includes("x")) {
const [width, height] = value.split("x").map((v) => +v);
if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)
throw new Error(`Invalid resolution format: use ${name}="800x600"`);
return { width, height };
}
if (value.includes(",")) {
const [width, height] = value.split(",").map((v) => +v);
if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)
throw new Error(`Invalid resolution format: use ${name}="800x600"`);
return { width, height };
}
throw new Error(`Invalid resolution format: use ${name}="800x600"`);
}
function headerParser(arg, previous) {
if (!arg)
return previous || {};
const result = previous || {};
const [name, value] = arg.split(":").map((v) => v.trim());
result[name] = value;
return result;
}
function enumParser(name, options, value) {
if (!options.includes(value))
throw new Error(`Invalid ${name}: ${value}. Valid values are: ${options.join(", ")}`);
return value;
}
function envToBoolean(value) {
if (value === "true" || value === "1")
return true;
if (value === "false" || value === "0")
return false;
return void 0;
}
function envToString(value) {
return value ? value.trim() : void 0;
}
function sanitizeForFilePath(s) {
const sanitize = (s2) => s2.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
const separator = s.lastIndexOf(".");
if (separator === -1)
return sanitize(s);
return sanitize(s.substring(0, separator)) + "." + sanitize(s.substring(separator + 1));
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
commaSeparatedList,
configFromCLIOptions,
defaultConfig,
dotenvFileLoader,
enumParser,
headerParser,
numberParser,
outputDir,
outputFile,
resolutionParser,
resolveCLIConfig,
resolveConfig,
semicolonSeparatedList
});

View file

@ -0,0 +1,244 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var context_exports = {};
__export(context_exports, {
Context: () => Context
});
module.exports = __toCommonJS(context_exports);
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_utils = require("playwright-core/lib/utils");
var import_playwright_core = require("playwright-core");
var import_url = require("url");
var import_os = __toESM(require("os"));
var import_log = require("../log");
var import_tab = require("./tab");
var import_config = require("./config");
const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
class Context {
constructor(options) {
this._tabs = [];
this._abortController = new AbortController();
this.config = options.config;
this.sessionLog = options.sessionLog;
this.options = options;
this._browserContextFactory = options.browserContextFactory;
this._clientInfo = options.clientInfo;
testDebug("create context");
Context._allContexts.add(this);
}
static {
this._allContexts = /* @__PURE__ */ new Set();
}
static async disposeAll() {
await Promise.all([...Context._allContexts].map((context) => context.dispose()));
}
tabs() {
return this._tabs;
}
currentTab() {
return this._currentTab;
}
currentTabOrDie() {
if (!this._currentTab)
throw new Error("No open pages available.");
return this._currentTab;
}
async newTab() {
const { browserContext } = await this._ensureBrowserContext({});
const page = await browserContext.newPage();
this._currentTab = this._tabs.find((t) => t.page === page);
return this._currentTab;
}
async selectTab(index) {
const tab = this._tabs[index];
if (!tab)
throw new Error(`Tab ${index} not found`);
await tab.page.bringToFront();
this._currentTab = tab;
return tab;
}
async ensureTab(options = {}) {
const { browserContext } = await this._ensureBrowserContext(options);
if (!this._currentTab)
await browserContext.newPage();
return this._currentTab;
}
async closeTab(index) {
const tab = index === void 0 ? this._currentTab : this._tabs[index];
if (!tab)
throw new Error(`Tab ${index} not found`);
const url = tab.page.url();
await tab.page.close();
return url;
}
async outputFile(fileName, options) {
return (0, import_config.outputFile)(this.config, this._clientInfo, fileName, options);
}
_onPageCreated(page) {
const tab = new import_tab.Tab(this, page, (tab2) => this._onPageClosed(tab2));
this._tabs.push(tab);
if (!this._currentTab)
this._currentTab = tab;
}
_onPageClosed(tab) {
const index = this._tabs.indexOf(tab);
if (index === -1)
return;
this._tabs.splice(index, 1);
if (this._currentTab === tab)
this._currentTab = this._tabs[Math.min(index, this._tabs.length - 1)];
if (!this._tabs.length)
void this.closeBrowserContext();
}
async closeBrowserContext() {
if (!this._closeBrowserContextPromise)
this._closeBrowserContextPromise = this._closeBrowserContextImpl().catch(import_log.logUnhandledError);
await this._closeBrowserContextPromise;
this._closeBrowserContextPromise = void 0;
}
isRunningTool() {
return this._runningToolName !== void 0;
}
setRunningTool(name) {
this._runningToolName = name;
}
async _closeBrowserContextImpl() {
if (!this._browserContextPromise)
return;
testDebug("close context");
const promise = this._browserContextPromise;
this._browserContextPromise = void 0;
this._browserContextOption = void 0;
await promise.then(async ({ browserContext, close }) => {
if (this.config.saveTrace)
await browserContext.tracing.stop();
await close();
});
}
async dispose() {
this._abortController.abort("MCP context disposed");
await this.closeBrowserContext();
Context._allContexts.delete(this);
}
async _setupRequestInterception(context) {
if (this.config.network?.allowedOrigins?.length) {
await context.route("**", (route) => route.abort("blockedbyclient"));
for (const origin of this.config.network.allowedOrigins)
await context.route(originOrHostGlob(origin), (route) => route.continue());
}
if (this.config.network?.blockedOrigins?.length) {
for (const origin of this.config.network.blockedOrigins)
await context.route(originOrHostGlob(origin), (route) => route.abort("blockedbyclient"));
}
}
async ensureBrowserContext(options = {}) {
const { browserContext } = await this._ensureBrowserContext(options);
return browserContext;
}
_ensureBrowserContext(options) {
if (this._browserContextPromise && (options.forceHeadless === void 0 || this._browserContextOption?.forceHeadless === options.forceHeadless))
return this._browserContextPromise;
const closePrework = this._browserContextPromise ? this.closeBrowserContext() : Promise.resolve();
this._browserContextPromise = closePrework.then(() => this._setupBrowserContext(options));
this._browserContextPromise.catch(() => {
this._browserContextPromise = void 0;
this._browserContextOption = void 0;
});
this._browserContextOption = options;
return this._browserContextPromise;
}
async _setupBrowserContext(options) {
if (this._closeBrowserContextPromise)
throw new Error("Another browser context is being closed.");
if (this.config.testIdAttribute)
import_playwright_core.selectors.setTestIdAttribute(this.config.testIdAttribute);
const result = await this._browserContextFactory.createContext(this._clientInfo, this._abortController.signal, { toolName: this._runningToolName, ...options });
const { browserContext } = result;
if (!this.config.allowUnrestrictedFileAccess) {
browserContext._setAllowedProtocols(["http:", "https:", "about:", "data:"]);
browserContext._setAllowedDirectories(allRootPaths(this._clientInfo));
}
await this._setupRequestInterception(browserContext);
for (const page of browserContext.pages())
this._onPageCreated(page);
browserContext.on("page", (page) => this._onPageCreated(page));
if (this.config.saveTrace) {
await browserContext.tracing.start({
name: "trace-" + Date.now(),
screenshots: true,
snapshots: true,
_live: true
});
}
return result;
}
lookupSecret(secretName) {
if (!this.config.secrets?.[secretName])
return { value: secretName, code: (0, import_utils.escapeWithQuotes)(secretName, "'") };
return {
value: this.config.secrets[secretName],
code: `process.env['${secretName}']`
};
}
firstRootPath() {
return allRootPaths(this._clientInfo)[0];
}
}
function allRootPaths(clientInfo) {
const paths = [];
for (const root of clientInfo.roots) {
const url = new URL(root.uri);
let rootPath;
try {
rootPath = (0, import_url.fileURLToPath)(url);
} catch (e) {
if (e.code === "ERR_INVALID_FILE_URL_PATH" && import_os.default.platform() === "win32")
rootPath = decodeURIComponent(url.pathname);
}
if (!rootPath)
continue;
paths.push(rootPath);
}
if (paths.length === 0)
paths.push(process.cwd());
return paths;
}
function originOrHostGlob(originOrHost) {
try {
const url = new URL(originOrHost);
if (url.origin !== "null")
return `${url.origin}/**`;
} catch {
}
return `*://${originOrHost}/**`;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Context
});

View file

@ -0,0 +1,278 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var response_exports = {};
__export(response_exports, {
Response: () => Response,
parseResponse: () => parseResponse,
renderTabMarkdown: () => renderTabMarkdown,
renderTabsMarkdown: () => renderTabsMarkdown,
requestDebug: () => requestDebug
});
module.exports = __toCommonJS(response_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_tab = require("./tab");
var import_utils = require("./tools/utils");
const requestDebug = (0, import_utilsBundle.debug)("pw:mcp:request");
class Response {
constructor(ordinal, context, toolName, toolArgs) {
this._results = [];
this._errors = [];
this._code = [];
this._images = [];
this._includeSnapshot = "none";
this._ordinal = ordinal;
this._context = context;
this.toolName = toolName;
this.toolArgs = toolArgs;
}
static {
this._ordinal = 0;
}
static create(context, toolName, toolArgs) {
return new Response(++Response._ordinal, context, toolName, toolArgs);
}
addTextResult(result) {
this._results.push({ text: result });
}
async addResult(result) {
if (result.data && !result.suggestedFilename)
result.suggestedFilename = (0, import_utils.dateAsFileName)(result.ext ?? "bin");
if (this._context.config.outputMode === "file") {
if (!result.suggestedFilename)
result.suggestedFilename = (0, import_utils.dateAsFileName)(result.ext ?? (result.text ? "txt" : "bin"));
}
const entry = { text: result.text, data: result.data, title: result.title };
if (result.suggestedFilename)
entry.filename = await this._context.outputFile(result.suggestedFilename, { origin: "llm", title: result.title ?? "Saved result" });
this._results.push(entry);
return { fileName: entry.filename };
}
addError(error) {
this._errors.push(error);
}
addCode(code) {
this._code.push(code);
}
addImage(image) {
this._images.push(image);
}
setIncludeSnapshot() {
this._includeSnapshot = this._context.config.snapshot.mode;
}
setIncludeFullSnapshot(includeSnapshotFileName) {
this._includeSnapshot = "full";
this._includeSnapshotFileName = includeSnapshotFileName;
}
async build() {
const rootPath = this._context.firstRootPath();
const sections = [];
const addSection = (title) => {
const section = { title, content: [] };
sections.push(section);
return section.content;
};
if (this._errors.length) {
const text = addSection("Error");
text.push("### Error");
text.push(this._errors.join("\n"));
}
if (this._results.length) {
const text = addSection("Result");
for (const result of this._results) {
if (result.filename) {
text.push(`- [${result.title}](${rootPath ? import_path.default.relative(rootPath, result.filename) : result.filename})`);
if (result.data)
await import_fs.default.promises.writeFile(result.filename, result.data);
else if (result.text)
await import_fs.default.promises.writeFile(result.filename, this._redactText(result.text));
} else if (result.text) {
text.push(result.text);
}
}
}
if (this._context.config.codegen !== "none" && this._code.length) {
const text = addSection("Ran Playwright code");
text.push(...this._code);
}
const tabSnapshot = this._context.currentTab() ? await this._context.currentTabOrDie().captureSnapshot() : void 0;
const tabHeaders = await Promise.all(this._context.tabs().map((tab) => tab.headerSnapshot()));
if (tabHeaders.some((header) => header.changed)) {
if (tabHeaders.length !== 1) {
const text2 = addSection("Open tabs");
text2.push(...renderTabsMarkdown(tabHeaders));
}
const text = addSection("Page");
text.push(...renderTabMarkdown(tabHeaders[0]));
}
if (tabSnapshot?.modalStates.length) {
const text = addSection("Modal state");
text.push(...(0, import_tab.renderModalStates)(tabSnapshot.modalStates));
}
if (tabSnapshot && this._includeSnapshot === "full") {
let fileName;
if (this._includeSnapshotFileName)
fileName = await this._context.outputFile(this._includeSnapshotFileName, { origin: "llm", title: "Saved snapshot" });
else if (this._context.config.outputMode === "file")
fileName = await this._context.outputFile(`snapshot-${this._ordinal}.yml`, { origin: "code", title: "Saved snapshot" });
if (fileName) {
await import_fs.default.promises.writeFile(fileName, tabSnapshot.ariaSnapshot);
const text = addSection("Snapshot");
text.push(`- File: ${rootPath ? import_path.default.relative(rootPath, fileName) : fileName}`);
} else {
const text = addSection("Snapshot");
text.push("```yaml");
text.push(tabSnapshot.ariaSnapshot);
text.push("```");
}
}
if (tabSnapshot && this._includeSnapshot === "incremental") {
const text = addSection("Snapshot");
text.push("```yaml");
if (tabSnapshot.ariaSnapshotDiff !== void 0)
text.push(tabSnapshot.ariaSnapshotDiff);
else
text.push(tabSnapshot.ariaSnapshot);
text.push("```");
}
if (tabSnapshot?.events.filter((event) => event.type !== "request").length) {
const text = addSection("Events");
for (const event of tabSnapshot.events) {
if (event.type === "console") {
if ((0, import_tab.shouldIncludeMessage)(this._context.config.console.level, event.message.type))
text.push(`- ${trimMiddle(event.message.toString(), 100)}`);
} else if (event.type === "download-start") {
text.push(`- Downloading file ${event.download.download.suggestedFilename()} ...`);
} else if (event.type === "download-finish") {
text.push(`- Downloaded file ${event.download.download.suggestedFilename()} to "${rootPath ? import_path.default.relative(rootPath, event.download.outputFile) : event.download.outputFile}"`);
}
}
}
const allText = sections.flatMap((section) => {
const content2 = [];
content2.push(`### ${section.title}`);
content2.push(...section.content);
content2.push("");
return content2;
}).join("\n");
const content = [
{
type: "text",
text: this._redactText(allText)
}
];
if (this._context.config.imageResponses !== "omit") {
for (const image of this._images)
content.push({ type: "image", data: image.data.toString("base64"), mimeType: image.contentType });
}
return {
content,
...this._errors.length > 0 ? { isError: true } : {}
};
}
_redactText(text) {
for (const [secretName, secretValue] of Object.entries(this._context.config.secrets ?? {}))
text = text.replaceAll(secretValue, `<secret>${secretName}</secret>`);
return text;
}
}
function renderTabMarkdown(tab) {
const lines = [`- Page URL: ${tab.url}`];
if (tab.title)
lines.push(`- Page Title: ${tab.title}`);
return lines;
}
function renderTabsMarkdown(tabs) {
if (!tabs.length)
return ['No open tabs. Use the "browser_navigate" tool to navigate to a page first.'];
const lines = [];
for (let i = 0; i < tabs.length; i++) {
const tab = tabs[i];
const current = tab.current ? " (current)" : "";
lines.push(`- ${i}:${current} [${tab.title}](${tab.url})`);
}
return lines;
}
function trimMiddle(text, maxLength) {
if (text.length <= maxLength)
return text;
return text.slice(0, Math.floor(maxLength / 2)) + "..." + text.slice(-3 - Math.floor(maxLength / 2));
}
function parseSections(text) {
const sections = /* @__PURE__ */ new Map();
const sectionHeaders = text.split(/^### /m).slice(1);
for (const section of sectionHeaders) {
const firstNewlineIndex = section.indexOf("\n");
if (firstNewlineIndex === -1)
continue;
const sectionName = section.substring(0, firstNewlineIndex);
const sectionContent = section.substring(firstNewlineIndex + 1).trim();
sections.set(sectionName, sectionContent);
}
return sections;
}
function parseResponse(response) {
if (response.content?.[0].type !== "text")
return void 0;
const text = response.content[0].text;
const sections = parseSections(text);
const error = sections.get("Error");
const result = sections.get("Result");
const code = sections.get("Ran Playwright code");
const tabs = sections.get("Open tabs");
const page = sections.get("Page");
const snapshot = sections.get("Snapshot");
const events = sections.get("Events");
const modalState = sections.get("Modal state");
const codeNoFrame = code?.replace(/^```js\n/, "").replace(/\n```$/, "");
const isError = response.isError;
const attachments = response.content.length > 1 ? response.content.slice(1) : void 0;
return {
result,
error,
code: codeNoFrame,
tabs,
page,
snapshot,
events,
modalState,
isError,
attachments,
text
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Response,
parseResponse,
renderTabMarkdown,
renderTabsMarkdown,
requestDebug
});

View file

@ -0,0 +1,75 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var sessionLog_exports = {};
__export(sessionLog_exports, {
SessionLog: () => SessionLog
});
module.exports = __toCommonJS(sessionLog_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_config = require("./config");
var import_response = require("./response");
class SessionLog {
constructor(sessionFolder) {
this._sessionFileQueue = Promise.resolve();
this._folder = sessionFolder;
this._file = import_path.default.join(this._folder, "session.md");
}
static async create(config, clientInfo) {
const sessionFolder = await (0, import_config.outputFile)(config, clientInfo, `session-${Date.now()}`, { origin: "code", title: "Saving session" });
await import_fs.default.promises.mkdir(sessionFolder, { recursive: true });
console.error(`Session: ${sessionFolder}`);
return new SessionLog(sessionFolder);
}
logResponse(toolName, toolArgs, responseObject) {
const parsed = (0, import_response.parseResponse)(responseObject);
if (parsed)
delete parsed.text;
const lines = [""];
lines.push(
`### Tool call: ${toolName}`,
`- Args`,
"```json",
JSON.stringify(toolArgs, null, 2),
"```"
);
if (parsed) {
lines.push(`- Result`);
lines.push("```json");
lines.push(JSON.stringify(parsed, null, 2));
lines.push("```");
}
lines.push("");
this._sessionFileQueue = this._sessionFileQueue.then(() => import_fs.default.promises.appendFile(this._file, lines.join("\n")));
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SessionLog
});

343
backend/node_modules/playwright/lib/mcp/browser/tab.js generated vendored Normal file
View file

@ -0,0 +1,343 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tab_exports = {};
__export(tab_exports, {
Tab: () => Tab,
TabEvents: () => TabEvents,
renderModalStates: () => renderModalStates,
shouldIncludeMessage: () => shouldIncludeMessage
});
module.exports = __toCommonJS(tab_exports);
var import_events = require("events");
var import_utils = require("playwright-core/lib/utils");
var import_utils2 = require("./tools/utils");
var import_log = require("../log");
var import_dialogs = require("./tools/dialogs");
var import_files = require("./tools/files");
var import_transform = require("../../transform/transform");
const TabEvents = {
modalState: "modalState"
};
class Tab extends import_events.EventEmitter {
constructor(context, page, onPageClose) {
super();
this._lastHeader = { title: "about:blank", url: "about:blank", current: false };
this._consoleMessages = [];
this._downloads = [];
this._requests = /* @__PURE__ */ new Set();
this._modalStates = [];
this._needsFullSnapshot = false;
this._eventEntries = [];
this._recentEventEntries = [];
this.context = context;
this.page = page;
this._onPageClose = onPageClose;
page.on("console", (event) => this._handleConsoleMessage(messageToConsoleMessage(event)));
page.on("pageerror", (error) => this._handleConsoleMessage(pageErrorToConsoleMessage(error)));
page.on("request", (request) => this._handleRequest(request));
page.on("close", () => this._onClose());
page.on("filechooser", (chooser) => {
this.setModalState({
type: "fileChooser",
description: "File chooser",
fileChooser: chooser,
clearedBy: import_files.uploadFile.schema.name
});
});
page.on("dialog", (dialog) => this._dialogShown(dialog));
page.on("download", (download) => {
void this._downloadStarted(download);
});
page.setDefaultNavigationTimeout(this.context.config.timeouts.navigation);
page.setDefaultTimeout(this.context.config.timeouts.action);
page[tabSymbol] = this;
this._initializedPromise = this._initialize();
}
static forPage(page) {
return page[tabSymbol];
}
static async collectConsoleMessages(page) {
const result = [];
const messages = await page.consoleMessages().catch(() => []);
for (const message of messages)
result.push(messageToConsoleMessage(message));
const errors = await page.pageErrors().catch(() => []);
for (const error of errors)
result.push(pageErrorToConsoleMessage(error));
return result;
}
async _initialize() {
for (const message of await Tab.collectConsoleMessages(this.page))
this._handleConsoleMessage(message);
const requests = await this.page.requests().catch(() => []);
for (const request of requests)
this._requests.add(request);
for (const initPage of this.context.config.browser.initPage || []) {
try {
const { default: func } = await (0, import_transform.requireOrImport)(initPage);
await func({ page: this.page });
} catch (e) {
(0, import_log.logUnhandledError)(e);
}
}
}
modalStates() {
return this._modalStates;
}
setModalState(modalState) {
this._modalStates.push(modalState);
this.emit(TabEvents.modalState, modalState);
}
clearModalState(modalState) {
this._modalStates = this._modalStates.filter((state) => state !== modalState);
}
_dialogShown(dialog) {
this.setModalState({
type: "dialog",
description: `"${dialog.type()}" dialog with message "${dialog.message()}"`,
dialog,
clearedBy: import_dialogs.handleDialog.schema.name
});
}
async _downloadStarted(download) {
const entry = {
download,
finished: false,
outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web", title: "Saving download" })
};
this._downloads.push(entry);
this._addLogEntry({ type: "download-start", wallTime: Date.now(), download: entry });
await download.saveAs(entry.outputFile);
entry.finished = true;
this._addLogEntry({ type: "download-finish", wallTime: Date.now(), download: entry });
}
_clearCollectedArtifacts() {
this._consoleMessages.length = 0;
this._downloads.length = 0;
this._requests.clear();
this._eventEntries.length = 0;
this._recentEventEntries.length = 0;
}
_handleRequest(request) {
this._requests.add(request);
this._addLogEntry({ type: "request", wallTime: Date.now(), request });
}
_handleConsoleMessage(message) {
this._consoleMessages.push(message);
this._addLogEntry({ type: "console", wallTime: Date.now(), message });
}
_addLogEntry(entry) {
this._eventEntries.push(entry);
this._recentEventEntries.push(entry);
}
_onClose() {
this._clearCollectedArtifacts();
this._onPageClose(this);
}
async headerSnapshot() {
let title;
await this._raceAgainstModalStates(async () => {
title = await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.title());
});
if (this._lastHeader.title !== title || this._lastHeader.url !== this.page.url() || this._lastHeader.current !== this.isCurrentTab()) {
this._lastHeader = { title: title ?? "", url: this.page.url(), current: this.isCurrentTab() };
return { ...this._lastHeader, changed: true };
}
return { ...this._lastHeader, changed: false };
}
isCurrentTab() {
return this === this.context.currentTab();
}
async waitForLoadState(state, options) {
await this._initializedPromise;
await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.waitForLoadState(state, options).catch(import_log.logUnhandledError));
}
async navigate(url) {
await this._initializedPromise;
this._clearCollectedArtifacts();
const { promise: downloadEvent, abort: abortDownloadEvent } = (0, import_utils2.eventWaiter)(this.page, "download", 3e3);
try {
await this.page.goto(url, { waitUntil: "domcontentloaded" });
abortDownloadEvent();
} catch (_e) {
const e = _e;
const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
if (!mightBeDownload)
throw e;
const download = await downloadEvent;
if (!download)
throw e;
await new Promise((resolve) => setTimeout(resolve, 500));
return;
}
await this.waitForLoadState("load", { timeout: 5e3 });
}
async consoleMessages(level) {
await this._initializedPromise;
return this._consoleMessages.filter((message) => shouldIncludeMessage(level, message.type));
}
async requests() {
await this._initializedPromise;
return this._requests;
}
async captureSnapshot() {
await this._initializedPromise;
let tabSnapshot;
const modalStates = await this._raceAgainstModalStates(async () => {
const snapshot = await this.page._snapshotForAI({ track: "response" });
tabSnapshot = {
ariaSnapshot: snapshot.full,
ariaSnapshotDiff: this._needsFullSnapshot ? void 0 : snapshot.incremental,
modalStates: [],
events: []
};
});
if (tabSnapshot) {
tabSnapshot.events = this._recentEventEntries;
this._recentEventEntries = [];
}
this._needsFullSnapshot = !tabSnapshot;
return tabSnapshot ?? {
ariaSnapshot: "",
ariaSnapshotDiff: "",
modalStates,
events: []
};
}
_javaScriptBlocked() {
return this._modalStates.some((state) => state.type === "dialog");
}
async _raceAgainstModalStates(action) {
if (this.modalStates().length)
return this.modalStates();
const promise = new import_utils.ManualPromise();
const listener = (modalState) => promise.resolve([modalState]);
this.once(TabEvents.modalState, listener);
return await Promise.race([
action().then(() => {
this.off(TabEvents.modalState, listener);
return [];
}),
promise
]);
}
async waitForCompletion(callback) {
await this._initializedPromise;
await this._raceAgainstModalStates(() => (0, import_utils2.waitForCompletion)(this, callback));
}
async refLocator(params) {
await this._initializedPromise;
return (await this.refLocators([params]))[0];
}
async refLocators(params) {
await this._initializedPromise;
return Promise.all(params.map(async (param) => {
try {
let locator = this.page.locator(`aria-ref=${param.ref}`);
if (param.element)
locator = locator.describe(param.element);
const { resolvedSelector } = await locator._resolveSelector();
return { locator, resolved: (0, import_utils.asLocator)("javascript", resolvedSelector) };
} catch (e) {
throw new Error(`Ref ${param.ref} not found in the current page snapshot. Try capturing new snapshot.`);
}
}));
}
async waitForTimeout(time) {
if (this._javaScriptBlocked()) {
await new Promise((f) => setTimeout(f, time));
return;
}
await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => {
return page.evaluate(() => new Promise((f) => setTimeout(f, 1e3))).catch(() => {
});
});
}
}
function messageToConsoleMessage(message) {
return {
type: message.type(),
text: message.text(),
toString: () => `[${message.type().toUpperCase()}] ${message.text()} @ ${message.location().url}:${message.location().lineNumber}`
};
}
function pageErrorToConsoleMessage(errorOrValue) {
if (errorOrValue instanceof Error) {
return {
type: "error",
text: errorOrValue.message,
toString: () => errorOrValue.stack || errorOrValue.message
};
}
return {
type: "error",
text: String(errorOrValue),
toString: () => String(errorOrValue)
};
}
function renderModalStates(modalStates) {
const result = [];
if (modalStates.length === 0)
result.push("- There is no modal state present");
for (const state of modalStates)
result.push(`- [${state.description}]: can be handled by the "${state.clearedBy}" tool`);
return result;
}
const consoleMessageLevels = ["error", "warning", "info", "debug"];
function shouldIncludeMessage(thresholdLevel, type) {
const messageLevel = consoleLevelForMessageType(type);
return consoleMessageLevels.indexOf(messageLevel) <= consoleMessageLevels.indexOf(thresholdLevel);
}
function consoleLevelForMessageType(type) {
switch (type) {
case "assert":
case "error":
return "error";
case "warning":
return "warning";
case "count":
case "dir":
case "dirxml":
case "info":
case "log":
case "table":
case "time":
case "timeEnd":
return "info";
case "clear":
case "debug":
case "endGroup":
case "profile":
case "profileEnd":
case "startGroup":
case "startGroupCollapsed":
case "trace":
return "debug";
default:
return "info";
}
}
const tabSymbol = Symbol("tabSymbol");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Tab,
TabEvents,
renderModalStates,
shouldIncludeMessage
});

View file

@ -0,0 +1,84 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tools_exports = {};
__export(tools_exports, {
browserTools: () => browserTools,
filteredTools: () => filteredTools
});
module.exports = __toCommonJS(tools_exports);
var import_common = __toESM(require("./tools/common"));
var import_console = __toESM(require("./tools/console"));
var import_dialogs = __toESM(require("./tools/dialogs"));
var import_evaluate = __toESM(require("./tools/evaluate"));
var import_files = __toESM(require("./tools/files"));
var import_form = __toESM(require("./tools/form"));
var import_install = __toESM(require("./tools/install"));
var import_keyboard = __toESM(require("./tools/keyboard"));
var import_mouse = __toESM(require("./tools/mouse"));
var import_navigate = __toESM(require("./tools/navigate"));
var import_network = __toESM(require("./tools/network"));
var import_open = __toESM(require("./tools/open"));
var import_pdf = __toESM(require("./tools/pdf"));
var import_runCode = __toESM(require("./tools/runCode"));
var import_snapshot = __toESM(require("./tools/snapshot"));
var import_screenshot = __toESM(require("./tools/screenshot"));
var import_tabs = __toESM(require("./tools/tabs"));
var import_tracing = __toESM(require("./tools/tracing"));
var import_wait = __toESM(require("./tools/wait"));
var import_verify = __toESM(require("./tools/verify"));
const browserTools = [
...import_common.default,
...import_console.default,
...import_dialogs.default,
...import_evaluate.default,
...import_files.default,
...import_form.default,
...import_install.default,
...import_keyboard.default,
...import_mouse.default,
...import_navigate.default,
...import_network.default,
...import_open.default,
...import_pdf.default,
...import_runCode.default,
...import_screenshot.default,
...import_snapshot.default,
...import_tabs.default,
...import_tracing.default,
...import_wait.default,
...import_verify.default
];
function filteredTools(config) {
return browserTools.filter((tool) => tool.capability.startsWith("core") || config.capabilities?.includes(tool.capability));
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
browserTools,
filteredTools
});

View file

@ -0,0 +1,65 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var common_exports = {};
__export(common_exports, {
default: () => common_default
});
module.exports = __toCommonJS(common_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_response = require("../response");
const close = (0, import_tool.defineTool)({
capability: "core",
schema: {
name: "browser_close",
title: "Close browser",
description: "Close the page",
inputSchema: import_mcpBundle.z.object({}),
type: "action"
},
handle: async (context, params, response) => {
await context.closeBrowserContext();
const result = (0, import_response.renderTabsMarkdown)([]);
response.addTextResult(result.join("\n"));
response.addCode(`await page.close()`);
}
});
const resize = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_resize",
title: "Resize browser window",
description: "Resize the browser window",
inputSchema: import_mcpBundle.z.object({
width: import_mcpBundle.z.number().describe("Width of the browser window"),
height: import_mcpBundle.z.number().describe("Height of the browser window")
}),
type: "action"
},
handle: async (tab, params, response) => {
response.addCode(`await page.setViewportSize({ width: ${params.width}, height: ${params.height} });`);
await tab.waitForCompletion(async () => {
await tab.page.setViewportSize({ width: params.width, height: params.height });
});
}
});
var common_default = [
close,
resize
];

View file

@ -0,0 +1,46 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var console_exports = {};
__export(console_exports, {
default: () => console_default
});
module.exports = __toCommonJS(console_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const console = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_console_messages",
title: "Get console messages",
description: "Returns all console messages",
inputSchema: import_mcpBundle.z.object({
level: import_mcpBundle.z.enum(["error", "warning", "info", "debug"]).default("info").describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".'),
filename: import_mcpBundle.z.string().optional().describe("Filename to save the console messages to. If not provided, messages are returned as text.")
}),
type: "readOnly"
},
handle: async (tab, params, response) => {
const messages = await tab.consoleMessages(params.level);
const text = messages.map((message) => message.toString()).join("\n");
await response.addResult({ text, suggestedFilename: params.filename });
}
});
var console_default = [
console
];

View file

@ -0,0 +1,60 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dialogs_exports = {};
__export(dialogs_exports, {
default: () => dialogs_default,
handleDialog: () => handleDialog
});
module.exports = __toCommonJS(dialogs_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const handleDialog = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_handle_dialog",
title: "Handle a dialog",
description: "Handle a dialog",
inputSchema: import_mcpBundle.z.object({
accept: import_mcpBundle.z.boolean().describe("Whether to accept the dialog."),
promptText: import_mcpBundle.z.string().optional().describe("The text of the prompt in case of a prompt dialog.")
}),
type: "action"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const dialogState = tab.modalStates().find((state) => state.type === "dialog");
if (!dialogState)
throw new Error("No dialog visible");
tab.clearModalState(dialogState);
await tab.waitForCompletion(async () => {
if (params.accept)
await dialogState.dialog.accept(params.promptText);
else
await dialogState.dialog.dismiss();
});
},
clearsModalState: "dialog"
});
var dialogs_default = [
handleDialog
];
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
handleDialog
});

View file

@ -0,0 +1,61 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var evaluate_exports = {};
__export(evaluate_exports, {
default: () => evaluate_default
});
module.exports = __toCommonJS(evaluate_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_utils = require("playwright-core/lib/utils");
var import_tool = require("./tool");
const evaluateSchema = import_mcpBundle.z.object({
function: import_mcpBundle.z.string().describe("() => { /* code */ } or (element) => { /* code */ } when element is provided"),
element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
ref: import_mcpBundle.z.string().optional().describe("Exact target element reference from the page snapshot"),
filename: import_mcpBundle.z.string().optional().describe("Filename to save the result to. If not provided, result is returned as JSON string.")
});
const evaluate = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_evaluate",
title: "Evaluate JavaScript",
description: "Evaluate JavaScript expression on page or element",
inputSchema: evaluateSchema,
type: "action"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
let locator;
if (params.ref && params.element) {
locator = await tab.refLocator({ ref: params.ref, element: params.element });
response.addCode(`await page.${locator.resolved}.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
} else {
response.addCode(`await page.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
}
await tab.waitForCompletion(async () => {
const receiver = locator?.locator ?? tab.page;
const result = await receiver._evaluateFunction(params.function);
const text = JSON.stringify(result, null, 2) || "undefined";
await response.addResult({ text, suggestedFilename: params.filename });
});
}
});
var evaluate_default = [
evaluate
];

View file

@ -0,0 +1,58 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var files_exports = {};
__export(files_exports, {
default: () => files_default,
uploadFile: () => uploadFile
});
module.exports = __toCommonJS(files_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const uploadFile = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_file_upload",
title: "Upload files",
description: "Upload one or multiple files",
inputSchema: import_mcpBundle.z.object({
paths: import_mcpBundle.z.array(import_mcpBundle.z.string()).optional().describe("The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.")
}),
type: "action"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const modalState = tab.modalStates().find((state) => state.type === "fileChooser");
if (!modalState)
throw new Error("No file chooser visible");
response.addCode(`await fileChooser.setFiles(${JSON.stringify(params.paths)})`);
tab.clearModalState(modalState);
await tab.waitForCompletion(async () => {
if (params.paths)
await modalState.fileChooser.setFiles(params.paths);
});
},
clearsModalState: "fileChooser"
});
var files_default = [
uploadFile
];
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
uploadFile
});

View file

@ -0,0 +1,63 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var form_exports = {};
__export(form_exports, {
default: () => form_default
});
module.exports = __toCommonJS(form_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_utils = require("playwright-core/lib/utils");
var import_tool = require("./tool");
const fillForm = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_fill_form",
title: "Fill form",
description: "Fill multiple form fields",
inputSchema: import_mcpBundle.z.object({
fields: import_mcpBundle.z.array(import_mcpBundle.z.object({
name: import_mcpBundle.z.string().describe("Human-readable field name"),
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
ref: import_mcpBundle.z.string().describe("Exact target field reference from the page snapshot"),
value: import_mcpBundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
})).describe("Fields to fill in")
}),
type: "input"
},
handle: async (tab, params, response) => {
for (const field of params.fields) {
const { locator, resolved } = await tab.refLocator({ element: field.name, ref: field.ref });
const locatorSource = `await page.${resolved}`;
if (field.type === "textbox" || field.type === "slider") {
const secret = tab.context.lookupSecret(field.value);
await locator.fill(secret.value);
response.addCode(`${locatorSource}.fill(${secret.code});`);
} else if (field.type === "checkbox" || field.type === "radio") {
await locator.setChecked(field.value === "true");
response.addCode(`${locatorSource}.setChecked(${field.value});`);
} else if (field.type === "combobox") {
await locator.selectOption({ label: field.value });
response.addCode(`${locatorSource}.selectOption(${(0, import_utils.escapeWithQuotes)(field.value)});`);
}
}
}
});
var form_default = [
fillForm
];

View file

@ -0,0 +1,72 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var install_exports = {};
__export(install_exports, {
default: () => install_default
});
module.exports = __toCommonJS(install_exports);
var import_child_process = require("child_process");
var import_path = __toESM(require("path"));
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_response = require("../response");
const install = (0, import_tool.defineTool)({
capability: "core-install",
schema: {
name: "browser_install",
title: "Install the browser specified in the config",
description: "Install the browser specified in the config. Call this if you get an error about the browser not being installed.",
inputSchema: import_mcpBundle.z.object({}),
type: "action"
},
handle: async (context, params, response) => {
const channel = context.config.browser?.launchOptions?.channel ?? context.config.browser?.browserName ?? "chrome";
const cliPath = import_path.default.join(require.resolve("playwright/package.json"), "../cli.js");
const child = (0, import_child_process.fork)(cliPath, ["install", channel], {
stdio: "pipe"
});
const output = [];
child.stdout?.on("data", (data) => output.push(data.toString()));
child.stderr?.on("data", (data) => output.push(data.toString()));
await new Promise((resolve, reject) => {
child.on("close", (code) => {
if (code === 0)
resolve();
else
reject(new Error(`Failed to install browser: ${output.join("")}`));
});
});
const tabHeaders = await Promise.all(context.tabs().map((tab) => tab.headerSnapshot()));
const result = (0, import_response.renderTabsMarkdown)(tabHeaders);
response.addTextResult(result.join("\n"));
}
});
var install_default = [
install
];

View file

@ -0,0 +1,107 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var keyboard_exports = {};
__export(keyboard_exports, {
default: () => keyboard_default
});
module.exports = __toCommonJS(keyboard_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_snapshot = require("./snapshot");
const pressKey = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_press_key",
title: "Press a key",
description: "Press a key on the keyboard",
inputSchema: import_mcpBundle.z.object({
key: import_mcpBundle.z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.addCode(`// Press ${params.key}`);
response.addCode(`await page.keyboard.press('${params.key}');`);
await tab.page.keyboard.press(params.key);
}
});
const pressSequentially = (0, import_tool.defineTabTool)({
capability: "internal",
schema: {
name: "browser_press_sequentially",
title: "Press sequentially",
description: "Press text sequentially on the keyboard",
inputSchema: import_mcpBundle.z.object({
text: import_mcpBundle.z.string().describe("Text to press sequentially"),
submit: import_mcpBundle.z.boolean().optional().describe("Whether to submit entered text (press Enter after)")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.addCode(`// Press ${params.text}`);
response.addCode(`await page.keyboard.type('${params.text}');`);
await tab.page.keyboard.type(params.text);
if (params.submit) {
response.addCode(`await page.keyboard.press('Enter');`);
response.setIncludeSnapshot();
await tab.waitForCompletion(async () => {
await tab.page.keyboard.press("Enter");
});
}
}
});
const typeSchema = import_snapshot.elementSchema.extend({
text: import_mcpBundle.z.string().describe("Text to type into the element"),
submit: import_mcpBundle.z.boolean().optional().describe("Whether to submit entered text (press Enter after)"),
slowly: import_mcpBundle.z.boolean().optional().describe("Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.")
});
const type = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_type",
title: "Type text",
description: "Type text into editable element",
inputSchema: typeSchema,
type: "input"
},
handle: async (tab, params, response) => {
const { locator, resolved } = await tab.refLocator(params);
const secret = tab.context.lookupSecret(params.text);
await tab.waitForCompletion(async () => {
if (params.slowly) {
response.setIncludeSnapshot();
response.addCode(`await page.${resolved}.pressSequentially(${secret.code});`);
await locator.pressSequentially(secret.value);
} else {
response.addCode(`await page.${resolved}.fill(${secret.code});`);
await locator.fill(secret.value);
}
if (params.submit) {
response.setIncludeSnapshot();
response.addCode(`await page.${resolved}.press('Enter');`);
await locator.press("Enter");
}
});
}
});
var keyboard_default = [
pressKey,
type,
pressSequentially
];

View file

@ -0,0 +1,107 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var mouse_exports = {};
__export(mouse_exports, {
default: () => mouse_default
});
module.exports = __toCommonJS(mouse_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const elementSchema = import_mcpBundle.z.object({
element: import_mcpBundle.z.string().describe("Human-readable element description used to obtain permission to interact with the element")
});
const mouseMove = (0, import_tool.defineTabTool)({
capability: "vision",
schema: {
name: "browser_mouse_move_xy",
title: "Move mouse",
description: "Move mouse to a given position",
inputSchema: elementSchema.extend({
x: import_mcpBundle.z.number().describe("X coordinate"),
y: import_mcpBundle.z.number().describe("Y coordinate")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.addCode(`// Move mouse to (${params.x}, ${params.y})`);
response.addCode(`await page.mouse.move(${params.x}, ${params.y});`);
await tab.waitForCompletion(async () => {
await tab.page.mouse.move(params.x, params.y);
});
}
});
const mouseClick = (0, import_tool.defineTabTool)({
capability: "vision",
schema: {
name: "browser_mouse_click_xy",
title: "Click",
description: "Click left mouse button at a given position",
inputSchema: elementSchema.extend({
x: import_mcpBundle.z.number().describe("X coordinate"),
y: import_mcpBundle.z.number().describe("Y coordinate")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
response.addCode(`// Click mouse at coordinates (${params.x}, ${params.y})`);
response.addCode(`await page.mouse.move(${params.x}, ${params.y});`);
response.addCode(`await page.mouse.down();`);
response.addCode(`await page.mouse.up();`);
await tab.waitForCompletion(async () => {
await tab.page.mouse.move(params.x, params.y);
await tab.page.mouse.down();
await tab.page.mouse.up();
});
}
});
const mouseDrag = (0, import_tool.defineTabTool)({
capability: "vision",
schema: {
name: "browser_mouse_drag_xy",
title: "Drag mouse",
description: "Drag left mouse button to a given position",
inputSchema: elementSchema.extend({
startX: import_mcpBundle.z.number().describe("Start X coordinate"),
startY: import_mcpBundle.z.number().describe("Start Y coordinate"),
endX: import_mcpBundle.z.number().describe("End X coordinate"),
endY: import_mcpBundle.z.number().describe("End Y coordinate")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
response.addCode(`// Drag mouse from (${params.startX}, ${params.startY}) to (${params.endX}, ${params.endY})`);
response.addCode(`await page.mouse.move(${params.startX}, ${params.startY});`);
response.addCode(`await page.mouse.down();`);
response.addCode(`await page.mouse.move(${params.endX}, ${params.endY});`);
response.addCode(`await page.mouse.up();`);
await tab.waitForCompletion(async () => {
await tab.page.mouse.move(params.startX, params.startY);
await tab.page.mouse.down();
await tab.page.mouse.move(params.endX, params.endY);
await tab.page.mouse.up();
});
}
});
var mouse_default = [
mouseMove,
mouseClick,
mouseDrag
];

View file

@ -0,0 +1,71 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var navigate_exports = {};
__export(navigate_exports, {
default: () => navigate_default
});
module.exports = __toCommonJS(navigate_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const navigate = (0, import_tool.defineTool)({
capability: "core",
schema: {
name: "browser_navigate",
title: "Navigate to a URL",
description: "Navigate to a URL",
inputSchema: import_mcpBundle.z.object({
url: import_mcpBundle.z.string().describe("The URL to navigate to")
}),
type: "action"
},
handle: async (context, params, response) => {
const tab = await context.ensureTab();
let url = params.url;
try {
new URL(url);
} catch (e) {
if (url.startsWith("localhost"))
url = "http://" + url;
else
url = "https://" + url;
}
await tab.navigate(url);
response.setIncludeSnapshot();
response.addCode(`await page.goto('${params.url}');`);
}
});
const goBack = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_navigate_back",
title: "Go back",
description: "Go back to the previous page",
inputSchema: import_mcpBundle.z.object({}),
type: "action"
},
handle: async (tab, params, response) => {
await tab.page.goBack();
response.setIncludeSnapshot();
response.addCode(`await page.goBack();`);
}
});
var navigate_default = [
navigate,
goBack
];

View file

@ -0,0 +1,63 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var network_exports = {};
__export(network_exports, {
default: () => network_default
});
module.exports = __toCommonJS(network_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const requests = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_network_requests",
title: "List network requests",
description: "Returns all network requests since loading the page",
inputSchema: import_mcpBundle.z.object({
includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false."),
filename: import_mcpBundle.z.string().optional().describe("Filename to save the network requests to. If not provided, requests are returned as text.")
}),
type: "readOnly"
},
handle: async (tab, params, response) => {
const requests2 = await tab.requests();
const text = [];
for (const request of requests2) {
const rendered = await renderRequest(request, params.includeStatic);
if (rendered)
text.push(rendered);
}
await response.addResult({ text: text.join("\n"), suggestedFilename: params.filename });
}
});
async function renderRequest(request, includeStatic) {
const response = request._hasResponse ? await request.response() : void 0;
const isStaticRequest = ["document", "stylesheet", "image", "media", "font", "script", "manifest"].includes(request.resourceType());
const isSuccessfulRequest = !response || response.status() < 400;
if (isStaticRequest && isSuccessfulRequest && !includeStatic)
return void 0;
const result = [];
result.push(`[${request.method().toUpperCase()}] ${request.url()}`);
if (response)
result.push(`=> [${response.status()}] ${response.statusText()}`);
return result.join(" ");
}
var network_default = [
requests
];

View file

@ -0,0 +1,57 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var open_exports = {};
__export(open_exports, {
default: () => open_default
});
module.exports = __toCommonJS(open_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const open = (0, import_tool.defineTool)({
capability: "internal",
schema: {
name: "browser_open",
title: "Open URL",
description: "Open a URL in the browser",
inputSchema: import_mcpBundle.z.object({
url: import_mcpBundle.z.string().describe("The URL to open"),
headed: import_mcpBundle.z.boolean().optional().describe("Run browser in headed mode")
}),
type: "action"
},
handle: async (context, params, response) => {
const forceHeadless = params.headed ? "headed" : "headless";
const tab = await context.ensureTab({ forceHeadless });
let url = params.url;
try {
new URL(url);
} catch (e) {
if (url.startsWith("localhost"))
url = "http://" + url;
else
url = "https://" + url;
}
await tab.navigate(url);
response.setIncludeSnapshot();
response.addCode(`await page.goto('${params.url}');`);
}
});
var open_default = [
open
];

View file

@ -0,0 +1,49 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var pdf_exports = {};
__export(pdf_exports, {
default: () => pdf_default
});
module.exports = __toCommonJS(pdf_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_utils = require("playwright-core/lib/utils");
var import_tool = require("./tool");
var import_utils2 = require("./utils");
const pdfSchema = import_mcpBundle.z.object({
filename: import_mcpBundle.z.string().optional().describe("File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified. Prefer relative file names to stay within the output directory.")
});
const pdf = (0, import_tool.defineTabTool)({
capability: "pdf",
schema: {
name: "browser_pdf_save",
title: "Save as PDF",
description: "Save page as PDF",
inputSchema: pdfSchema,
type: "readOnly"
},
handle: async (tab, params, response) => {
const data = await tab.page.pdf();
const suggestedFilename = params.filename ?? (0, import_utils2.dateAsFileName)("pdf");
await response.addResult({ data, title: "Page as pdf", suggestedFilename });
response.addCode(`await page.pdf(${(0, import_utils.formatObject)({ path: suggestedFilename })});`);
}
});
var pdf_default = [
pdf
];

View file

@ -0,0 +1,78 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var runCode_exports = {};
__export(runCode_exports, {
default: () => runCode_default
});
module.exports = __toCommonJS(runCode_exports);
var import_vm = __toESM(require("vm"));
var import_utils = require("playwright-core/lib/utils");
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const codeSchema = import_mcpBundle.z.object({
code: import_mcpBundle.z.string().describe(`A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction. For example: \`async (page) => { await page.getByRole('button', { name: 'Submit' }).click(); return await page.title(); }\``),
filename: import_mcpBundle.z.string().optional().describe("Filename to save the result to. If not provided, result is returned as JSON string.")
});
const runCode = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_run_code",
title: "Run Playwright code",
description: "Run Playwright code snippet",
inputSchema: codeSchema,
type: "action"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
response.addCode(`await (${params.code})(page);`);
const __end__ = new import_utils.ManualPromise();
const context = {
page: tab.page,
__end__
};
import_vm.default.createContext(context);
await tab.waitForCompletion(async () => {
const snippet = `(async () => {
try {
const result = await (${params.code})(page);
__end__.resolve(JSON.stringify(result));
} catch (e) {
__end__.reject(e);
}
})()`;
await import_vm.default.runInContext(snippet, context);
const result = await __end__;
if (typeof result === "string")
await response.addResult({ text: result, suggestedFilename: params.filename });
});
}
});
var runCode_default = [
runCode
];

View file

@ -0,0 +1,93 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var screenshot_exports = {};
__export(screenshot_exports, {
default: () => screenshot_default,
scaleImageToFitMessage: () => scaleImageToFitMessage
});
module.exports = __toCommonJS(screenshot_exports);
var import_utils = require("playwright-core/lib/utils");
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_utils2 = require("playwright-core/lib/utils");
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_utils3 = require("./utils");
const screenshotSchema = import_mcpBundle.z.object({
type: import_mcpBundle.z.enum(["png", "jpeg"]).default("png").describe("Image format for the screenshot. Default is png."),
filename: import_mcpBundle.z.string().optional().describe("File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified. Prefer relative file names to stay within the output directory."),
element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too."),
ref: import_mcpBundle.z.string().optional().describe("Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too."),
fullPage: import_mcpBundle.z.boolean().optional().describe("When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Cannot be used with element screenshots.")
});
const screenshot = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_take_screenshot",
title: "Take a screenshot",
description: `Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.`,
inputSchema: screenshotSchema,
type: "readOnly"
},
handle: async (tab, params, response) => {
if (!!params.element !== !!params.ref)
throw new Error("Both element and ref must be provided or neither.");
if (params.fullPage && params.ref)
throw new Error("fullPage cannot be used with element screenshots.");
const fileType = params.type || "png";
const options = {
type: fileType,
quality: fileType === "png" ? void 0 : 90,
scale: "css",
...params.fullPage !== void 0 && { fullPage: params.fullPage }
};
const isElementScreenshot = params.element && params.ref;
const screenshotTarget = isElementScreenshot ? params.element : params.fullPage ? "full page" : "viewport";
const ref = params.ref ? await tab.refLocator({ element: params.element || "", ref: params.ref }) : null;
const data = ref ? await ref.locator.screenshot(options) : await tab.page.screenshot(options);
const fileName = params.filename || (0, import_utils3.dateAsFileName)(fileType);
response.addCode(`// Screenshot ${screenshotTarget} and save it as ${fileName}`);
if (ref)
response.addCode(`await page.${ref.resolved}.screenshot(${(0, import_utils2.formatObject)({ ...options, path: fileName })});`);
else
response.addCode(`await page.screenshot(${(0, import_utils2.formatObject)({ ...options, path: fileName })});`);
await response.addResult({ data, title: `Screenshot of ${screenshotTarget}`, suggestedFilename: fileName });
response.addImage({
contentType: fileType === "png" ? "image/png" : "image/jpeg",
data: scaleImageToFitMessage(data, fileType)
});
}
});
function scaleImageToFitMessage(buffer, imageType) {
const image = imageType === "png" ? import_utilsBundle.PNG.sync.read(buffer) : import_utilsBundle.jpegjs.decode(buffer, { maxMemoryUsageInMB: 512 });
const pixels = image.width * image.height;
const shrink = Math.min(1568 / image.width, 1568 / image.height, Math.sqrt(1.15 * 1024 * 1024 / pixels));
if (shrink > 1)
return buffer;
const width = image.width * shrink | 0;
const height = image.height * shrink | 0;
const scaledImage = (0, import_utils.scaleImageToSize)(image, { width, height });
return imageType === "png" ? import_utilsBundle.PNG.sync.write(scaledImage) : import_utilsBundle.jpegjs.encode(scaledImage, 80).data;
}
var screenshot_default = [
screenshot
];
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
scaleImageToFitMessage
});

View file

@ -0,0 +1,173 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var snapshot_exports = {};
__export(snapshot_exports, {
default: () => snapshot_default,
elementSchema: () => elementSchema
});
module.exports = __toCommonJS(snapshot_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_utils = require("playwright-core/lib/utils");
var import_tool = require("./tool");
const snapshot = (0, import_tool.defineTool)({
capability: "core",
schema: {
name: "browser_snapshot",
title: "Page snapshot",
description: "Capture accessibility snapshot of the current page, this is better than screenshot",
inputSchema: import_mcpBundle.z.object({
filename: import_mcpBundle.z.string().optional().describe("Save snapshot to markdown file instead of returning it in the response.")
}),
type: "readOnly"
},
handle: async (context, params, response) => {
await context.ensureTab();
response.setIncludeFullSnapshot(params.filename);
}
});
const elementSchema = import_mcpBundle.z.object({
element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
});
const clickSchema = elementSchema.extend({
doubleClick: import_mcpBundle.z.boolean().optional().describe("Whether to perform a double click instead of a single click"),
button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional().describe("Button to click, defaults to left"),
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
});
const click = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_click",
title: "Click",
description: "Perform click on a web page",
inputSchema: clickSchema,
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const { locator, resolved } = await tab.refLocator(params);
const options = {
button: params.button,
modifiers: params.modifiers
};
const formatted = (0, import_utils.formatObject)(options, " ", "oneline");
const optionsAttr = formatted !== "{}" ? formatted : "";
if (params.doubleClick)
response.addCode(`await page.${resolved}.dblclick(${optionsAttr});`);
else
response.addCode(`await page.${resolved}.click(${optionsAttr});`);
await tab.waitForCompletion(async () => {
if (params.doubleClick)
await locator.dblclick(options);
else
await locator.click(options);
});
}
});
const drag = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_drag",
title: "Drag mouse",
description: "Perform drag and drop between two elements",
inputSchema: import_mcpBundle.z.object({
startElement: import_mcpBundle.z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
endElement: import_mcpBundle.z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
endRef: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
}),
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const [start, end] = await tab.refLocators([
{ ref: params.startRef, element: params.startElement },
{ ref: params.endRef, element: params.endElement }
]);
await tab.waitForCompletion(async () => {
await start.locator.dragTo(end.locator);
});
response.addCode(`await page.${start.resolved}.dragTo(page.${end.resolved});`);
}
});
const hover = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_hover",
title: "Hover mouse",
description: "Hover over element on page",
inputSchema: elementSchema,
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const { locator, resolved } = await tab.refLocator(params);
response.addCode(`await page.${resolved}.hover();`);
await tab.waitForCompletion(async () => {
await locator.hover();
});
}
});
const selectOptionSchema = elementSchema.extend({
values: import_mcpBundle.z.array(import_mcpBundle.z.string()).describe("Array of values to select in the dropdown. This can be a single value or multiple values.")
});
const selectOption = (0, import_tool.defineTabTool)({
capability: "core",
schema: {
name: "browser_select_option",
title: "Select option",
description: "Select an option in a dropdown",
inputSchema: selectOptionSchema,
type: "input"
},
handle: async (tab, params, response) => {
response.setIncludeSnapshot();
const { locator, resolved } = await tab.refLocator(params);
response.addCode(`await page.${resolved}.selectOption(${(0, import_utils.formatObject)(params.values)});`);
await tab.waitForCompletion(async () => {
await locator.selectOption(params.values);
});
}
});
const pickLocator = (0, import_tool.defineTabTool)({
capability: "testing",
schema: {
name: "browser_generate_locator",
title: "Create locator for element",
description: "Generate locator for the given element to use in tests",
inputSchema: elementSchema,
type: "readOnly"
},
handle: async (tab, params, response) => {
const { resolved } = await tab.refLocator(params);
response.addTextResult(resolved);
}
});
var snapshot_default = [
snapshot,
click,
drag,
hover,
selectOption,
pickLocator
];
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
elementSchema
});

View file

@ -0,0 +1,67 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tabs_exports = {};
__export(tabs_exports, {
default: () => tabs_default
});
module.exports = __toCommonJS(tabs_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_response = require("../response");
const browserTabs = (0, import_tool.defineTool)({
capability: "core-tabs",
schema: {
name: "browser_tabs",
title: "Manage tabs",
description: "List, create, close, or select a browser tab.",
inputSchema: import_mcpBundle.z.object({
action: import_mcpBundle.z.enum(["list", "new", "close", "select"]).describe("Operation to perform"),
index: import_mcpBundle.z.number().optional().describe("Tab index, used for close/select. If omitted for close, current tab is closed.")
}),
type: "action"
},
handle: async (context, params, response) => {
switch (params.action) {
case "list": {
await context.ensureTab();
break;
}
case "new": {
await context.newTab();
break;
}
case "close": {
await context.closeTab(params.index);
break;
}
case "select": {
if (params.index === void 0)
throw new Error("Tab index is required");
await context.selectTab(params.index);
break;
}
}
const tabHeaders = await Promise.all(context.tabs().map((tab) => tab.headerSnapshot()));
const result = (0, import_response.renderTabsMarkdown)(tabHeaders);
response.addTextResult(result.join("\n"));
}
});
var tabs_default = [
browserTabs
];

View file

@ -0,0 +1,47 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tool_exports = {};
__export(tool_exports, {
defineTabTool: () => defineTabTool,
defineTool: () => defineTool
});
module.exports = __toCommonJS(tool_exports);
function defineTool(tool) {
return tool;
}
function defineTabTool(tool) {
return {
...tool,
handle: async (context, params, response) => {
const tab = await context.ensureTab();
const modalStates = tab.modalStates().map((state) => state.type);
if (tool.clearsModalState && !modalStates.includes(tool.clearsModalState))
response.addError(`Error: The tool "${tool.schema.name}" can only be used when there is related modal state present.`);
else if (!tool.clearsModalState && modalStates.length)
response.addError(`Error: Tool "${tool.schema.name}" does not handle the modal state.`);
else
return tool.handle(tab, params, response);
}
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
defineTabTool,
defineTool
});

View file

@ -0,0 +1,74 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tracing_exports = {};
__export(tracing_exports, {
default: () => tracing_default
});
module.exports = __toCommonJS(tracing_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const tracingStart = (0, import_tool.defineTool)({
capability: "tracing",
schema: {
name: "browser_start_tracing",
title: "Start tracing",
description: "Start trace recording",
inputSchema: import_mcpBundle.z.object({}),
type: "readOnly"
},
handle: async (context, params, response) => {
const browserContext = await context.ensureBrowserContext();
const tracesDir = await context.outputFile(`traces`, { origin: "code", title: "Collecting trace" });
const name = "trace-" + Date.now();
await browserContext.tracing.start({
name,
screenshots: true,
snapshots: true,
_live: true
});
const traceLegend = `- Action log: ${tracesDir}/${name}.trace
- Network log: ${tracesDir}/${name}.network
- Resources with content by sha1: ${tracesDir}/resources`;
response.addTextResult(`Tracing started, saving to ${tracesDir}.
${traceLegend}`);
browserContext.tracing[traceLegendSymbol] = traceLegend;
}
});
const tracingStop = (0, import_tool.defineTool)({
capability: "tracing",
schema: {
name: "browser_stop_tracing",
title: "Stop tracing",
description: "Stop trace recording",
inputSchema: import_mcpBundle.z.object({}),
type: "readOnly"
},
handle: async (context, params, response) => {
const browserContext = await context.ensureBrowserContext();
await browserContext.tracing.stop();
const traceLegend = browserContext.tracing[traceLegendSymbol];
response.addTextResult(`Tracing stopped.
${traceLegend}`);
}
});
var tracing_default = [
tracingStart,
tracingStop
];
const traceLegendSymbol = Symbol("tracesDir");

View file

@ -0,0 +1,94 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var utils_exports = {};
__export(utils_exports, {
callOnPageNoTrace: () => callOnPageNoTrace,
dateAsFileName: () => dateAsFileName,
eventWaiter: () => eventWaiter,
waitForCompletion: () => waitForCompletion
});
module.exports = __toCommonJS(utils_exports);
async function waitForCompletion(tab, callback) {
const requests = [];
const requestListener = (request) => requests.push(request);
const disposeListeners = () => {
tab.page.off("request", requestListener);
};
tab.page.on("request", requestListener);
let result;
try {
result = await callback();
await tab.waitForTimeout(500);
} finally {
disposeListeners();
}
const requestedNavigation = requests.some((request) => request.isNavigationRequest());
if (requestedNavigation) {
await tab.page.mainFrame().waitForLoadState("load", { timeout: 1e4 }).catch(() => {
});
return result;
}
const promises = [];
for (const request of requests) {
if (["document", "stylesheet", "script", "xhr", "fetch"].includes(request.resourceType()))
promises.push(request.response().then((r) => r?.finished()).catch(() => {
}));
else
promises.push(request.response().catch(() => {
}));
}
const timeout = new Promise((resolve) => setTimeout(resolve, 5e3));
await Promise.race([Promise.all(promises), timeout]);
if (requests.length)
await tab.waitForTimeout(500);
return result;
}
async function callOnPageNoTrace(page, callback) {
return await page._wrapApiCall(() => callback(page), { internal: true });
}
function dateAsFileName(extension) {
const date = /* @__PURE__ */ new Date();
return `page-${date.toISOString().replace(/[:.]/g, "-")}.${extension}`;
}
function eventWaiter(page, event, timeout) {
const disposables = [];
const eventPromise = new Promise((resolve, reject) => {
page.on(event, resolve);
disposables.push(() => page.off(event, resolve));
});
let abort;
const abortPromise = new Promise((resolve, reject) => {
abort = () => resolve(void 0);
});
const timeoutPromise = new Promise((f) => {
const timeoutId = setTimeout(() => f(void 0), timeout);
disposables.push(() => clearTimeout(timeoutId));
});
return {
promise: Promise.race([eventPromise, abortPromise, timeoutPromise]).finally(() => disposables.forEach((dispose) => dispose())),
abort
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
callOnPageNoTrace,
dateAsFileName,
eventWaiter,
waitForCompletion
});

View file

@ -0,0 +1,143 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var verify_exports = {};
__export(verify_exports, {
default: () => verify_default
});
module.exports = __toCommonJS(verify_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_utils = require("playwright-core/lib/utils");
var import_tool = require("./tool");
const verifyElement = (0, import_tool.defineTabTool)({
capability: "testing",
schema: {
name: "browser_verify_element_visible",
title: "Verify element visible",
description: "Verify element is visible on the page",
inputSchema: import_mcpBundle.z.object({
role: import_mcpBundle.z.string().describe('ROLE of the element. Can be found in the snapshot like this: `- {ROLE} "Accessible Name":`'),
accessibleName: import_mcpBundle.z.string().describe('ACCESSIBLE_NAME of the element. Can be found in the snapshot like this: `- role "{ACCESSIBLE_NAME}"`')
}),
type: "assertion"
},
handle: async (tab, params, response) => {
const locator = tab.page.getByRole(params.role, { name: params.accessibleName });
if (await locator.count() === 0) {
response.addError(`Element with role "${params.role}" and accessible name "${params.accessibleName}" not found`);
return;
}
response.addCode(`await expect(page.getByRole(${(0, import_utils.escapeWithQuotes)(params.role)}, { name: ${(0, import_utils.escapeWithQuotes)(params.accessibleName)} })).toBeVisible();`);
response.addTextResult("Done");
}
});
const verifyText = (0, import_tool.defineTabTool)({
capability: "testing",
schema: {
name: "browser_verify_text_visible",
title: "Verify text visible",
description: `Verify text is visible on the page. Prefer ${verifyElement.schema.name} if possible.`,
inputSchema: import_mcpBundle.z.object({
text: import_mcpBundle.z.string().describe('TEXT to verify. Can be found in the snapshot like this: `- role "Accessible Name": {TEXT}` or like this: `- text: {TEXT}`')
}),
type: "assertion"
},
handle: async (tab, params, response) => {
const locator = tab.page.getByText(params.text).filter({ visible: true });
if (await locator.count() === 0) {
response.addError("Text not found");
return;
}
response.addCode(`await expect(page.getByText(${(0, import_utils.escapeWithQuotes)(params.text)})).toBeVisible();`);
response.addTextResult("Done");
}
});
const verifyList = (0, import_tool.defineTabTool)({
capability: "testing",
schema: {
name: "browser_verify_list_visible",
title: "Verify list visible",
description: "Verify list is visible on the page",
inputSchema: import_mcpBundle.z.object({
element: import_mcpBundle.z.string().describe("Human-readable list description"),
ref: import_mcpBundle.z.string().describe("Exact target element reference that points to the list"),
items: import_mcpBundle.z.array(import_mcpBundle.z.string()).describe("Items to verify")
}),
type: "assertion"
},
handle: async (tab, params, response) => {
const { locator } = await tab.refLocator({ ref: params.ref, element: params.element });
const itemTexts = [];
for (const item of params.items) {
const itemLocator = locator.getByText(item);
if (await itemLocator.count() === 0) {
response.addError(`Item "${item}" not found`);
return;
}
itemTexts.push(await itemLocator.textContent());
}
const ariaSnapshot = `\`
- list:
${itemTexts.map((t) => ` - listitem: ${(0, import_utils.escapeWithQuotes)(t, '"')}`).join("\n")}
\``;
response.addCode(`await expect(page.locator('body')).toMatchAriaSnapshot(${ariaSnapshot});`);
response.addTextResult("Done");
}
});
const verifyValue = (0, import_tool.defineTabTool)({
capability: "testing",
schema: {
name: "browser_verify_value",
title: "Verify value",
description: "Verify element value",
inputSchema: import_mcpBundle.z.object({
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the element"),
element: import_mcpBundle.z.string().describe("Human-readable element description"),
ref: import_mcpBundle.z.string().describe("Exact target element reference that points to the element"),
value: import_mcpBundle.z.string().describe('Value to verify. For checkbox, use "true" or "false".')
}),
type: "assertion"
},
handle: async (tab, params, response) => {
const { locator, resolved } = await tab.refLocator({ ref: params.ref, element: params.element });
const locatorSource = `page.${resolved}`;
if (params.type === "textbox" || params.type === "slider" || params.type === "combobox") {
const value = await locator.inputValue();
if (value !== params.value) {
response.addError(`Expected value "${params.value}", but got "${value}"`);
return;
}
response.addCode(`await expect(${locatorSource}).toHaveValue(${(0, import_utils.escapeWithQuotes)(params.value)});`);
} else if (params.type === "checkbox" || params.type === "radio") {
const value = await locator.isChecked();
if (value !== (params.value === "true")) {
response.addError(`Expected value "${params.value}", but got "${value}"`);
return;
}
const matcher = value ? "toBeChecked" : "not.toBeChecked";
response.addCode(`await expect(${locatorSource}).${matcher}();`);
}
response.addTextResult("Done");
}
});
var verify_default = [
verifyElement,
verifyText,
verifyList,
verifyValue
];

View file

@ -0,0 +1,63 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var wait_exports = {};
__export(wait_exports, {
default: () => wait_default
});
module.exports = __toCommonJS(wait_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
const wait = (0, import_tool.defineTool)({
capability: "core",
schema: {
name: "browser_wait_for",
title: "Wait for",
description: "Wait for text to appear or disappear or a specified time to pass",
inputSchema: import_mcpBundle.z.object({
time: import_mcpBundle.z.number().optional().describe("The time to wait in seconds"),
text: import_mcpBundle.z.string().optional().describe("The text to wait for"),
textGone: import_mcpBundle.z.string().optional().describe("The text to wait for to disappear")
}),
type: "assertion"
},
handle: async (context, params, response) => {
if (!params.text && !params.textGone && !params.time)
throw new Error("Either time, text or textGone must be provided");
if (params.time) {
response.addCode(`await new Promise(f => setTimeout(f, ${params.time} * 1000));`);
await new Promise((f) => setTimeout(f, Math.min(3e4, params.time * 1e3)));
}
const tab = context.currentTabOrDie();
const locator = params.text ? tab.page.getByText(params.text).first() : void 0;
const goneLocator = params.textGone ? tab.page.getByText(params.textGone).first() : void 0;
if (goneLocator) {
response.addCode(`await page.getByText(${JSON.stringify(params.textGone)}).first().waitFor({ state: 'hidden' });`);
await goneLocator.waitFor({ state: "hidden" });
}
if (locator) {
response.addCode(`await page.getByText(${JSON.stringify(params.text)}).first().waitFor({ state: 'visible' });`);
await locator.waitFor({ state: "visible" });
}
response.addTextResult(`Waited for ${params.text || params.textGone || params.time}`);
response.setIncludeSnapshot();
}
});
var wait_default = [
wait
];

View file

@ -0,0 +1,44 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var watchdog_exports = {};
__export(watchdog_exports, {
setupExitWatchdog: () => setupExitWatchdog
});
module.exports = __toCommonJS(watchdog_exports);
var import_browserContextFactory = require("./browserContextFactory");
var import_context = require("./context");
function setupExitWatchdog() {
let isExiting = false;
const handleExit = async () => {
if (isExiting)
return;
isExiting = true;
setTimeout(() => process.exit(0), 15e3);
await import_context.Context.disposeAll();
await import_browserContextFactory.SharedContextFactory.dispose();
process.exit(0);
};
process.stdin.on("close", handleExit);
process.on("SIGINT", handleExit);
process.on("SIGTERM", handleExit);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
setupExitWatchdog
});

16
backend/node_modules/playwright/lib/mcp/config.d.js generated vendored Normal file
View file

@ -0,0 +1,16 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var config_d_exports = {};
module.exports = __toCommonJS(config_d_exports);

View file

@ -0,0 +1,351 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var cdpRelay_exports = {};
__export(cdpRelay_exports, {
CDPRelayServer: () => CDPRelayServer
});
module.exports = __toCommonJS(cdpRelay_exports);
var import_child_process = require("child_process");
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_registry = require("playwright-core/lib/server/registry/index");
var import_utils = require("playwright-core/lib/utils");
var import_http2 = require("../sdk/http");
var import_log = require("../log");
var protocol = __toESM(require("./protocol"));
const debugLogger = (0, import_utilsBundle.debug)("pw:mcp:relay");
class CDPRelayServer {
constructor(server, browserChannel, userDataDir, executablePath) {
this._playwrightConnection = null;
this._extensionConnection = null;
this._nextSessionId = 1;
this._wsHost = (0, import_http2.addressToString)(server.address(), { protocol: "ws" });
this._browserChannel = browserChannel;
this._userDataDir = userDataDir;
this._executablePath = executablePath;
const uuid = crypto.randomUUID();
this._cdpPath = `/cdp/${uuid}`;
this._extensionPath = `/extension/${uuid}`;
this._resetExtensionConnection();
this._wss = new import_utilsBundle.wsServer({ server });
this._wss.on("connection", this._onConnection.bind(this));
}
cdpEndpoint() {
return `${this._wsHost}${this._cdpPath}`;
}
extensionEndpoint() {
return `${this._wsHost}${this._extensionPath}`;
}
async ensureExtensionConnectionForMCPContext(clientInfo, abortSignal, toolName) {
debugLogger("Ensuring extension connection for MCP context");
if (this._extensionConnection)
return;
this._connectBrowser(clientInfo, toolName);
debugLogger("Waiting for incoming extension connection");
await Promise.race([
this._extensionConnectionPromise,
new Promise((_, reject) => setTimeout(() => {
reject(new Error(`Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed. See https://github.com/microsoft/playwright-mcp/blob/main/extension/README.md for installation instructions.`));
}, process.env.PWMCP_TEST_CONNECTION_TIMEOUT ? parseInt(process.env.PWMCP_TEST_CONNECTION_TIMEOUT, 10) : 5e3)),
new Promise((_, reject) => abortSignal.addEventListener("abort", reject))
]);
debugLogger("Extension connection established");
}
_connectBrowser(clientInfo, toolName) {
const mcpRelayEndpoint = `${this._wsHost}${this._extensionPath}`;
const url = new URL("chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html");
url.searchParams.set("mcpRelayUrl", mcpRelayEndpoint);
const client = {
name: clientInfo.name,
version: clientInfo.version
};
url.searchParams.set("client", JSON.stringify(client));
url.searchParams.set("protocolVersion", process.env.PWMCP_TEST_PROTOCOL_VERSION ?? protocol.VERSION.toString());
if (toolName)
url.searchParams.set("newTab", String(toolName === "browser_navigate"));
const token = process.env.PLAYWRIGHT_MCP_EXTENSION_TOKEN;
if (token)
url.searchParams.set("token", token);
const href = url.toString();
let executablePath = this._executablePath;
if (!executablePath) {
const executableInfo = import_registry.registry.findExecutable(this._browserChannel);
if (!executableInfo)
throw new Error(`Unsupported channel: "${this._browserChannel}"`);
executablePath = executableInfo.executablePath("javascript");
if (!executablePath)
throw new Error(`"${this._browserChannel}" executable not found. Make sure it is installed at a standard location.`);
}
const args = [];
if (this._userDataDir)
args.push(`--user-data-dir=${this._userDataDir}`);
args.push(href);
(0, import_child_process.spawn)(executablePath, args, {
windowsHide: true,
detached: true,
shell: false,
stdio: "ignore"
});
}
stop() {
this.closeConnections("Server stopped");
this._wss.close();
}
closeConnections(reason) {
this._closePlaywrightConnection(reason);
this._closeExtensionConnection(reason);
}
_onConnection(ws2, request) {
const url = new URL(`http://localhost${request.url}`);
debugLogger(`New connection to ${url.pathname}`);
if (url.pathname === this._cdpPath) {
this._handlePlaywrightConnection(ws2);
} else if (url.pathname === this._extensionPath) {
this._handleExtensionConnection(ws2);
} else {
debugLogger(`Invalid path: ${url.pathname}`);
ws2.close(4004, "Invalid path");
}
}
_handlePlaywrightConnection(ws2) {
if (this._playwrightConnection) {
debugLogger("Rejecting second Playwright connection");
ws2.close(1e3, "Another CDP client already connected");
return;
}
this._playwrightConnection = ws2;
ws2.on("message", async (data) => {
try {
const message = JSON.parse(data.toString());
await this._handlePlaywrightMessage(message);
} catch (error) {
debugLogger(`Error while handling Playwright message
${data.toString()}
`, error);
}
});
ws2.on("close", () => {
if (this._playwrightConnection !== ws2)
return;
this._playwrightConnection = null;
this._closeExtensionConnection("Playwright client disconnected");
debugLogger("Playwright WebSocket closed");
});
ws2.on("error", (error) => {
debugLogger("Playwright WebSocket error:", error);
});
debugLogger("Playwright MCP connected");
}
_closeExtensionConnection(reason) {
this._extensionConnection?.close(reason);
this._extensionConnectionPromise.reject(new Error(reason));
this._resetExtensionConnection();
}
_resetExtensionConnection() {
this._connectedTabInfo = void 0;
this._extensionConnection = null;
this._extensionConnectionPromise = new import_utils.ManualPromise();
void this._extensionConnectionPromise.catch(import_log.logUnhandledError);
}
_closePlaywrightConnection(reason) {
if (this._playwrightConnection?.readyState === import_utilsBundle.ws.OPEN)
this._playwrightConnection.close(1e3, reason);
this._playwrightConnection = null;
}
_handleExtensionConnection(ws2) {
if (this._extensionConnection) {
ws2.close(1e3, "Another extension connection already established");
return;
}
this._extensionConnection = new ExtensionConnection(ws2);
this._extensionConnection.onclose = (c, reason) => {
debugLogger("Extension WebSocket closed:", reason, c === this._extensionConnection);
if (this._extensionConnection !== c)
return;
this._resetExtensionConnection();
this._closePlaywrightConnection(`Extension disconnected: ${reason}`);
};
this._extensionConnection.onmessage = this._handleExtensionMessage.bind(this);
this._extensionConnectionPromise.resolve();
}
_handleExtensionMessage(method, params) {
switch (method) {
case "forwardCDPEvent":
const sessionId = params.sessionId || this._connectedTabInfo?.sessionId;
this._sendToPlaywright({
sessionId,
method: params.method,
params: params.params
});
break;
}
}
async _handlePlaywrightMessage(message) {
debugLogger("\u2190 Playwright:", `${message.method} (id=${message.id})`);
const { id, sessionId, method, params } = message;
try {
const result = await this._handleCDPCommand(method, params, sessionId);
this._sendToPlaywright({ id, sessionId, result });
} catch (e) {
debugLogger("Error in the extension:", e);
this._sendToPlaywright({
id,
sessionId,
error: { message: e.message }
});
}
}
async _handleCDPCommand(method, params, sessionId) {
switch (method) {
case "Browser.getVersion": {
return {
protocolVersion: "1.3",
product: "Chrome/Extension-Bridge",
userAgent: "CDP-Bridge-Server/1.0.0"
};
}
case "Browser.setDownloadBehavior": {
return {};
}
case "Target.setAutoAttach": {
if (sessionId)
break;
const { targetInfo } = await this._extensionConnection.send("attachToTab", {});
this._connectedTabInfo = {
targetInfo,
sessionId: `pw-tab-${this._nextSessionId++}`
};
debugLogger("Simulating auto-attach");
this._sendToPlaywright({
method: "Target.attachedToTarget",
params: {
sessionId: this._connectedTabInfo.sessionId,
targetInfo: {
...this._connectedTabInfo.targetInfo,
attached: true
},
waitingForDebugger: false
}
});
return {};
}
case "Target.getTargetInfo": {
return this._connectedTabInfo?.targetInfo;
}
}
return await this._forwardToExtension(method, params, sessionId);
}
async _forwardToExtension(method, params, sessionId) {
if (!this._extensionConnection)
throw new Error("Extension not connected");
if (this._connectedTabInfo?.sessionId === sessionId)
sessionId = void 0;
return await this._extensionConnection.send("forwardCDPCommand", { sessionId, method, params });
}
_sendToPlaywright(message) {
debugLogger("\u2192 Playwright:", `${message.method ?? `response(id=${message.id})`}`);
this._playwrightConnection?.send(JSON.stringify(message));
}
}
class ExtensionConnection {
constructor(ws2) {
this._callbacks = /* @__PURE__ */ new Map();
this._lastId = 0;
this._ws = ws2;
this._ws.on("message", this._onMessage.bind(this));
this._ws.on("close", this._onClose.bind(this));
this._ws.on("error", this._onError.bind(this));
}
async send(method, params) {
if (this._ws.readyState !== import_utilsBundle.ws.OPEN)
throw new Error(`Unexpected WebSocket state: ${this._ws.readyState}`);
const id = ++this._lastId;
this._ws.send(JSON.stringify({ id, method, params }));
const error = new Error(`Protocol error: ${method}`);
return new Promise((resolve, reject) => {
this._callbacks.set(id, { resolve, reject, error });
});
}
close(message) {
debugLogger("closing extension connection:", message);
if (this._ws.readyState === import_utilsBundle.ws.OPEN)
this._ws.close(1e3, message);
}
_onMessage(event) {
const eventData = event.toString();
let parsedJson;
try {
parsedJson = JSON.parse(eventData);
} catch (e) {
debugLogger(`<closing ws> Closing websocket due to malformed JSON. eventData=${eventData} e=${e?.message}`);
this._ws.close();
return;
}
try {
this._handleParsedMessage(parsedJson);
} catch (e) {
debugLogger(`<closing ws> Closing websocket due to failed onmessage callback. eventData=${eventData} e=${e?.message}`);
this._ws.close();
}
}
_handleParsedMessage(object) {
if (object.id && this._callbacks.has(object.id)) {
const callback = this._callbacks.get(object.id);
this._callbacks.delete(object.id);
if (object.error) {
const error = callback.error;
error.message = object.error;
callback.reject(error);
} else {
callback.resolve(object.result);
}
} else if (object.id) {
debugLogger("\u2190 Extension: unexpected response", object);
} else {
this.onmessage?.(object.method, object.params);
}
}
_onClose(event) {
debugLogger(`<ws closed> code=${event.code} reason=${event.reason}`);
this._dispose();
this.onclose?.(this, event.reason);
}
_onError(event) {
debugLogger(`<ws error> message=${event.message} type=${event.type} target=${event.target}`);
this._dispose();
}
_dispose() {
for (const callback of this._callbacks.values())
callback.reject(new Error("WebSocket closed"));
this._callbacks.clear();
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CDPRelayServer
});

View file

@ -0,0 +1,76 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var extensionContextFactory_exports = {};
__export(extensionContextFactory_exports, {
ExtensionContextFactory: () => ExtensionContextFactory
});
module.exports = __toCommonJS(extensionContextFactory_exports);
var playwright = __toESM(require("playwright-core"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_utils = require("playwright-core/lib/utils");
var import_cdpRelay = require("./cdpRelay");
const debugLogger = (0, import_utilsBundle.debug)("pw:mcp:relay");
class ExtensionContextFactory {
constructor(browserChannel, userDataDir, executablePath) {
this._browserChannel = browserChannel;
this._userDataDir = userDataDir;
this._executablePath = executablePath;
}
async createContext(clientInfo, abortSignal, options) {
const browser = await this._obtainBrowser(clientInfo, abortSignal, options?.toolName);
return {
browserContext: browser.contexts()[0],
close: async () => {
debugLogger("close() called for browser context");
await browser.close();
}
};
}
async _obtainBrowser(clientInfo, abortSignal, toolName) {
const relay = await this._startRelay(abortSignal);
await relay.ensureExtensionConnectionForMCPContext(clientInfo, abortSignal, toolName);
return await playwright.chromium.connectOverCDP(relay.cdpEndpoint(), { isLocal: true });
}
async _startRelay(abortSignal) {
const httpServer = (0, import_utils.createHttpServer)();
await (0, import_utils.startHttpServer)(httpServer, {});
if (abortSignal.aborted) {
httpServer.close();
throw new Error(abortSignal.reason);
}
const cdpRelayServer = new import_cdpRelay.CDPRelayServer(httpServer, this._browserChannel, this._userDataDir, this._executablePath);
abortSignal.addEventListener("abort", () => cdpRelayServer.stop());
debugLogger(`CDP relay server started, extension endpoint: ${cdpRelayServer.extensionEndpoint()}.`);
return cdpRelayServer;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ExtensionContextFactory
});

View file

@ -0,0 +1,28 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var protocol_exports = {};
__export(protocol_exports, {
VERSION: () => VERSION
});
module.exports = __toCommonJS(protocol_exports);
const VERSION = 1;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
VERSION
});

61
backend/node_modules/playwright/lib/mcp/index.js generated vendored Normal file
View file

@ -0,0 +1,61 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var mcp_exports = {};
__export(mcp_exports, {
createConnection: () => createConnection
});
module.exports = __toCommonJS(mcp_exports);
var import_browserServerBackend = require("./browser/browserServerBackend");
var import_config = require("./browser/config");
var import_browserContextFactory = require("./browser/browserContextFactory");
var mcpServer = __toESM(require("./sdk/server"));
const packageJSON = require("../../package.json");
async function createConnection(userConfig = {}, contextGetter) {
const config = await (0, import_config.resolveConfig)(userConfig);
const factory = contextGetter ? new SimpleBrowserContextFactory(contextGetter) : (0, import_browserContextFactory.contextFactory)(config);
return mcpServer.createServer("Playwright", packageJSON.version, new import_browserServerBackend.BrowserServerBackend(config, factory), false);
}
class SimpleBrowserContextFactory {
constructor(contextGetter) {
this.name = "custom";
this.description = "Connect to a browser using a custom context getter";
this._contextGetter = contextGetter;
}
async createContext() {
const browserContext = await this._contextGetter();
return {
browserContext,
close: () => browserContext.close()
};
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createConnection
});

35
backend/node_modules/playwright/lib/mcp/log.js generated vendored Normal file
View file

@ -0,0 +1,35 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var log_exports = {};
__export(log_exports, {
logUnhandledError: () => logUnhandledError,
testDebug: () => testDebug
});
module.exports = __toCommonJS(log_exports);
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
const errorDebug = (0, import_utilsBundle.debug)("pw:mcp:error");
function logUnhandledError(error) {
errorDebug(error);
}
const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
logUnhandledError,
testDebug
});

111
backend/node_modules/playwright/lib/mcp/program.js generated vendored Normal file

File diff suppressed because one or more lines are too long

28
backend/node_modules/playwright/lib/mcp/sdk/exports.js generated vendored Normal file
View file

@ -0,0 +1,28 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var exports_exports = {};
module.exports = __toCommonJS(exports_exports);
__reExport(exports_exports, require("./inProcessTransport"), module.exports);
__reExport(exports_exports, require("./server"), module.exports);
__reExport(exports_exports, require("./tool"), module.exports);
__reExport(exports_exports, require("./http"), module.exports);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
...require("./inProcessTransport"),
...require("./server"),
...require("./tool"),
...require("./http")
});

152
backend/node_modules/playwright/lib/mcp/sdk/http.js generated vendored Normal file
View file

@ -0,0 +1,152 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var http_exports = {};
__export(http_exports, {
addressToString: () => addressToString,
startMcpHttpServer: () => startMcpHttpServer
});
module.exports = __toCommonJS(http_exports);
var import_assert = __toESM(require("assert"));
var import_crypto = __toESM(require("crypto"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var mcpBundle = __toESM(require("playwright-core/lib/mcpBundle"));
var import_utils = require("playwright-core/lib/utils");
var mcpServer = __toESM(require("./server"));
const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
async function startMcpHttpServer(config, serverBackendFactory, allowedHosts) {
const httpServer = (0, import_utils.createHttpServer)();
await (0, import_utils.startHttpServer)(httpServer, config);
return await installHttpTransport(httpServer, serverBackendFactory, allowedHosts);
}
function addressToString(address, options) {
(0, import_assert.default)(address, "Could not bind server socket");
if (typeof address === "string")
throw new Error("Unexpected address type: " + address);
let host = address.family === "IPv4" ? address.address : `[${address.address}]`;
if (options.normalizeLoopback && (host === "0.0.0.0" || host === "[::]" || host === "[::1]" || host === "127.0.0.1"))
host = "localhost";
return `${options.protocol}://${host}:${address.port}`;
}
async function installHttpTransport(httpServer, serverBackendFactory, allowedHosts) {
const url = addressToString(httpServer.address(), { protocol: "http", normalizeLoopback: true });
const host = new URL(url).host;
allowedHosts = (allowedHosts || [host]).map((h) => h.toLowerCase());
const allowAnyHost = allowedHosts.includes("*");
const sseSessions = /* @__PURE__ */ new Map();
const streamableSessions = /* @__PURE__ */ new Map();
httpServer.on("request", async (req, res) => {
if (!allowAnyHost) {
const host2 = req.headers.host?.toLowerCase();
if (!host2) {
res.statusCode = 400;
return res.end("Missing host");
}
if (!allowedHosts.includes(host2)) {
res.statusCode = 403;
return res.end("Access is only allowed at " + allowedHosts.join(", "));
}
}
const url2 = new URL(`http://localhost${req.url}`);
if (url2.pathname === "/killkillkill" && req.method === "GET") {
res.statusCode = 200;
res.end("Killing process");
process.emit("SIGINT");
return;
}
if (url2.pathname.startsWith("/sse"))
await handleSSE(serverBackendFactory, req, res, url2, sseSessions);
else
await handleStreamable(serverBackendFactory, req, res, streamableSessions);
});
return url;
}
async function handleSSE(serverBackendFactory, req, res, url, sessions) {
if (req.method === "POST") {
const sessionId = url.searchParams.get("sessionId");
if (!sessionId) {
res.statusCode = 400;
return res.end("Missing sessionId");
}
const transport = sessions.get(sessionId);
if (!transport) {
res.statusCode = 404;
return res.end("Session not found");
}
return await transport.handlePostMessage(req, res);
} else if (req.method === "GET") {
const transport = new mcpBundle.SSEServerTransport("/sse", res);
sessions.set(transport.sessionId, transport);
testDebug(`create SSE session: ${transport.sessionId}`);
await mcpServer.connect(serverBackendFactory, transport, false);
res.on("close", () => {
testDebug(`delete SSE session: ${transport.sessionId}`);
sessions.delete(transport.sessionId);
});
return;
}
res.statusCode = 405;
res.end("Method not allowed");
}
async function handleStreamable(serverBackendFactory, req, res, sessions) {
const sessionId = req.headers["mcp-session-id"];
if (sessionId) {
const transport = sessions.get(sessionId);
if (!transport) {
res.statusCode = 404;
res.end("Session not found");
return;
}
return await transport.handleRequest(req, res);
}
if (req.method === "POST") {
const transport = new mcpBundle.StreamableHTTPServerTransport({
sessionIdGenerator: () => import_crypto.default.randomUUID(),
onsessioninitialized: async (sessionId2) => {
testDebug(`create http session: ${transport.sessionId}`);
await mcpServer.connect(serverBackendFactory, transport, true);
sessions.set(sessionId2, transport);
}
});
transport.onclose = () => {
if (!transport.sessionId)
return;
sessions.delete(transport.sessionId);
testDebug(`delete http session: ${transport.sessionId}`);
};
await transport.handleRequest(req, res);
return;
}
res.statusCode = 400;
res.end("Invalid request");
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
addressToString,
startMcpHttpServer
});

View file

@ -0,0 +1,71 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var inProcessTransport_exports = {};
__export(inProcessTransport_exports, {
InProcessTransport: () => InProcessTransport
});
module.exports = __toCommonJS(inProcessTransport_exports);
class InProcessTransport {
constructor(server) {
this._connected = false;
this._server = server;
this._serverTransport = new InProcessServerTransport(this);
}
async start() {
if (this._connected)
throw new Error("InprocessTransport already started!");
await this._server.connect(this._serverTransport);
this._connected = true;
}
async send(message, options) {
if (!this._connected)
throw new Error("Transport not connected");
this._serverTransport._receiveFromClient(message);
}
async close() {
if (this._connected) {
this._connected = false;
this.onclose?.();
this._serverTransport.onclose?.();
}
}
_receiveFromServer(message, extra) {
this.onmessage?.(message, extra);
}
}
class InProcessServerTransport {
constructor(clientTransport) {
this._clientTransport = clientTransport;
}
async start() {
}
async send(message, options) {
this._clientTransport._receiveFromServer(message);
}
async close() {
this.onclose?.();
}
_receiveFromClient(message) {
this.onmessage?.(message);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
InProcessTransport
});

223
backend/node_modules/playwright/lib/mcp/sdk/server.js generated vendored Normal file
View file

@ -0,0 +1,223 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var server_exports = {};
__export(server_exports, {
allRootPaths: () => allRootPaths,
connect: () => connect,
createServer: () => createServer,
firstRootPath: () => firstRootPath,
start: () => start,
wrapInClient: () => wrapInClient,
wrapInProcess: () => wrapInProcess
});
module.exports = __toCommonJS(server_exports);
var import_url = require("url");
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var mcpBundle = __toESM(require("playwright-core/lib/mcpBundle"));
var import_http = require("./http");
var import_inProcessTransport = require("./inProcessTransport");
const serverDebug = (0, import_utilsBundle.debug)("pw:mcp:server");
const serverDebugResponse = (0, import_utilsBundle.debug)("pw:mcp:server:response");
async function connect(factory, transport, runHeartbeat) {
const server = createServer(factory.name, factory.version, factory.create(), runHeartbeat);
await server.connect(transport);
}
function wrapInProcess(backend) {
const server = createServer("Internal", "0.0.0", backend, false);
return new import_inProcessTransport.InProcessTransport(server);
}
async function wrapInClient(backend, options) {
const server = createServer("Internal", "0.0.0", backend, false);
const transport = new import_inProcessTransport.InProcessTransport(server);
const client = new mcpBundle.Client({ name: options.name, version: options.version });
await client.connect(transport);
await client.ping();
return client;
}
function createServer(name, version, backend, runHeartbeat) {
const server = new mcpBundle.Server({ name, version }, {
capabilities: {
tools: {}
}
});
server.setRequestHandler(mcpBundle.ListToolsRequestSchema, async () => {
serverDebug("listTools");
const tools = await backend.listTools();
return { tools };
});
let initializePromise;
server.setRequestHandler(mcpBundle.CallToolRequestSchema, async (request, extra) => {
serverDebug("callTool", request);
const progressToken = request.params._meta?.progressToken;
let progressCounter = 0;
const progress = progressToken ? (params) => {
extra.sendNotification({
method: "notifications/progress",
params: {
progressToken,
progress: params.progress ?? ++progressCounter,
total: params.total,
message: params.message
}
}).catch(serverDebug);
} : () => {
};
try {
if (!initializePromise)
initializePromise = initializeServer(server, backend, runHeartbeat);
await initializePromise;
const toolResult = await backend.callTool(request.params.name, request.params.arguments || {}, progress);
const mergedResult = mergeTextParts(toolResult);
serverDebugResponse("callResult", mergedResult);
return mergedResult;
} catch (error) {
return {
content: [{ type: "text", text: "### Result\n" + String(error) }],
isError: true
};
}
});
addServerListener(server, "close", () => backend.serverClosed?.(server));
return server;
}
const initializeServer = async (server, backend, runHeartbeat) => {
const capabilities = server.getClientCapabilities();
let clientRoots = [];
if (capabilities?.roots) {
const { roots } = await server.listRoots().catch((e) => {
serverDebug(e);
return { roots: [] };
});
clientRoots = roots;
}
const clientInfo = {
name: server.getClientVersion()?.name ?? "unknown",
version: server.getClientVersion()?.version ?? "unknown",
roots: clientRoots,
timestamp: Date.now()
};
await backend.initialize?.(clientInfo);
if (runHeartbeat)
startHeartbeat(server);
};
const startHeartbeat = (server) => {
const beat = () => {
Promise.race([
server.ping(),
new Promise((_, reject) => setTimeout(() => reject(new Error("ping timeout")), 5e3))
]).then(() => {
setTimeout(beat, 3e3);
}).catch(() => {
void server.close();
});
};
beat();
};
function addServerListener(server, event, listener) {
const oldListener = server[`on${event}`];
server[`on${event}`] = () => {
oldListener?.();
listener();
};
}
async function start(serverBackendFactory, options) {
if (options.port === void 0) {
await connect(serverBackendFactory, new mcpBundle.StdioServerTransport(), false);
return;
}
const url = await (0, import_http.startMcpHttpServer)(options, serverBackendFactory, options.allowedHosts);
const mcpConfig = { mcpServers: {} };
mcpConfig.mcpServers[serverBackendFactory.nameInConfig] = {
url: `${url}/mcp`
};
const message = [
`Listening on ${url}`,
"Put this in your client config:",
JSON.stringify(mcpConfig, void 0, 2),
"For legacy SSE transport support, you can use the /sse endpoint instead."
].join("\n");
console.error(message);
}
function firstRootPath(clientInfo) {
if (clientInfo.roots.length === 0)
return void 0;
const firstRootUri = clientInfo.roots[0]?.uri;
const url = firstRootUri ? new URL(firstRootUri) : void 0;
try {
return url ? (0, import_url.fileURLToPath)(url) : void 0;
} catch (error) {
serverDebug(error);
return void 0;
}
}
function allRootPaths(clientInfo) {
const paths = [];
for (const root of clientInfo.roots) {
try {
const url = new URL(root.uri);
const path = (0, import_url.fileURLToPath)(url);
if (path)
paths.push(path);
} catch (error) {
serverDebug(error);
}
}
return paths;
}
function mergeTextParts(result) {
const content = [];
const testParts = [];
for (const part of result.content) {
if (part.type === "text") {
testParts.push(part.text);
continue;
}
if (testParts.length > 0) {
content.push({ type: "text", text: testParts.join("\n") });
testParts.length = 0;
}
content.push(part);
}
if (testParts.length > 0)
content.push({ type: "text", text: testParts.join("\n") });
return {
...result,
content
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
allRootPaths,
connect,
createServer,
firstRootPath,
start,
wrapInClient,
wrapInProcess
});

47
backend/node_modules/playwright/lib/mcp/sdk/tool.js generated vendored Normal file
View file

@ -0,0 +1,47 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tool_exports = {};
__export(tool_exports, {
defineToolSchema: () => defineToolSchema,
toMcpTool: () => toMcpTool
});
module.exports = __toCommonJS(tool_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
function toMcpTool(tool) {
const readOnly = tool.type === "readOnly" || tool.type === "assertion";
return {
name: tool.name,
description: tool.description,
inputSchema: import_mcpBundle.z.toJSONSchema(tool.inputSchema),
annotations: {
title: tool.title,
readOnlyHint: readOnly,
destructiveHint: !readOnly,
openWorldHint: true
}
};
}
function defineToolSchema(tool) {
return tool;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
defineToolSchema,
toMcpTool
});

296
backend/node_modules/playwright/lib/mcp/terminal/cli.js generated vendored Normal file
View file

@ -0,0 +1,296 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var import_child_process = require("child_process");
var import_crypto = __toESM(require("crypto"));
var import_fs = __toESM(require("fs"));
var import_net = __toESM(require("net"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_socketConnection = require("./socketConnection");
const debugCli = (0, import_utilsBundle.debug)("pw:cli");
const packageJSON = require("../../../package.json");
async function runCliCommand(sessionName, args) {
const session = await connectToDaemon(sessionName);
const result = await session.runCliCommand(args);
console.log(result);
session.dispose();
}
async function socketExists(socketPath) {
try {
const stat = await import_fs.default.promises.stat(socketPath);
if (stat?.isSocket())
return true;
} catch (e) {
}
return false;
}
class SocketSession {
constructor(connection) {
this._nextMessageId = 1;
this._callbacks = /* @__PURE__ */ new Map();
this._connection = connection;
this._connection.onmessage = (message) => this._onMessage(message);
this._connection.onclose = () => this.dispose();
}
async callTool(name, args) {
return this._send(name, args);
}
async runCliCommand(args) {
return await this._send("runCliCommand", { args });
}
async _send(method, params = {}) {
const messageId = this._nextMessageId++;
const message = {
id: messageId,
method,
params
};
await this._connection.send(message);
return new Promise((resolve, reject) => {
this._callbacks.set(messageId, { resolve, reject });
});
}
dispose() {
for (const callback of this._callbacks.values())
callback.reject(new Error("Disposed"));
this._callbacks.clear();
this._connection.close();
}
_onMessage(object) {
if (object.id && this._callbacks.has(object.id)) {
const callback = this._callbacks.get(object.id);
this._callbacks.delete(object.id);
if (object.error)
callback.reject(new Error(object.error));
else
callback.resolve(object.result);
} else if (object.id) {
throw new Error(`Unexpected message id: ${object.id}`);
} else {
throw new Error(`Unexpected message without id: ${JSON.stringify(object)}`);
}
}
}
function localCacheDir() {
if (process.platform === "linux")
return process.env.XDG_CACHE_HOME || import_path.default.join(import_os.default.homedir(), ".cache");
if (process.platform === "darwin")
return import_path.default.join(import_os.default.homedir(), "Library", "Caches");
if (process.platform === "win32")
return process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local");
throw new Error("Unsupported platform: " + process.platform);
}
function playwrightCacheDir() {
return import_path.default.join(localCacheDir(), "ms-playwright");
}
function calculateSha1(buffer) {
const hash = import_crypto.default.createHash("sha1");
hash.update(buffer);
return hash.digest("hex");
}
function socketDirHash() {
return calculateSha1(__dirname);
}
function daemonSocketDir() {
return import_path.default.resolve(playwrightCacheDir(), "daemon", socketDirHash());
}
function daemonSocketPath(sessionName) {
const socketName = `${sessionName}.sock`;
if (import_os.default.platform() === "win32")
return `\\\\.\\pipe\\${socketDirHash()}-${socketName}`;
return import_path.default.resolve(daemonSocketDir(), socketName);
}
async function connectToDaemon(sessionName) {
const socketPath = daemonSocketPath(sessionName);
debugCli(`Connecting to daemon at ${socketPath}`);
if (await socketExists(socketPath)) {
debugCli(`Socket file exists, attempting to connect...`);
try {
return await connectToSocket(socketPath);
} catch (e) {
if (import_os.default.platform() !== "win32")
await import_fs.default.promises.unlink(socketPath).catch(() => {
});
}
}
const cliPath = import_path.default.join(__dirname, "../../../cli.js");
debugCli(`Will launch daemon process: ${cliPath}`);
const userDataDir = import_path.default.resolve(daemonSocketDir(), `${sessionName}-user-data`);
const child = (0, import_child_process.spawn)(process.execPath, [cliPath, "run-mcp-server", `--daemon=${socketPath}`, `--user-data-dir=${userDataDir}`], {
detached: true,
stdio: "ignore",
cwd: process.cwd()
// Will be used as root.
});
child.unref();
const maxRetries = 50;
const retryDelay = 100;
for (let i = 0; i < maxRetries; i++) {
await new Promise((resolve) => setTimeout(resolve, 100));
try {
return await connectToSocket(socketPath);
} catch (e) {
if (e.code !== "ENOENT")
throw e;
debugCli(`Retrying to connect to daemon at ${socketPath} (${i + 1}/${maxRetries})`);
}
}
throw new Error(`Failed to connect to daemon at ${socketPath} after ${maxRetries * retryDelay}ms`);
}
async function connectToSocket(socketPath) {
const socket = await new Promise((resolve, reject) => {
const socket2 = import_net.default.createConnection(socketPath, () => {
debugCli(`Connected to daemon at ${socketPath}`);
resolve(socket2);
});
socket2.on("error", reject);
});
return new SocketSession(new import_socketConnection.SocketConnection(socket));
}
function currentSessionPath() {
return import_path.default.resolve(daemonSocketDir(), "current-session");
}
async function getCurrentSession() {
try {
const session = await import_fs.default.promises.readFile(currentSessionPath(), "utf-8");
return session.trim() || "default";
} catch {
return "default";
}
}
async function setCurrentSession(sessionName) {
await import_fs.default.promises.mkdir(daemonSocketDir(), { recursive: true });
await import_fs.default.promises.writeFile(currentSessionPath(), sessionName);
}
async function canConnectToSocket(socketPath) {
return new Promise((resolve) => {
const socket = import_net.default.createConnection(socketPath, () => {
socket.destroy();
resolve(true);
});
socket.on("error", () => {
resolve(false);
});
});
}
async function listSessions() {
const dir = daemonSocketDir();
try {
const files = await import_fs.default.promises.readdir(dir);
const sessions = [];
for (const file of files) {
if (file.endsWith("-user-data")) {
const sessionName = file.slice(0, -"-user-data".length);
const socketPath = daemonSocketPath(sessionName);
const live = await canConnectToSocket(socketPath);
sessions.push({ name: sessionName, live });
}
}
return sessions;
} catch {
return [];
}
}
function resolveSessionName(args) {
if (args.session)
return args.session;
if (process.env.PLAYWRIGHT_CLI_SESSION)
return process.env.PLAYWRIGHT_CLI_SESSION;
return "default";
}
async function handleSessionCommand(args) {
const subcommand = args._[1];
if (!subcommand) {
const current = await getCurrentSession();
console.log(current);
return;
}
if (subcommand === "list") {
const sessions = await listSessions();
const current = await getCurrentSession();
console.log("Sessions:");
for (const session of sessions) {
const marker = session.name === current ? "->" : " ";
const liveMarker = session.live ? " (live)" : "";
console.log(`${marker} ${session.name}${liveMarker}`);
}
if (sessions.length === 0)
console.log(" (no sessions)");
return;
}
if (subcommand === "set") {
const sessionName = args._[2];
if (!sessionName) {
console.error("Usage: playwright-cli session set <session-name>");
process.exit(1);
}
await setCurrentSession(sessionName);
console.log(`Current session set to: ${sessionName}`);
return;
}
console.error(`Unknown session subcommand: ${subcommand}`);
process.exit(1);
}
async function main() {
const argv = process.argv.slice(2);
const args = require("minimist")(argv);
const help = require("./help.json");
const commandName = args._[0];
if (args.version || args.v) {
console.log(packageJSON.version);
process.exit(0);
}
if (commandName === "session") {
await handleSessionCommand(args);
return;
}
const command = help.commands[commandName];
if (args.help || args.h) {
if (command) {
console.log(command);
} else {
console.log("playwright-cli - run playwright mcp commands from terminal\n");
console.log(help.global);
}
process.exit(0);
}
if (!command) {
console.error(`Unknown command: ${commandName}
`);
console.log(help.global);
process.exit(1);
}
let sessionName = resolveSessionName(args);
if (sessionName === "default" && !args.session && !process.env.PLAYWRIGHT_CLI_SESSION)
sessionName = await getCurrentSession();
runCliCommand(sessionName, args).catch((e) => {
console.error(e.message);
process.exit(1);
});
}
main().catch((e) => {
console.error(e.message);
process.exit(1);
});

View file

@ -0,0 +1,56 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var command_exports = {};
__export(command_exports, {
declareCommand: () => declareCommand,
parseCommand: () => parseCommand
});
module.exports = __toCommonJS(command_exports);
function declareCommand(command) {
return command;
}
function parseCommand(command, args) {
const shape = command.args ? command.args.shape : {};
const argv = args["_"];
const options = command.options?.parse({ ...args, _: void 0 }) ?? {};
const argsObject = {};
let i = 0;
for (const name of Object.keys(shape))
argsObject[name] = argv[++i];
let parsedArgsObject = {};
try {
parsedArgsObject = command.args?.parse(argsObject) ?? {};
} catch (e) {
throw new Error(formatZodError(e));
}
const toolName = typeof command.toolName === "function" ? command.toolName(parsedArgsObject, options) : command.toolName;
const toolParams = command.toolParams(parsedArgsObject, options);
return { toolName, toolParams };
}
function formatZodError(error) {
const issue = error.issues[0];
if (issue.code === "invalid_type")
return `${issue.message} in <${issue.path.join(".")}>`;
return error.issues.map((i) => i.message).join("\n");
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
declareCommand,
parseCommand
});

View file

@ -0,0 +1,333 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var commands_exports = {};
__export(commands_exports, {
commands: () => commands
});
module.exports = __toCommonJS(commands_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_command = require("./command");
const click = (0, import_command.declareCommand)({
name: "click",
description: "Perform click on a web page",
args: import_mcpBundle.z.object({
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
}),
options: import_mcpBundle.z.object({
button: import_mcpBundle.z.string().optional().describe("Button to click, defaults to left"),
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.string()).optional().describe("Modifier keys to press")
}),
toolName: "browser_click",
toolParams: ({ ref }, { button, modifiers }) => ({ ref, button, modifiers })
});
const doubleClick = (0, import_command.declareCommand)({
name: "dblclick",
description: "Perform double click on a web page",
args: import_mcpBundle.z.object({
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
}),
options: import_mcpBundle.z.object({
button: import_mcpBundle.z.string().optional().describe("Button to click, defaults to left"),
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.string()).optional().describe("Modifier keys to press")
}),
toolName: "browser_click",
toolParams: ({ ref }, { button, modifiers }) => ({ ref, button, modifiers, doubleClick: true })
});
const close = (0, import_command.declareCommand)({
name: "close",
description: "Close the page",
args: import_mcpBundle.z.object({}),
toolName: "browser_close",
toolParams: () => ({})
});
const consoleMessages = (0, import_command.declareCommand)({
name: "console",
description: "Returns all console messages",
args: import_mcpBundle.z.object({
level: import_mcpBundle.z.string().optional().describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".')
}),
toolName: "browser_console_messages",
toolParams: ({ level }) => ({ level })
});
const drag = (0, import_command.declareCommand)({
name: "drag",
description: "Perform drag and drop between two elements",
args: import_mcpBundle.z.object({
startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
endRef: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
}),
options: import_mcpBundle.z.object({
headed: import_mcpBundle.z.boolean().default(false).describe("Run browser in headed mode")
}),
toolName: "browser_drag",
toolParams: ({ startRef, endRef }) => ({ startRef, endRef })
});
const evaluate = (0, import_command.declareCommand)({
name: "evaluate",
description: "Evaluate JavaScript expression on page or element",
args: import_mcpBundle.z.object({
function: import_mcpBundle.z.string().describe("() => { /* code */ } or (element) => { /* code */ } when element is provided"),
ref: import_mcpBundle.z.string().optional().describe("Exact target element reference from the page snapshot")
}),
toolName: "browser_evaluate",
toolParams: ({ function: fn, ref }) => ({ function: fn, ref })
});
const fileUpload = (0, import_command.declareCommand)({
name: "upload-file",
description: "Upload one or multiple files",
args: import_mcpBundle.z.object({}),
options: import_mcpBundle.z.object({
paths: import_mcpBundle.z.array(import_mcpBundle.z.string()).optional().describe("The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.")
}),
toolName: "browser_file_upload",
toolParams: (_, { paths }) => ({ paths })
});
const handleDialog = (0, import_command.declareCommand)({
name: "handle-dialog",
description: "Handle a dialog",
args: import_mcpBundle.z.object({
accept: import_mcpBundle.z.boolean().describe("Whether to accept the dialog."),
promptText: import_mcpBundle.z.string().optional().describe("The text of the prompt in case of a prompt dialog.")
}),
toolName: "browser_handle_dialog",
toolParams: ({ accept, promptText }) => ({ accept, promptText })
});
const hover = (0, import_command.declareCommand)({
name: "hover",
description: "Hover over element on page",
args: import_mcpBundle.z.object({
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
}),
toolName: "browser_hover",
toolParams: ({ ref }) => ({ ref })
});
const open = (0, import_command.declareCommand)({
name: "open",
description: "Open URL",
args: import_mcpBundle.z.object({
url: import_mcpBundle.z.string().describe("The URL to navigate to")
}),
options: import_mcpBundle.z.object({
headed: import_mcpBundle.z.boolean().default(false).describe("Run browser in headed mode")
}),
toolName: "browser_open",
toolParams: ({ url }, { headed }) => ({ url, headed })
});
const navigateBack = (0, import_command.declareCommand)({
name: "go-back",
description: "Go back to the previous page",
args: import_mcpBundle.z.object({}),
toolName: "browser_navigate_back",
toolParams: () => ({})
});
const networkRequests = (0, import_command.declareCommand)({
name: "network-requests",
description: "Returns all network requests since loading the page",
args: import_mcpBundle.z.object({}),
options: import_mcpBundle.z.object({
includeStatic: import_mcpBundle.z.boolean().optional().describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.")
}),
toolName: "browser_network_requests",
toolParams: (_, { includeStatic }) => ({ includeStatic })
});
const pressKey = (0, import_command.declareCommand)({
name: "press",
description: "Press a key on the keyboard",
args: import_mcpBundle.z.object({
key: import_mcpBundle.z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`")
}),
toolName: "browser_press_key",
toolParams: ({ key }) => ({ key })
});
const resize = (0, import_command.declareCommand)({
name: "resize",
description: "Resize the browser window",
args: import_mcpBundle.z.object({
width: import_mcpBundle.z.number().describe("Width of the browser window"),
height: import_mcpBundle.z.number().describe("Height of the browser window")
}),
toolName: "browser_resize",
toolParams: ({ width, height }) => ({ width, height })
});
const runCode = (0, import_command.declareCommand)({
name: "run-code",
description: "Run Playwright code snippet",
args: import_mcpBundle.z.object({
code: import_mcpBundle.z.string().describe("A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction.")
}),
toolName: "browser_run_code",
toolParams: ({ code }) => ({ code })
});
const selectOption = (0, import_command.declareCommand)({
name: "select-option",
description: "Select an option in a dropdown",
args: import_mcpBundle.z.object({
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot"),
values: import_mcpBundle.z.array(import_mcpBundle.z.string()).describe("Array of values to select in the dropdown. This can be a single value or multiple values.")
}),
toolName: "browser_select_option",
toolParams: ({ ref, values }) => ({ ref, values })
});
const snapshot = (0, import_command.declareCommand)({
name: "snapshot",
description: "Capture accessibility snapshot of the current page, this is better than screenshot",
args: import_mcpBundle.z.object({}),
options: import_mcpBundle.z.object({
filename: import_mcpBundle.z.string().optional().describe("Save snapshot to markdown file instead of returning it in the response.")
}),
toolName: "browser_snapshot",
toolParams: (_, { filename }) => ({ filename })
});
const screenshot = (0, import_command.declareCommand)({
name: "screenshot",
description: "Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.",
args: import_mcpBundle.z.object({
ref: import_mcpBundle.z.string().optional().describe("Exact target element reference from the page snapshot.")
}),
options: import_mcpBundle.z.object({
filename: import_mcpBundle.z.string().optional().describe("File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified."),
fullPage: import_mcpBundle.z.boolean().optional().describe("When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport.")
}),
toolName: "browser_take_screenshot",
toolParams: ({ ref }, { filename, fullPage }) => ({ filename, ref, fullPage })
});
const type = (0, import_command.declareCommand)({
name: "type",
description: "Type text into editable element",
args: import_mcpBundle.z.object({
text: import_mcpBundle.z.string().describe("Text to type into the element")
}),
options: import_mcpBundle.z.object({
submit: import_mcpBundle.z.boolean().optional().describe("Whether to submit entered text (press Enter after)")
}),
toolName: "browser_press_sequentially",
toolParams: ({ text }, { submit }) => ({ text, submit })
});
const waitFor = (0, import_command.declareCommand)({
name: "wait-for",
description: "Wait for text to appear or disappear or a specified time to pass",
args: import_mcpBundle.z.object({}),
options: import_mcpBundle.z.object({
time: import_mcpBundle.z.number().optional().describe("The time to wait in seconds"),
text: import_mcpBundle.z.string().optional().describe("The text to wait for"),
textGone: import_mcpBundle.z.string().optional().describe("The text to wait for to disappear")
}),
toolName: "browser_wait_for",
toolParams: (_, { time, text, textGone }) => ({ time, text, textGone })
});
const tab = (0, import_command.declareCommand)({
name: "tab",
description: "Close a browser tab",
args: import_mcpBundle.z.object({
action: import_mcpBundle.z.string().describe(`Action to perform on tabs, 'list' | 'new' | 'close' | 'select'`),
index: import_mcpBundle.z.number().optional().describe("Tab index. If omitted, current tab is closed.")
}),
toolName: "browser_tabs",
toolParams: ({ action, index }) => ({ action, index })
});
const mouseClickXy = (0, import_command.declareCommand)({
name: "mouse-click-xy",
description: "Click left mouse button at a given position",
args: import_mcpBundle.z.object({
x: import_mcpBundle.z.number().describe("X coordinate"),
y: import_mcpBundle.z.number().describe("Y coordinate")
}),
toolName: "browser_mouse_click_xy",
toolParams: ({ x, y }) => ({ x, y })
});
const mouseDragXy = (0, import_command.declareCommand)({
name: "mouse-drag-xy",
description: "Drag left mouse button to a given position",
args: import_mcpBundle.z.object({
startX: import_mcpBundle.z.number().describe("Start X coordinate"),
startY: import_mcpBundle.z.number().describe("Start Y coordinate"),
endX: import_mcpBundle.z.number().describe("End X coordinate"),
endY: import_mcpBundle.z.number().describe("End Y coordinate")
}),
toolName: "browser_mouse_drag_xy",
toolParams: ({ startX, startY, endX, endY }) => ({ startX, startY, endX, endY })
});
const mouseMoveXy = (0, import_command.declareCommand)({
name: "mouse-move-xy",
description: "Move mouse to a given position",
args: import_mcpBundle.z.object({
x: import_mcpBundle.z.number().describe("X coordinate"),
y: import_mcpBundle.z.number().describe("Y coordinate")
}),
toolName: "browser_mouse_move_xy",
toolParams: ({ x, y }) => ({ x, y })
});
const pdfSave = (0, import_command.declareCommand)({
name: "pdf-save",
description: "Save page as PDF",
args: import_mcpBundle.z.object({}),
options: import_mcpBundle.z.object({
filename: import_mcpBundle.z.string().optional().describe("File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.")
}),
toolName: "browser_pdf_save",
toolParams: (_, { filename }) => ({ filename })
});
const startTracing = (0, import_command.declareCommand)({
name: "start-tracing",
description: "Start trace recording",
args: import_mcpBundle.z.object({}),
toolName: "browser_start_tracing",
toolParams: () => ({})
});
const stopTracing = (0, import_command.declareCommand)({
name: "stop-tracing",
description: "Stop trace recording",
args: import_mcpBundle.z.object({}),
toolName: "browser_stop_tracing",
toolParams: () => ({})
});
const commandsArray = [
click,
close,
doubleClick,
consoleMessages,
drag,
evaluate,
fileUpload,
handleDialog,
hover,
open,
navigateBack,
networkRequests,
pressKey,
resize,
runCode,
selectOption,
snapshot,
screenshot,
type,
waitFor,
tab,
mouseClickXy,
mouseDragXy,
mouseMoveXy,
pdfSave,
startTracing,
stopTracing
];
const commands = Object.fromEntries(commandsArray.map((cmd) => [cmd.name, cmd]));
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
commands
});

View file

@ -0,0 +1,129 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var daemon_exports = {};
__export(daemon_exports, {
startMcpDaemonServer: () => startMcpDaemonServer
});
module.exports = __toCommonJS(daemon_exports);
var import_promises = __toESM(require("fs/promises"));
var import_net = __toESM(require("net"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_url = __toESM(require("url"));
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
var import_socketConnection = require("./socketConnection");
var import_commands = require("./commands");
var import_command = require("./command");
const daemonDebug = (0, import_utilsBundle.debug)("pw:daemon");
async function socketExists(socketPath) {
try {
const stat = await import_promises.default.stat(socketPath);
if (stat?.isSocket())
return true;
} catch (e) {
}
return false;
}
async function startMcpDaemonServer(socketPath, serverBackendFactory) {
if (import_os.default.platform() !== "win32" && await socketExists(socketPath)) {
daemonDebug(`Socket already exists, removing: ${socketPath}`);
try {
await import_promises.default.unlink(socketPath);
} catch (error) {
daemonDebug(`Failed to remove existing socket: ${error}`);
throw error;
}
}
const backend = serverBackendFactory.create();
const cwd = import_url.default.pathToFileURL(process.cwd()).href;
await backend.initialize?.({
name: "playwright-cli",
version: "1.0.0",
roots: [{
uri: cwd,
name: "cwd"
}],
timestamp: Date.now()
});
await import_promises.default.mkdir(import_path.default.dirname(socketPath), { recursive: true });
const server = import_net.default.createServer((socket) => {
daemonDebug("new client connection");
const connection = new import_socketConnection.SocketConnection(socket);
connection.onclose = () => {
daemonDebug("client disconnected");
};
connection.onmessage = async (message) => {
const { id, method, params } = message;
try {
daemonDebug("received command", method);
if (method === "runCliCommand") {
const { toolName, toolParams } = parseCliCommand(params.args);
const response = await backend.callTool(toolName, toolParams, () => {
});
await connection.send({ id, result: formatResult(response) });
} else {
throw new Error(`Unknown method: ${method}`);
}
} catch (e) {
daemonDebug("command failed", e);
await connection.send({ id, error: e.message });
}
};
});
return new Promise((resolve, reject) => {
server.on("error", (error) => {
daemonDebug(`server error: ${error.message}`);
reject(error);
});
server.listen(socketPath, () => {
daemonDebug(`daemon server listening on ${socketPath}`);
resolve(socketPath);
});
});
}
function formatResult(result) {
const lines = [];
for (const content of result.content) {
if (content.type === "text")
lines.push(content.text);
else
lines.push(`<${content.type} content>`);
}
return lines.join("\n");
}
function parseCliCommand(args) {
const command = import_commands.commands[args._[0]];
if (!command)
throw new Error("Command is required");
return (0, import_command.parseCommand)(command, args);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
startMcpDaemonServer
});

View file

@ -0,0 +1,32 @@
{
"global": "Usage: playwright-cli <command> [options]\nCommands:\n click <ref> perform click on a web page\n close close the page\n dblclick <ref> perform double click on a web page\n console <level> returns all console messages\n drag <startRef> <endRef> perform drag and drop between two elements\n evaluate <function> <ref> evaluate javascript expression on page or element\n upload-file upload one or multiple files\n handle-dialog <accept> <promptText> handle a dialog\n hover <ref> hover over element on page\n open <url> open url\n go-back go back to the previous page\n network-requests returns all network requests since loading the page\n press <key> press a key on the keyboard\n resize <width> <height> resize the browser window\n run-code <code> run playwright code snippet\n select-option <ref> <values> select an option in a dropdown\n snapshot capture accessibility snapshot of the current page, this is better than screenshot\n screenshot <ref> take a screenshot of the current page. you can't perform actions based on the screenshot, use browser_snapshot for actions.\n type <text> type text into editable element\n wait-for wait for text to appear or disappear or a specified time to pass\n tab <action> <index> close a browser tab\n mouse-click-xy <x> <y> click left mouse button at a given position\n mouse-drag-xy <startX> <startY> <endX> <endY> drag left mouse button to a given position\n mouse-move-xy <x> <y> move mouse to a given position\n pdf-save save page as pdf\n start-tracing start trace recording\n stop-tracing stop trace recording",
"commands": {
"click": "playwright-cli click <ref>\n\nPerform click on a web page\n\nArguments:\n <ref>\tExact target element reference from the page snapshot\nOptions:\n --button\tbutton to click, defaults to left\n --modifiers\tmodifier keys to press",
"close": "playwright-cli close \n\nClose the page\n",
"dblclick": "playwright-cli dblclick <ref>\n\nPerform double click on a web page\n\nArguments:\n <ref>\tExact target element reference from the page snapshot\nOptions:\n --button\tbutton to click, defaults to left\n --modifiers\tmodifier keys to press",
"console": "playwright-cli console <level>\n\nReturns all console messages\n\nArguments:\n <level>\tLevel of the console messages to return. Each level includes the messages of more severe levels. Defaults to \"info\".",
"drag": "playwright-cli drag <startRef> <endRef>\n\nPerform drag and drop between two elements\n\nArguments:\n <startRef>\tExact source element reference from the page snapshot\n <endRef>\tExact target element reference from the page snapshot\nOptions:\n --headed\trun browser in headed mode",
"evaluate": "playwright-cli evaluate <function> <ref>\n\nEvaluate JavaScript expression on page or element\n\nArguments:\n <function>\t() => { /* code */ } or (element) => { /* code */ } when element is provided\n <ref>\tExact target element reference from the page snapshot",
"upload-file": "playwright-cli upload-file \n\nUpload one or multiple files\n\nOptions:\n --paths\tthe absolute paths to the files to upload. can be single file or multiple files. if omitted, file chooser is cancelled.",
"handle-dialog": "playwright-cli handle-dialog <accept> <promptText>\n\nHandle a dialog\n\nArguments:\n <accept>\tWhether to accept the dialog.\n <promptText>\tThe text of the prompt in case of a prompt dialog.",
"hover": "playwright-cli hover <ref>\n\nHover over element on page\n\nArguments:\n <ref>\tExact target element reference from the page snapshot",
"open": "playwright-cli open <url>\n\nOpen URL\n\nArguments:\n <url>\tThe URL to navigate to\nOptions:\n --headed\trun browser in headed mode",
"go-back": "playwright-cli go-back \n\nGo back to the previous page\n",
"network-requests": "playwright-cli network-requests \n\nReturns all network requests since loading the page\n\nOptions:\n --includeStatic\twhether to include successful static resources like images, fonts, scripts, etc. defaults to false.",
"press": "playwright-cli press <key>\n\nPress a key on the keyboard\n\nArguments:\n <key>\tName of the key to press or a character to generate, such as `ArrowLeft` or `a`",
"resize": "playwright-cli resize <width> <height>\n\nResize the browser window\n\nArguments:\n <width>\tWidth of the browser window\n <height>\tHeight of the browser window",
"run-code": "playwright-cli run-code <code>\n\nRun Playwright code snippet\n\nArguments:\n <code>\tA JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction.",
"select-option": "playwright-cli select-option <ref> <values>\n\nSelect an option in a dropdown\n\nArguments:\n <ref>\tExact target element reference from the page snapshot\n <values>\tArray of values to select in the dropdown. This can be a single value or multiple values.",
"snapshot": "playwright-cli snapshot \n\nCapture accessibility snapshot of the current page, this is better than screenshot\n\nOptions:\n --filename\tsave snapshot to markdown file instead of returning it in the response.",
"screenshot": "playwright-cli screenshot <ref>\n\nTake a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.\n\nArguments:\n <ref>\tExact target element reference from the page snapshot.\nOptions:\n --filename\tfile name to save the screenshot to. defaults to `page-{timestamp}.{png|jpeg}` if not specified.\n --fullPage\twhen true, takes a screenshot of the full scrollable page, instead of the currently visible viewport.",
"type": "playwright-cli type <text>\n\nType text into editable element\n\nArguments:\n <text>\tText to type into the element\nOptions:\n --submit\twhether to submit entered text (press enter after)",
"wait-for": "playwright-cli wait-for \n\nWait for text to appear or disappear or a specified time to pass\n\nOptions:\n --time\tthe time to wait in seconds\n --text\tthe text to wait for\n --textGone\tthe text to wait for to disappear",
"tab": "playwright-cli tab <action> <index>\n\nClose a browser tab\n\nArguments:\n <action>\tAction to perform on tabs, 'list' | 'new' | 'close' | 'select'\n <index>\tTab index. If omitted, current tab is closed.",
"mouse-click-xy": "playwright-cli mouse-click-xy <x> <y>\n\nClick left mouse button at a given position\n\nArguments:\n <x>\tX coordinate\n <y>\tY coordinate",
"mouse-drag-xy": "playwright-cli mouse-drag-xy <startX> <startY> <endX> <endY>\n\nDrag left mouse button to a given position\n\nArguments:\n <startX>\tStart X coordinate\n <startY>\tStart Y coordinate\n <endX>\tEnd X coordinate\n <endY>\tEnd Y coordinate",
"mouse-move-xy": "playwright-cli mouse-move-xy <x> <y>\n\nMove mouse to a given position\n\nArguments:\n <x>\tX coordinate\n <y>\tY coordinate",
"pdf-save": "playwright-cli pdf-save \n\nSave page as PDF\n\nOptions:\n --filename\tfile name to save the pdf to. defaults to `page-{timestamp}.pdf` if not specified.",
"start-tracing": "playwright-cli start-tracing \n\nStart trace recording\n",
"stop-tracing": "playwright-cli stop-tracing \n\nStop trace recording\n"
}
}

View file

@ -0,0 +1,88 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_commands = require("./commands");
function generateCommandHelp(command) {
const args = [];
const shape = command.args ? command.args.shape : {};
for (const [name, schema] of Object.entries(shape)) {
const zodSchema = schema;
const description = zodSchema.description ?? "";
args.push({ name, description });
}
const lines = [
`playwright-cli ${command.name} ${Object.keys(shape).map((k) => `<${k}>`).join(" ")}`,
"",
command.description,
""
];
if (args.length) {
lines.push("Arguments:");
lines.push(...args.map(({ name, description }) => ` <${name}> ${description}`));
}
if (command.options) {
lines.push("Options:");
const optionsShape = command.options.shape;
for (const [name, schema] of Object.entries(optionsShape)) {
const zodSchema = schema;
const description = (zodSchema.description ?? "").toLowerCase();
lines.push(` --${name} ${description}`);
}
}
return lines.join("\n");
}
function generateHelp() {
const lines = [];
lines.push("Usage: playwright-cli <command> [options]");
lines.push("Commands:");
for (const command of Object.values(import_commands.commands))
lines.push(" " + generateHelpEntry(command));
return lines.join("\n");
}
function generateHelpEntry(command) {
const args = [];
const shape = command.args.shape;
for (const [name, schema] of Object.entries(shape)) {
const zodSchema = schema;
const description = zodSchema.description ?? "";
args.push({ name, description });
}
const prefix = `${command.name} ${Object.keys(shape).map((k) => `<${k}>`).join(" ")}`;
const suffix = command.description.toLowerCase();
const padding = " ".repeat(Math.max(1, 40 - prefix.length));
return prefix + padding + suffix;
}
async function main() {
const help = {
global: generateHelp(),
commands: Object.fromEntries(
Object.entries(import_commands.commands).map(([name, command]) => [name, generateCommandHelp(command)])
)
};
const fileName = import_path.default.resolve(__dirname, "help.json").replace("lib", "src");
console.log("Writing ", import_path.default.relative(process.cwd(), fileName));
await import_fs.default.promises.writeFile(fileName, JSON.stringify(help, null, 2));
}
void main();

View file

@ -0,0 +1,80 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var socketConnection_exports = {};
__export(socketConnection_exports, {
SocketConnection: () => SocketConnection
});
module.exports = __toCommonJS(socketConnection_exports);
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
const daemonDebug = (0, import_utilsBundle.debug)("pw:daemon");
class SocketConnection {
constructor(socket) {
this._pendingBuffers = [];
this._socket = socket;
socket.on("data", (buffer) => this._onData(buffer));
socket.on("close", () => {
this.onclose?.();
});
socket.on("error", (e) => daemonDebug(`error: ${e.message}`));
}
async send(message) {
await new Promise((resolve, reject) => {
this._socket.write(`${JSON.stringify(message)}
`, (error) => {
if (error)
reject(error);
else
resolve(void 0);
});
});
}
close() {
this._socket.destroy();
}
_onData(buffer) {
let end = buffer.indexOf("\n");
if (end === -1) {
this._pendingBuffers.push(buffer);
return;
}
this._pendingBuffers.push(buffer.slice(0, end));
const message = Buffer.concat(this._pendingBuffers).toString();
this._dispatchMessage(message);
let start = end + 1;
end = buffer.indexOf("\n", start);
while (end !== -1) {
const message2 = buffer.toString(void 0, start, end);
this._dispatchMessage(message2);
start = end + 1;
end = buffer.indexOf("\n", start);
}
this._pendingBuffers = [buffer.slice(start)];
}
_dispatchMessage(message) {
try {
this.onmessage?.(JSON.parse(message));
} catch (e) {
daemonDebug("failed to dispatch message", e);
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SocketConnection
});

View file

@ -0,0 +1,98 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var browserBackend_exports = {};
__export(browserBackend_exports, {
createCustomMessageHandler: () => createCustomMessageHandler
});
module.exports = __toCommonJS(browserBackend_exports);
var import_config = require("../browser/config");
var import_browserServerBackend = require("../browser/browserServerBackend");
var import_tab = require("../browser/tab");
var import_util = require("../../util");
var import_browserContextFactory = require("../browser/browserContextFactory");
function createCustomMessageHandler(testInfo, context) {
let backend;
return async (data) => {
if (data.initialize) {
if (backend)
throw new Error("MCP backend is already initialized");
backend = new import_browserServerBackend.BrowserServerBackend({ ...import_config.defaultConfig, capabilities: ["testing"] }, (0, import_browserContextFactory.identityBrowserContextFactory)(context));
await backend.initialize(data.initialize.clientInfo);
const pausedMessage = await generatePausedMessage(testInfo, context);
return { initialize: { pausedMessage } };
}
if (data.listTools) {
if (!backend)
throw new Error("MCP backend is not initialized");
return { listTools: await backend.listTools() };
}
if (data.callTool) {
if (!backend)
throw new Error("MCP backend is not initialized");
return { callTool: await backend.callTool(data.callTool.name, data.callTool.arguments) };
}
if (data.close) {
backend?.serverClosed();
backend = void 0;
return { close: {} };
}
throw new Error("Unknown MCP request");
};
}
async function generatePausedMessage(testInfo, context) {
const lines = [];
if (testInfo.errors.length) {
lines.push(`### Paused on error:`);
for (const error of testInfo.errors)
lines.push((0, import_util.stripAnsiEscapes)(error.message || ""));
} else {
lines.push(`### Paused at end of test. ready for interaction`);
}
for (let i = 0; i < context.pages().length; i++) {
const page = context.pages()[i];
const stateSuffix = context.pages().length > 1 ? i + 1 + " of " + context.pages().length : "state";
lines.push(
"",
`### Page ${stateSuffix}`,
`- Page URL: ${page.url()}`,
`- Page Title: ${await page.title()}`.trim()
);
let console = testInfo.errors.length ? await import_tab.Tab.collectConsoleMessages(page) : [];
console = console.filter((msg) => msg.type === "error");
if (console.length) {
lines.push("- Console Messages:");
for (const message of console)
lines.push(` - ${message.toString()}`);
}
lines.push(
`- Page Snapshot:`,
"```yaml",
(await page._snapshotForAI()).full,
"```"
);
}
lines.push("");
if (testInfo.errors.length)
lines.push(`### Task`, `Try recovering from the error prior to continuing`);
return lines.join("\n");
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createCustomMessageHandler
});

View file

@ -0,0 +1,122 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var generatorTools_exports = {};
__export(generatorTools_exports, {
generatorReadLog: () => generatorReadLog,
generatorWriteTest: () => generatorWriteTest,
setupPage: () => setupPage
});
module.exports = __toCommonJS(generatorTools_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_testTool = require("./testTool");
var import_testContext = require("./testContext");
const setupPage = (0, import_testTool.defineTestTool)({
schema: {
name: "generator_setup_page",
title: "Setup generator page",
description: "Setup the page for test.",
inputSchema: import_mcpBundle.z.object({
plan: import_mcpBundle.z.string().describe("The plan for the test. This should be the actual test plan with all the steps."),
project: import_mcpBundle.z.string().optional().describe('Project to use for setup. For example: "chromium", if no project is provided uses the first project in the config.'),
seedFile: import_mcpBundle.z.string().optional().describe('A seed file contains a single test that is used to setup the page for testing, for example: "tests/seed.spec.ts". If no seed file is provided, a default seed file is created.')
}),
type: "readOnly"
},
handle: async (context, params) => {
const seed = await context.getOrCreateSeedFile(params.seedFile, params.project);
context.generatorJournal = new import_testContext.GeneratorJournal(context.rootPath, params.plan, seed);
const { output, status } = await context.runSeedTest(seed.file, seed.projectName);
return { content: [{ type: "text", text: output }], isError: status !== "paused" };
}
});
const generatorReadLog = (0, import_testTool.defineTestTool)({
schema: {
name: "generator_read_log",
title: "Retrieve test log",
description: "Retrieve the performed test log",
inputSchema: import_mcpBundle.z.object({}),
type: "readOnly"
},
handle: async (context) => {
if (!context.generatorJournal)
throw new Error(`Please setup page using "${setupPage.schema.name}" first.`);
const result = context.generatorJournal.journal();
return { content: [{
type: "text",
text: result
}] };
}
});
const generatorWriteTest = (0, import_testTool.defineTestTool)({
schema: {
name: "generator_write_test",
title: "Write test",
description: "Write the generated test to the test file",
inputSchema: import_mcpBundle.z.object({
fileName: import_mcpBundle.z.string().describe("The file to write the test to"),
code: import_mcpBundle.z.string().describe("The generated test code")
}),
type: "readOnly"
},
handle: async (context, params) => {
if (!context.generatorJournal)
throw new Error(`Please setup page using "${setupPage.schema.name}" first.`);
const testRunner = context.existingTestRunner();
if (!testRunner)
throw new Error("No test runner found, please setup page and perform actions first.");
const config = await testRunner.loadConfig();
const dirs = [];
for (const project of config.projects) {
const testDir = import_path.default.relative(context.rootPath, project.project.testDir).replace(/\\/g, "/");
const fileName = params.fileName.replace(/\\/g, "/");
if (fileName.startsWith(testDir)) {
const resolvedFile = import_path.default.resolve(context.rootPath, fileName);
await import_fs.default.promises.mkdir(import_path.default.dirname(resolvedFile), { recursive: true });
await import_fs.default.promises.writeFile(resolvedFile, params.code);
return {
content: [{
type: "text",
text: `### Result
Test written to ${params.fileName}`
}]
};
}
dirs.push(testDir);
}
throw new Error(`Test file did not match any of the test dirs: ${dirs.join(", ")}`);
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
generatorReadLog,
generatorWriteTest,
setupPage
});

View file

@ -0,0 +1,145 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var plannerTools_exports = {};
__export(plannerTools_exports, {
saveTestPlan: () => saveTestPlan,
setupPage: () => setupPage,
submitTestPlan: () => submitTestPlan
});
module.exports = __toCommonJS(plannerTools_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_testTool = require("./testTool");
const setupPage = (0, import_testTool.defineTestTool)({
schema: {
name: "planner_setup_page",
title: "Setup planner page",
description: "Setup the page for test planning",
inputSchema: import_mcpBundle.z.object({
project: import_mcpBundle.z.string().optional().describe('Project to use for setup. For example: "chromium", if no project is provided uses the first project in the config.'),
seedFile: import_mcpBundle.z.string().optional().describe('A seed file contains a single test that is used to setup the page for testing, for example: "tests/seed.spec.ts". If no seed file is provided, a default seed file is created.')
}),
type: "readOnly"
},
handle: async (context, params) => {
const seed = await context.getOrCreateSeedFile(params.seedFile, params.project);
const { output, status } = await context.runSeedTest(seed.file, seed.projectName);
return { content: [{ type: "text", text: output }], isError: status !== "paused" };
}
});
const planSchema = import_mcpBundle.z.object({
overview: import_mcpBundle.z.string().describe("A brief overview of the application to be tested"),
suites: import_mcpBundle.z.array(import_mcpBundle.z.object({
name: import_mcpBundle.z.string().describe("The name of the suite"),
seedFile: import_mcpBundle.z.string().describe("A seed file that was used to setup the page for testing."),
tests: import_mcpBundle.z.array(import_mcpBundle.z.object({
name: import_mcpBundle.z.string().describe("The name of the test"),
file: import_mcpBundle.z.string().describe('The file the test should be saved to, for example: "tests/<suite-name>/<test-name>.spec.ts".'),
steps: import_mcpBundle.z.array(import_mcpBundle.z.object({
perform: import_mcpBundle.z.string().optional().describe(`Action to perform. For example: 'Click on the "Submit" button'.`),
expect: import_mcpBundle.z.string().array().describe(`Expected result of the action where appropriate. For example: 'The page should show the "Thank you for your submission" message'`)
}))
}))
}))
});
const submitTestPlan = (0, import_testTool.defineTestTool)({
schema: {
name: "planner_submit_plan",
title: "Submit test plan",
description: "Submit the test plan to the test planner",
inputSchema: planSchema,
type: "readOnly"
},
handle: async (context, params) => {
return {
content: [{
type: "text",
text: JSON.stringify(params, null, 2)
}]
};
}
});
const saveTestPlan = (0, import_testTool.defineTestTool)({
schema: {
name: "planner_save_plan",
title: "Save test plan as markdown file",
description: "Save the test plan as a markdown file",
inputSchema: planSchema.extend({
name: import_mcpBundle.z.string().describe('The name of the test plan, for example: "Test Plan".'),
fileName: import_mcpBundle.z.string().describe('The file to save the test plan to, for example: "spec/test.plan.md". Relative to the workspace root.')
}),
type: "readOnly"
},
handle: async (context, params) => {
const lines = [];
lines.push(`# ${params.name}`);
lines.push(``);
lines.push(`## Application Overview`);
lines.push(``);
lines.push(params.overview);
lines.push(``);
lines.push(`## Test Scenarios`);
for (let i = 0; i < params.suites.length; i++) {
lines.push(``);
const suite = params.suites[i];
lines.push(`### ${i + 1}. ${suite.name}`);
lines.push(``);
lines.push(`**Seed:** \`${suite.seedFile}\``);
for (let j = 0; j < suite.tests.length; j++) {
lines.push(``);
const test = suite.tests[j];
lines.push(`#### ${i + 1}.${j + 1}. ${test.name}`);
lines.push(``);
lines.push(`**File:** \`${test.file}\``);
lines.push(``);
lines.push(`**Steps:**`);
for (let k = 0; k < test.steps.length; k++) {
lines.push(` ${k + 1}. ${test.steps[k].perform ?? "-"}`);
for (const expect of test.steps[k].expect)
lines.push(` - expect: ${expect}`);
}
}
}
lines.push(``);
await import_fs.default.promises.writeFile(import_path.default.resolve(context.rootPath, params.fileName), lines.join("\n"));
return {
content: [{
type: "text",
text: `Test plan saved to ${params.fileName}`
}]
};
}
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
saveTestPlan,
setupPage,
submitTestPlan
});

Some files were not shown because too many files have changed in this diff Show more