feat(cli): generate commands for conditional tools (#1962)

This PR adds all tools in the CLI interface. When a tool is not enabled
the server responds with an error guiding the user on how to enable the
category or the experiment.

Closes:
https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1933
This commit is contained in:
Nicholas Roscino
2026-04-30 09:59:08 +02:00
committed by GitHub
parent 7ee5e867ef
commit b2b3e99d67
19 changed files with 484 additions and 117 deletions
+1 -1
View File
@@ -398,7 +398,7 @@ in the DevTools Elements panel (if any).
## Extensions
> NOTE: Extensions are not active by default. Use the '--category-extensions' flag
> NOTE: Extensions are not active by default. Use the '--categoryExtensions' flag
### `install_extension`
+49 -15
View File
@@ -11,7 +11,12 @@ import {Client} from '@modelcontextprotocol/sdk/client/index.js';
import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';
import {parseArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';
import {labels} from '../build/src/tools/categories.js';
import {buildFlag} from '../build/src/index.js';
import {
labels,
ToolCategory,
OFF_BY_DEFAULT_CATEGORIES,
} from '../build/src/tools/categories.js';
import {createTools} from '../build/src/tools/tools.js';
const OUTPUT_PATH = path.join(
@@ -29,7 +34,7 @@ async function fetchTools() {
const transport = new StdioClientTransport({
command: 'node',
args: [serverPath],
args: [serverPath, '--viaCli'],
env: {...process.env, CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},
});
@@ -103,6 +108,15 @@ function schemaToCLIOptions(schema: JsonSchema): CliOption[] {
async function generateCli() {
const tools = await fetchTools();
const staticTools = createTools(parseArguments());
const toolNameToCategoryEnum = new Map<string, string>();
const toolNameToConditions = new Map<string, string[]>();
for (const tool of staticTools) {
toolNameToCategoryEnum.set(tool.name, tool.annotations.category);
toolNameToConditions.set(tool.name, tool.annotations.conditions || []);
}
// Sort tools by name
const sortedTools = tools
.sort((a, b) => a.name.localeCompare(b.name))
@@ -117,18 +131,17 @@ async function generateCli() {
if (tool.name === 'wait_for') {
return false;
}
// Skipping get_tab_id as it is for internal integrations
if (tool.name === 'get_tab_id') {
return false;
}
// Skipping in_page tools as they are not launched yet
if (toolNameToCategoryEnum.get(tool.name) === ToolCategory.IN_PAGE) {
return false;
}
return true;
});
const staticTools = createTools(parseArguments());
const toolNameToCategory = new Map<string, string>();
for (const tool of staticTools) {
toolNameToCategory.set(
tool.name,
labels[tool.annotations.category as keyof typeof labels],
);
}
const commands: Record<
string,
{description: string; category: string; args: Record<string, CliOption>}
@@ -140,15 +153,36 @@ async function generateCli() {
for (const opt of options) {
args[opt.name] = opt;
}
const category = toolNameToCategory.get(tool.name);
if (!category) {
const categoryEnum = toolNameToCategoryEnum.get(tool.name);
if (!categoryEnum) {
throw new Error(`Tool ${tool.name} has no category.`);
}
const category = labels[categoryEnum as unknown as keyof typeof labels];
if (!tool.description) {
throw new Error(`Tool ${tool.name} is missing descripttion`);
throw new Error(`Tool ${tool.name} is missing description`);
}
let description = tool.description;
const requiredFlags: string[] = [];
const isOffByDefault = OFF_BY_DEFAULT_CATEGORIES.includes(categoryEnum);
if (isOffByDefault) {
const categoryFlag = buildFlag(categoryEnum);
requiredFlags.push(`--${categoryFlag}=true`);
}
const conditions = toolNameToConditions.get(tool.name) || [];
for (const condition of conditions) {
requiredFlags.push(`--${condition}=true`);
}
if (requiredFlags.length > 0) {
description += ` (requires flag: ${requiredFlags.join(', ')})`;
}
commands[tool.name] = {
description: tool.description,
description,
category,
args,
};
+7 -1
View File
@@ -13,6 +13,7 @@ import {get_encoding} from 'tiktoken';
import {cliOptions} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';
import type {ParsedArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';
import {buildFlag} from '../build/src/index.js';
import {
ToolCategory,
OFF_BY_DEFAULT_CATEGORIES,
@@ -356,7 +357,7 @@ async function generateReference(
markdown += `## ${categoryName}\n\n`;
if (OFF_BY_DEFAULT_CATEGORIES.includes(category)) {
const flagName = `--category-${category}`;
const flagName = `--${buildFlag(category)}`;
markdown += `> NOTE: ${categoryName} are not active by default. Use the '${flagName}' flag\n\n`;
}
@@ -446,6 +447,11 @@ function getToolsAndCategories(tools: any) {
// Convert ToolDefinitions to ToolWithAnnotations
const toolsWithAnnotations: ToolWithAnnotations[] = tools
.filter(tool => {
// Skipping in_page tools as they are not launched yet
if (tool.annotations.category.includes('experimental')) {
return false;
}
if (!tool.annotations.conditions) {
return true;
}
+21
View File
@@ -123,6 +123,27 @@ chrome-devtools take_snapshot # Take a text snapshot of the page from the a11y t
chrome-devtools take_snapshot --verbose true --filePath "s.txt" # Take a verbose snapshot and save to file
```
## Extensions
```bash
chrome-devtools list_extensions # Lists all the Chrome extensions installed in the browser
chrome-devtools install_extension "/path/to/extension" # Installs a Chrome extension from the given path
chrome-devtools uninstall_extension "extension_id" # Uninstalls a Chrome extension by its ID
chrome-devtools reload_extension "extension_id" # Reloads an unpacked Chrome extension by its ID
chrome-devtools trigger_extension_action "extension_id" # Triggers the default action of an extension by its ID
```
## Experimental Features
Experimental tools are disabled by default. Enable them with the corresponding flag during `start`.
```bash
chrome-devtools click_at 100 200 # Clicks at the provided coordinates (requires --experimentalVision=true)
chrome-devtools screencast_start # Starts a screencast recording (requires --experimentalScreencast=true and ffmpeg)
chrome-devtools screencast_stop # Stops the active screencast
chrome-devtools list_webmcp_tools # List all WebMCP tools (requires --experimentalWebmcp=true)
```
## Service Management
```bash
+1 -1
View File
@@ -245,7 +245,7 @@ export class McpResponse implements Response {
}
setListInPageTools(): void {
if (this.#args.categoryInPageTools) {
if (this.#args.categoryExperimentalInPage) {
this.#listInPageTools = true;
}
}
+206
View File
@@ -49,6 +49,38 @@ export const commands: Commands = {
},
},
},
click_at: {
description:
'Clicks at the provided coordinates (requires flag: --experimentalVision=true)',
category: 'Input automation',
args: {
x: {
name: 'x',
type: 'number',
description: 'The x coordinate',
required: true,
},
y: {
name: 'y',
type: 'number',
description: 'The y coordinate',
required: true,
},
dblClick: {
name: 'dblClick',
type: 'boolean',
description: 'Set to true for double clicks. Default is false.',
required: false,
},
includeSnapshot: {
name: 'includeSnapshot',
type: 'boolean',
description:
'Whether to include a snapshot in the response. Default is false.',
required: false,
},
},
},
close_page: {
description:
'Closes the page by its index. The last open page cannot be closed.',
@@ -164,6 +196,26 @@ export const commands: Commands = {
},
},
},
execute_webmcp_tool: {
description:
'Executes a WebMCP tool exposed by the page. (requires flag: --experimentalWebmcp=true)',
category: 'Debugging',
args: {
toolName: {
name: 'toolName',
type: 'string',
description: 'The name of the WebMCP tool to execute',
required: true,
},
input: {
name: 'input',
type: 'string',
description:
'The JSON-stringified parameters to pass to the WebMCP tool',
required: false,
},
},
},
fill: {
description:
'Type text into an input, text area or select an option from a <select> element.',
@@ -205,6 +257,31 @@ export const commands: Commands = {
},
},
},
get_memory_snapshot_details: {
description:
'Loads a memory heapsnapshot and returns all available information including statistics, static data, and aggregated node information. Supports pagination for aggregates. (requires flag: --experimentalMemory=true)',
category: 'Memory',
args: {
filePath: {
name: 'filePath',
type: 'string',
description: 'A path to a .heapsnapshot file to read.',
required: true,
},
pageIdx: {
name: 'pageIdx',
type: 'number',
description: 'The page index for pagination of aggregates.',
required: false,
},
pageSize: {
name: 'pageSize',
type: 'number',
description: 'The page size for pagination of aggregates.',
required: false,
},
},
},
get_network_request: {
description:
'Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.',
@@ -233,6 +310,38 @@ export const commands: Commands = {
},
},
},
get_nodes_by_class: {
description:
'Loads a memory heapsnapshot and returns instances of a specific class with their stable IDs. (requires flag: --experimentalMemory=true)',
category: 'Memory',
args: {
filePath: {
name: 'filePath',
type: 'string',
description: 'A path to a .heapsnapshot file to read.',
required: true,
},
uid: {
name: 'uid',
type: 'number',
description:
'The unique UID for the class, obtained from aggregates listing.',
required: true,
},
pageIdx: {
name: 'pageIdx',
type: 'number',
description: 'The page index for pagination.',
required: false,
},
pageSize: {
name: 'pageSize',
type: 'number',
description: 'The page size for pagination.',
required: false,
},
},
},
handle_dialog: {
description:
'If a browser dialog was opened, use this command to handle it',
@@ -273,6 +382,19 @@ export const commands: Commands = {
},
},
},
install_extension: {
description:
'Installs a Chrome extension from the given path. (requires flag: --categoryExtensions=true)',
category: 'Extensions',
args: {
path: {
name: 'path',
type: 'string',
description: 'Absolute path to the unpacked extension folder.',
required: true,
},
},
},
lighthouse_audit: {
description:
'Get Lighthouse score and reports for accessibility, SEO and best practices. This excludes performance. For performance audits, run performance_start_trace',
@@ -339,6 +461,12 @@ export const commands: Commands = {
},
},
},
list_extensions: {
description:
'Lists all the Chrome extensions installed in the browser. This includes their name, ID, version, and enabled status. (requires flag: --categoryExtensions=true)',
category: 'Extensions',
args: {},
},
list_network_requests: {
description:
'List all requests for the currently selected page since the last navigation.',
@@ -380,6 +508,25 @@ export const commands: Commands = {
category: 'Navigation automation',
args: {},
},
list_webmcp_tools: {
description:
'Lists all WebMCP tools the page exposes. (requires flag: --experimentalWebmcp=true)',
category: 'Debugging',
args: {},
},
load_memory_snapshot: {
description:
'Loads a memory heapsnapshot and returns snapshot summary stats. (requires flag: --experimentalMemory=true)',
category: 'Memory',
args: {
filePath: {
name: 'filePath',
type: 'string',
description: 'A path to a .heapsnapshot file to read.',
required: true,
},
},
},
navigate_page: {
description:
'Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.',
@@ -549,6 +696,19 @@ export const commands: Commands = {
},
},
},
reload_extension: {
description:
'Reloads an unpacked Chrome extension by its ID. (requires flag: --categoryExtensions=true)',
category: 'Extensions',
args: {
id: {
name: 'id',
type: 'string',
description: 'ID of the extension to reload.',
required: true,
},
},
},
resize_page: {
description:
"Resizes the selected page's window so that the page has specified dimension",
@@ -568,6 +728,26 @@ export const commands: Commands = {
},
},
},
screencast_start: {
description:
'Starts recording a screencast (video) of the selected page in specified format. (requires flag: --experimentalScreencast=true)',
category: 'Debugging',
args: {
filePath: {
name: 'filePath',
type: 'string',
description:
'Output file path (.webm,.mp4 are supported). Uses mkdtemp to generate a unique path if not provided.',
required: false,
},
},
},
screencast_stop: {
description:
'Stops the active screencast recording on the selected page. (requires flag: --experimentalScreencast=true)',
category: 'Debugging',
args: {},
},
select_page: {
description: 'Select a page as a context for future tool calls.',
category: 'Navigation automation',
@@ -665,6 +845,19 @@ export const commands: Commands = {
},
},
},
trigger_extension_action: {
description:
'Triggers the default action of an extension by its ID. (requires flag: --categoryExtensions=true)',
category: 'Extensions',
args: {
id: {
name: 'id',
type: 'string',
description: 'ID of the extension to trigger the action for.',
required: true,
},
},
},
type_text: {
description: 'Type text using keyboard into a previously focused input',
category: 'Input automation',
@@ -684,6 +877,19 @@ export const commands: Commands = {
},
},
},
uninstall_extension: {
description:
'Uninstalls a Chrome extension by its ID. (requires flag: --categoryExtensions=true)',
category: 'Extensions',
args: {
id: {
name: 'id',
type: 'string',
description: 'ID of the extension to uninstall.',
required: true,
},
},
},
upload_file: {
description: 'Upload a file through a provided element.',
category: 'Input automation',
+2 -1
View File
@@ -237,9 +237,10 @@ export const cliOptions = {
describe:
'Set to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.',
},
categoryInPageTools: {
categoryExperimentalInPage: {
type: 'boolean',
hidden: true,
default: false,
describe:
'Set to true to enable tools exposed by the inspected page itself',
},
+5 -13
View File
@@ -47,20 +47,11 @@ const startCliOptions = {
delete startCliOptions.autoConnect;
// Missing CLI serialization.
delete startCliOptions.viewport;
// CLI is generated based on the default tool definitions. To enable conditional
// tools, they need to be enabled during CLI generation.
delete startCliOptions.experimentalPageIdRouting;
delete startCliOptions.experimentalVision;
delete startCliOptions.experimentalWebmcp;
delete startCliOptions.experimentalInteropTools;
delete startCliOptions.experimentalScreencast;
delete startCliOptions.categoryEmulation;
delete startCliOptions.categoryPerformance;
delete startCliOptions.categoryNetwork;
delete startCliOptions.categoryExtensions;
// Always on in CLI.
// Change the defaults for the CLI.
delete startCliOptions.experimentalStructuredContent;
// Change the defaults.
delete startCliOptions.experimentalInteropTools;
delete startCliOptions.experimentalPageIdRouting;
if (!('default' in cliOptions.headless)) {
throw new Error('headless cli option unexpectedly does not have a default');
}
@@ -70,6 +61,7 @@ if ('default' in cliOptions.isolated) {
startCliOptions.headless!.default = true;
startCliOptions.isolated!.description =
'If specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to true unless userDataDir is provided.';
startCliOptions.categoryExtensions!.default = true;
const y = yargs(hideBin(process.argv))
.scriptName('chrome-devtools')
+118 -59
View File
@@ -24,12 +24,110 @@ import {
ListRootsResultSchema,
RootsListChangedNotificationSchema,
} from './third_party/index.js';
import {ToolCategory} from './tools/categories.js';
import type {ToolCategory} from './tools/categories.js';
import {labels, OFF_BY_DEFAULT_CATEGORIES} from './tools/categories.js';
import type {DefinedPageTool, ToolDefinition} from './tools/ToolDefinition.js';
import {pageIdSchema} from './tools/ToolDefinition.js';
import {createTools} from './tools/tools.js';
import {VERSION} from './version.js';
export function buildFlag(category: ToolCategory) {
return `category${category.charAt(0).toUpperCase() + category.slice(1)}`;
}
function buildDisabledMessage(
toolName: string,
flag: string,
categoryLabel?: string,
): string {
const reason = categoryLabel
? `is in category ${categoryLabel} which`
: `requires experimental feature ${flag} and`;
return `Tool ${toolName} ${reason} is currently disabled. Enable it by running chrome-devtools start ${flag}=true. For more information check the README.`;
}
function getCategoryStatus(
category: ToolCategory,
serverArgs: ReturnType<typeof parseArguments>,
): {categoryFlag?: string; disabled: boolean} {
const categoryFlag = buildFlag(category);
const flagValue = serverArgs[categoryFlag];
const isDisabled = OFF_BY_DEFAULT_CATEGORIES.includes(category)
? !flagValue
: flagValue === false;
if (isDisabled) {
return {
categoryFlag,
disabled: true,
};
}
return {
disabled: false,
};
}
function getConditionStatus(
condition: string,
serverArgs: ReturnType<typeof parseArguments>,
): {conditionFlag?: string; disabled: boolean} {
if (condition && !serverArgs[condition]) {
return {conditionFlag: condition, disabled: true};
}
return {disabled: false};
}
function getToolStatusInfo(
tool: ToolDefinition | DefinedPageTool,
serverArgs: ReturnType<typeof parseArguments>,
): {disabled: boolean; reason?: string} {
const category = tool.annotations.category;
const categoryCheck = getCategoryStatus(category, serverArgs);
if (category && categoryCheck.disabled) {
if (!categoryCheck.categoryFlag) {
throw new Error(
'when the category is disabled there should always be a flag set',
);
}
return {
disabled: true,
reason: buildDisabledMessage(
tool.name,
`--${categoryCheck.categoryFlag}`,
labels[category!],
),
};
}
for (const condition of tool.annotations.conditions || []) {
const conditionCheck = getConditionStatus(condition, serverArgs);
if (conditionCheck.disabled) {
if (!conditionCheck.conditionFlag) {
throw new Error(
'when the condition is disabled there should always be a flag set',
);
}
return {
disabled: true,
reason: buildDisabledMessage(
tool.name,
`--${conditionCheck.conditionFlag}`,
),
};
}
}
return {disabled: false};
}
export async function createMcpServer(
serverArgs: ReturnType<typeof parseArguments>,
options: {
@@ -143,66 +241,15 @@ export async function createMcpServer(
const toolMutex = new Mutex();
function registerTool(tool: ToolDefinition | DefinedPageTool): void {
if (
tool.annotations.category === ToolCategory.EMULATION &&
serverArgs.categoryEmulation === false
) {
return;
}
if (
tool.annotations.category === ToolCategory.PERFORMANCE &&
serverArgs.categoryPerformance === false
) {
return;
}
if (
tool.annotations.category === ToolCategory.NETWORK &&
serverArgs.categoryNetwork === false
) {
return;
}
if (
tool.annotations.category === ToolCategory.EXTENSIONS &&
serverArgs.categoryExtensions === false
) {
return;
}
if (
tool.annotations.category === ToolCategory.IN_PAGE &&
!serverArgs.categoryInPageTools
) {
return;
}
if (
tool.annotations.conditions?.includes('computerVision') &&
!serverArgs.experimentalVision
) {
return;
}
if (
tool.annotations.conditions?.includes('experimentalMemory') &&
!serverArgs.experimentalMemory
) {
return;
}
if (
tool.annotations.conditions?.includes('experimentalInteropTools') &&
!serverArgs.experimentalInteropTools
) {
return;
}
if (
tool.annotations.conditions?.includes('screencast') &&
!serverArgs.experimentalScreencast
) {
return;
}
if (
tool.annotations.conditions?.includes('experimentalWebmcp') &&
!serverArgs.experimentalWebmcp
) {
const {disabled, reason: disabledReason} = getToolStatusInfo(
tool,
serverArgs,
);
if (disabled && !serverArgs.viaCli) {
return;
}
const schema =
'pageScoped' in tool &&
tool.pageScoped &&
@@ -219,6 +266,18 @@ export async function createMcpServer(
annotations: tool.annotations,
},
async (params): Promise<CallToolResult> => {
if (disabledReason) {
return {
content: [
{
type: 'text',
text: disabledReason,
},
],
isError: true,
};
}
const guard = await toolMutex.acquire();
const startTime = Date.now();
let success = false;
+12 -2
View File
@@ -192,11 +192,13 @@
},
{
"name": "category_in_page_tools",
"flagType": "boolean"
"flagType": "boolean",
"isDeprecated": true
},
{
"name": "category_in_page_tools_present",
"flagType": "boolean"
"flagType": "boolean",
"isDeprecated": true
},
{
"name": "clearcut_endpoint_present",
@@ -265,5 +267,13 @@
{
"name": "via_cli_present",
"flagType": "boolean"
},
{
"name": "category_experimental_in_page_present",
"flagType": "boolean"
},
{
"name": "category_experimental_in_page",
"flagType": "boolean"
}
]
+5 -2
View File
@@ -12,7 +12,7 @@ export enum ToolCategory {
NETWORK = 'network',
DEBUGGING = 'debugging',
EXTENSIONS = 'extensions',
IN_PAGE = 'in-page',
IN_PAGE = 'experimentalInPage',
MEMORY = 'memory',
}
@@ -28,4 +28,7 @@ export const labels = {
[ToolCategory.MEMORY]: 'Memory',
};
export const OFF_BY_DEFAULT_CATEGORIES = [ToolCategory.EXTENSIONS];
export const OFF_BY_DEFAULT_CATEGORIES = [
ToolCategory.EXTENSIONS,
ToolCategory.IN_PAGE,
];
-2
View File
@@ -48,7 +48,6 @@ export const listInPageTools = definePageTool({
annotations: {
category: ToolCategory.IN_PAGE,
readOnlyHint: true,
conditions: ['inPageTools'],
},
schema: {},
blockedByDialog: false,
@@ -63,7 +62,6 @@ export const executeInPageTool = definePageTool({
annotations: {
category: ToolCategory.IN_PAGE,
readOnlyHint: false,
conditions: ['inPageTools'],
},
schema: {
toolName: zod.string().describe('The name of the tool to execute'),
+1 -1
View File
@@ -90,7 +90,7 @@ export const clickAt = definePageTool({
annotations: {
category: ToolCategory.INPUT,
readOnlyHint: false,
conditions: ['computerVision'],
conditions: ['experimentalVision'],
},
schema: {
x: zod.number().describe('The x coordinate'),
+2 -2
View File
@@ -28,7 +28,7 @@ export const startScreencast = definePageTool(args => ({
annotations: {
category: ToolCategory.DEBUGGING,
readOnlyHint: false,
conditions: ['screencast'],
conditions: ['experimentalScreencast'],
},
schema: {
filePath: zod
@@ -99,7 +99,7 @@ export const stopScreencast = definePageTool({
annotations: {
category: ToolCategory.DEBUGGING,
readOnlyHint: false,
conditions: ['screencast'],
conditions: ['experimentalScreencast'],
},
schema: {},
blockedByDialog: false,
+3 -3
View File
@@ -1111,7 +1111,7 @@ describe('inPage tools', () => {
t.assert.snapshot?.(JSON.stringify(structuredContent, null, 2));
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -1162,14 +1162,14 @@ describe('inPage tools', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
}
it('includes in-page tools in list_pages response', async () => {
await testIncludesInPageTools(async (response, context) => {
const listPagesDef = listPages({
categoryInPageTools: true,
categoryExperimentalInPage: true,
} as ParsedArguments);
await listPagesDef.handler({params: {}}, response, context);
}, 'list_pages');
+2
View File
@@ -19,6 +19,8 @@ describe('cli args parsing', () => {
categoryNetwork: true,
'category-extensions': false,
categoryExtensions: false,
'category-experimental-in-page': false,
categoryExperimentalInPage: false,
'auto-connect': undefined,
autoConnect: undefined,
'performance-crux': true,
@@ -71,4 +71,39 @@ describe('chrome-devtools', () => {
'take_screenshot output is unexpected',
);
});
it('fails to invoke list_network_requests when categoryNetwork is disabled', async () => {
await runCli(['start', '--categoryNetwork=false'], sessionId);
const result = await runCli(['list_network_requests'], sessionId);
assert.strictEqual(result.status, 0);
assert(
result.stdout.includes(
'Tool list_network_requests is in category Network which is currently disabled',
),
'error message is unexpected: ' + result.stdout,
);
assert(
result.stdout.includes('chrome-devtools start --categoryNetwork=true'),
'restart command suggestion is missing: ' + result.stdout,
);
});
it('fails to invoke click_at when experimentalVision is disabled (default)', async () => {
await runCli(['start'], sessionId);
const result = await runCli(['click_at', '100', '100'], sessionId);
assert.strictEqual(result.status, 0);
assert(
result.stdout.includes(
'Tool click_at requires experimental feature --experimentalVision and is currently disabled',
),
'error message is unexpected: ' + result.stdout,
);
assert(
result.stdout.includes('chrome-devtools start --experimentalVision=true'),
'restart command suggestion is miss: ' + result.stdout,
);
});
});
+1 -1
View File
@@ -114,7 +114,7 @@ describe('e2e', () => {
);
assert.ok(listInPageTools);
},
['--category-in-page-tools'],
['--category-experimental-in-page'],
);
});
+13 -13
View File
@@ -72,7 +72,7 @@ describe('inPage', () => {
});
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -102,7 +102,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -131,7 +131,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -150,7 +150,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
});
@@ -215,7 +215,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -302,7 +302,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -347,7 +347,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -486,7 +486,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -535,7 +535,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -590,7 +590,7 @@ describe('inPage', () => {
);
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -647,7 +647,7 @@ describe('inPage', () => {
stub.restore();
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -713,7 +713,7 @@ describe('inPage', () => {
stubSnapshot.restore();
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
@@ -771,7 +771,7 @@ describe('inPage', () => {
stubSnapshot.restore();
},
undefined,
{categoryInPageTools: true} as ParsedArguments,
{categoryExperimentalInPage: true} as ParsedArguments,
);
});
});