Files
AI/참고/playwright-main/tests/mcp/cli-json.spec.ts

224 lines
8.8 KiB
TypeScript
Raw Normal View History

2026-05-12 19:40:31 +09:00
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { test, expect } from './cli-fixtures';
const SNAPSHOT_FILE = expect.stringMatching(/^\.playwright-cli[\\/]page-[\dTZ:.-]+\.yml$/);
test('output is pretty-printed', async ({ cli }) => {
const { output } = await cli('--json', 'list');
expect(output).toBe(`{
"browsers": []
}`);
});
test('version command returns JSON', async ({ cli }) => {
const { output } = await cli('--json', '--version');
const parsed = JSON.parse(output);
expect(parsed).toEqual({ version: expect.any(String) });
});
test('unknown command returns JSON error with exit 1', async ({ cli }) => {
const { output, exitCode } = await cli('--json', 'nope');
expect(JSON.parse(output)).toEqual({ isError: true, error: 'Unknown command: nope' });
expect(exitCode).toBe(1);
});
test('unknown flag returns JSON error with exit 1', async ({ cli }) => {
const { output, exitCode } = await cli('--json', 'list', '--bogus');
expect(JSON.parse(output)).toEqual({ isError: true, error: 'Unknown option: --bogus' });
expect(exitCode).toBe(1);
});
test('running tool command without open browser returns JSON error', async ({ cli }) => {
const { output, exitCode } = await cli('--json', 'goto', 'about:blank');
expect(JSON.parse(output)).toEqual({
isError: true,
error: `The browser 'default' is not open, please run open first`,
});
expect(exitCode).toBe(1);
});
test('list returns empty browsers before open', async ({ cli }) => {
const { output } = await cli('--json', 'list');
expect(JSON.parse(output)).toEqual({ browsers: [] });
});
test('close returns not-open status when nothing is running', async ({ cli }) => {
const { output } = await cli('--json', 'close');
expect(JSON.parse(output)).toEqual({ session: 'default', status: 'not-open' });
});
test('delete-data returns not-deleted when there is no session', async ({ cli }) => {
const { output } = await cli('--json', 'delete-data');
expect(JSON.parse(output)).toEqual({ session: 'default', deleted: false });
});
test('kill-all returns zero killed when filter matches nothing', async ({ cli }) => {
const { output } = await cli('--json', 'kill-all', { env: { PWTEST_KILL_ALL_PID_FILTER_FOR_TEST: '0' } });
expect(JSON.parse(output)).toEqual({ killed: 0, pids: [] });
});
test('open returns envelope with session, pid and snapshot file', async ({ cli, server }) => {
const { output } = await cli('--json', 'open', server.HELLO_WORLD);
expect(JSON.parse(output)).toEqual({
session: 'default',
pid: expect.any(Number),
result: { snapshot: { file: SNAPSHOT_FILE } },
});
});
test('list after open returns one browser entry', async ({ cli, server, mcpBrowserNormalized }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'list');
expect(JSON.parse(output)).toEqual({
browsers: [{
name: 'default',
workspace: expect.any(String),
status: 'open',
browserType: mcpBrowserNormalized,
userDataDir: null,
headed: false,
persistent: false,
attached: false,
compatible: true,
version: expect.any(String),
}],
});
});
test('goto returns snapshot file envelope', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'goto', server.HELLO_WORLD);
expect(JSON.parse(output)).toEqual({ snapshot: { file: SNAPSHOT_FILE } });
});
test('eval returns result string', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'eval', '() => 1 + 2');
expect(JSON.parse(output)).toEqual({ result: '3' });
});
test('eval with error surfaces isError JSON', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'eval', '() => { throw new Error("boom"); }');
const parsed = JSON.parse(output);
expect(parsed.isError).toBe(true);
expect(parsed.error).toContain('boom');
});
test('tab-new creates a new tab and returns tab list', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'tab-new');
const parsed = JSON.parse(output);
expect(parsed.result.split('\n')).toEqual([
`- 0: [Title](${server.HELLO_WORLD})`,
'- 1: (current) [](about:blank)',
]);
});
test('tab-list lists all tabs', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
await cli('tab-new');
const { output } = await cli('--json', 'tab-list');
const parsed = JSON.parse(output);
expect(parsed.result.split('\n')).toEqual([
`- 0: [Title](${server.HELLO_WORLD})`,
'- 1: (current) [](about:blank)',
]);
});
test('tab-close closes a tab and returns remaining tabs', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
await cli('tab-new');
const { output } = await cli('--json', 'tab-close');
const parsed = JSON.parse(output);
expect(parsed.result.split('\n')).toEqual([
`- 0: (current) [Title](${server.HELLO_WORLD})`,
]);
});
test('snapshot returns inline snapshot yaml', async ({ cli, server }) => {
server.setContent('/', '<h1>Hi</h1>', 'text/html');
await cli('open', server.PREFIX);
const { output } = await cli('--json', 'snapshot');
const parsed = JSON.parse(output);
expect(typeof parsed.snapshot).toBe('string');
expect(parsed.snapshot).toContain('heading "Hi"');
});
test('tool error on bad navigation returns JSON error', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'goto', 'https://not-a-real-domain.example.invalid');
const parsed = JSON.parse(output);
expect(parsed.isError).toBe(true);
expect(typeof parsed.error).toBe('string');
});
test('close after open returns closed status', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'close');
expect(JSON.parse(output)).toEqual({ session: 'default', status: 'closed' });
});
test('close-all after open returns closed sessions', async ({ cli, server }) => {
await cli('open', server.HELLO_WORLD);
const { output } = await cli('--json', 'close-all');
expect(JSON.parse(output)).toEqual({ closed: ['default'] });
});
test('requests returns numbered list as JSON result', async ({ cli, server }) => {
await cli('open', server.PREFIX);
await cli('eval', '() => fetch("/hello-world")');
const { output } = await cli('--json', 'requests');
const parsed = JSON.parse(output);
expect(typeof parsed.result).toBe('string');
expect(parsed.result).toMatch(new RegExp(String.raw`^\d+\. \[GET\] [^ ]+/hello-world => \[200\] OK$`, 'm'));
});
test('request and per-part commands return JSON result', async ({ cli, server }) => {
server.setContent('/', `
<button onclick="fetch('/api', { method: 'POST', headers: { 'X-Custom-Header': 'test-value' }, body: JSON.stringify({ key: 'value' }) })">Click me</button>
`, 'text/html');
server.setRoute('/api', (_req, res) => {
res.setHeader('X-Custom-Response', 'response-value');
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ name: 'John Doe' }));
});
await cli('open', server.PREFIX);
await cli('click', 'e2');
const { output: list } = await cli('requests');
const num = list.match(/^(\d+)\. \[POST\] [^ ]+\/api =>/m)![1];
expect(JSON.parse((await cli('--json', 'request-headers', num)).output).result).toContain('x-custom-header: test-value');
expect(JSON.parse((await cli('--json', 'request-body', num)).output)).toEqual({ result: '{"key":"value"}' });
expect(JSON.parse((await cli('--json', 'response-headers', num)).output).result).toContain('x-custom-response: response-value');
expect(JSON.parse((await cli('--json', 'response-body', num)).output)).toEqual({ result: '{"name":"John Doe"}' });
const detail = JSON.parse((await cli('--json', 'request', num)).output);
expect(detail.result).toContain(`#${num} [POST] ${server.PREFIX}/api`);
expect(detail.result).toContain(`Run \`response-body ${num}\` to read the response body.`);
});
test('request with out-of-range index returns JSON error', async ({ cli, server }) => {
await cli('open', server.PREFIX);
const { output } = await cli('--json', 'request', '999');
const parsed = JSON.parse(output);
expect(parsed.isError).toBe(true);
expect(parsed.error).toContain('Request #999 not found');
});