mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-11-04 15:00:11 +00:00
fix(pages): revert reporting the page size after resize_page (#3308)
This reverts commit f0030564a3 (#3132).
`McpPage.resize()` read `Page.getLayoutMetrics` from the target page
after the resize. Chrome does not lay out a background tab again until
the tab is visible. Thus, for a background tab, `resize_page` reported
the old page size (for example `Requested 1100x750, page is 1504x836`),
although the window had the requested size.
The window bounds (`Browser.getWindowBounds`) cannot replace the layout
metrics. They give the outer window size, which includes the tab strip
and the toolbar, not the page size.
`resize_page` again prints no page size. #2998 is open again.
Fixes #3306
This commit is contained in:
1 parent
ecab31def0
commit
186ea66f1b
7 files changed
+22
-236
No files matched your search
@@ -298,7 +298,7 @@
|
||||
|
||||
### `resize_page`
|
||||
|
||||
**Description:** Resizes the page's window so that the page has specified dimension. If the browser clamps the window size, the actual page dimensions are reported.
|
||||
**Description:** Resizes the page's window so that the page has specified dimension
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
||||
@@ -1439,45 +1439,6 @@ export class McpPage implements ContextPage {
|
||||
});
|
||||
}
|
||||
|
||||
async resize(
|
||||
width: number,
|
||||
height: number,
|
||||
): Promise<{width: number; height: number} | undefined> {
|
||||
try {
|
||||
const browser = this.pptrPage.browser();
|
||||
const windowId = await this.pptrPage.windowId();
|
||||
const bounds = await browser.getWindowBounds(windowId);
|
||||
|
||||
if (bounds.windowState === 'fullscreen') {
|
||||
// Have to call this twice on Ubuntu when the window is in fullscreen mode.
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
} else if (bounds.windowState !== 'normal') {
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
}
|
||||
} catch {
|
||||
// Window APIs are not supported on all platforms
|
||||
}
|
||||
await this.pptrPage.resize({
|
||||
contentWidth: width,
|
||||
contentHeight: height,
|
||||
});
|
||||
|
||||
if (this.getDialog()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// @ts-expect-error internal API
|
||||
const client = this.pptrPage._client();
|
||||
const metrics: Protocol.Page.GetLayoutMetricsResponse = await client.send(
|
||||
'Page.getLayoutMetrics',
|
||||
);
|
||||
return {
|
||||
width: metrics.cssLayoutViewport.clientWidth,
|
||||
height: metrics.cssLayoutViewport.clientHeight,
|
||||
};
|
||||
}
|
||||
|
||||
lighthouseNavigation(flags?: Flags): Promise<RunnerResult | undefined> {
|
||||
return lighthouseNavigation(this.pptrPage, this.pptrPage.url(), {
|
||||
flags,
|
||||
|
||||
@@ -1754,7 +1754,7 @@ export const commands: Commands = {
|
||||
},
|
||||
resize_page: {
|
||||
description:
|
||||
"Resizes the page's window so that the page has specified dimension. If the browser clamps the window size, the actual page dimensions are reported.",
|
||||
"Resizes the page's window so that the page has specified dimension",
|
||||
category: 'Emulation',
|
||||
args: {
|
||||
pageId: {
|
||||
|
||||
@@ -529,10 +529,6 @@ export type ContextPage = Readonly<{
|
||||
text: string[],
|
||||
options?: {timeout?: number; visible?: boolean},
|
||||
): Promise<Element>;
|
||||
resize(
|
||||
width: number,
|
||||
height: number,
|
||||
): Promise<{width: number; height: number} | undefined>;
|
||||
getDevToolsPage(): Promise<Page | undefined>;
|
||||
openDevTools(): Promise<Page | undefined>;
|
||||
ensureDevToolsCommentBridge(
|
||||
|
||||
+20
-10
@@ -355,7 +355,7 @@ export const navigatePage: PageToolFactory = definePageTool(
|
||||
|
||||
export const resizePage: PageToolFactory = definePageTool(() => ({
|
||||
name: 'resize_page',
|
||||
description: `Resizes the page's window so that the page has specified dimension. If the browser clamps the window size, the actual page dimensions are reported.`,
|
||||
description: `Resizes the page's window so that the page has specified dimension`,
|
||||
annotations: {
|
||||
category: ToolCategory.EMULATION,
|
||||
readOnlyHint: false,
|
||||
@@ -369,17 +369,27 @@ export const resizePage: PageToolFactory = definePageTool(() => ({
|
||||
verifyFilesSchema: {},
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
const {width, height} = request.params;
|
||||
|
||||
const actualSize = await page.resize(width, height);
|
||||
if (
|
||||
actualSize &&
|
||||
(actualSize.width !== width || actualSize.height !== height)
|
||||
) {
|
||||
response.appendResponseLine(
|
||||
`Requested ${width}x${height}, page is ${actualSize.width}x${actualSize.height}`,
|
||||
);
|
||||
try {
|
||||
const browser = page.pptrPage.browser();
|
||||
const windowId = await page.pptrPage.windowId();
|
||||
|
||||
const bounds = await browser.getWindowBounds(windowId);
|
||||
|
||||
if (bounds.windowState === 'fullscreen') {
|
||||
// Have to call this twice on Ubuntu when the window is in fullscreen mode.
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
} else if (bounds.windowState !== 'normal') {
|
||||
await browser.setWindowBounds(windowId, {windowState: 'normal'});
|
||||
}
|
||||
} catch {
|
||||
// Window APIs are not supported on all platforms
|
||||
}
|
||||
await page.pptrPage.resize({
|
||||
contentWidth: request.params.width,
|
||||
contentHeight: request.params.height,
|
||||
});
|
||||
|
||||
response.setIncludePages(true);
|
||||
},
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
createMockCDPSession,
|
||||
createMockDialog,
|
||||
createMockMcpResponse,
|
||||
createMockPuppeteerBrowser,
|
||||
createMockPuppeteerPage,
|
||||
createMockPuppeteerTarget,
|
||||
createMockServerConfig,
|
||||
@@ -2258,107 +2257,6 @@ describe('McpPage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resize()', () => {
|
||||
it('resizes the page and returns the resulting cssLayoutViewport dimensions', async () => {
|
||||
const {mcpPage, pptrPage} = await createMcpPage();
|
||||
const browser = createMockPuppeteerBrowser();
|
||||
pptrPage.browser.returns(browser);
|
||||
pptrPage.windowId.resolves('win-1');
|
||||
browser.getWindowBounds.resolves({windowState: 'normal'});
|
||||
pptrPage.cdpSession.send.withArgs('Page.getLayoutMetrics').resolves({
|
||||
cssLayoutViewport: {
|
||||
clientWidth: 500,
|
||||
clientHeight: 232,
|
||||
pageX: 0,
|
||||
pageY: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const actualSize = await mcpPage.resize(100, 100);
|
||||
|
||||
sinon.assert.notCalled(browser.setWindowBounds);
|
||||
sinon.assert.calledOnceWithExactly(pptrPage.resize, {
|
||||
contentWidth: 100,
|
||||
contentHeight: 100,
|
||||
});
|
||||
assert.deepStrictEqual(actualSize, {width: 500, height: 232});
|
||||
});
|
||||
|
||||
it('restores normal window state from fullscreen twice before resizing', async () => {
|
||||
const {mcpPage, pptrPage} = await createMcpPage();
|
||||
const browser = createMockPuppeteerBrowser();
|
||||
pptrPage.browser.returns(browser);
|
||||
pptrPage.windowId.resolves('win-1');
|
||||
browser.getWindowBounds.resolves({windowState: 'fullscreen'});
|
||||
pptrPage.cdpSession.send.withArgs('Page.getLayoutMetrics').resolves({
|
||||
cssLayoutViewport: {
|
||||
clientWidth: 800,
|
||||
clientHeight: 600,
|
||||
pageX: 0,
|
||||
pageY: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const actualSize = await mcpPage.resize(800, 600);
|
||||
|
||||
sinon.assert.calledTwice(browser.setWindowBounds);
|
||||
sinon.assert.calledWithExactly(
|
||||
browser.setWindowBounds.firstCall,
|
||||
'win-1',
|
||||
{windowState: 'normal'},
|
||||
);
|
||||
sinon.assert.calledWithExactly(
|
||||
browser.setWindowBounds.secondCall,
|
||||
'win-1',
|
||||
{windowState: 'normal'},
|
||||
);
|
||||
sinon.assert.calledOnceWithExactly(pptrPage.resize, {
|
||||
contentWidth: 800,
|
||||
contentHeight: 600,
|
||||
});
|
||||
assert.deepStrictEqual(actualSize, {width: 800, height: 600});
|
||||
});
|
||||
|
||||
it('continues resizing when window bounds APIs are unsupported', async () => {
|
||||
const {mcpPage, pptrPage} = await createMcpPage();
|
||||
pptrPage.windowId.rejects(new Error('Window APIs not supported'));
|
||||
pptrPage.cdpSession.send.withArgs('Page.getLayoutMetrics').resolves({
|
||||
cssLayoutViewport: {
|
||||
clientWidth: 700,
|
||||
clientHeight: 500,
|
||||
pageX: 0,
|
||||
pageY: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const actualSize = await mcpPage.resize(700, 500);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(pptrPage.resize, {
|
||||
contentWidth: 700,
|
||||
contentHeight: 500,
|
||||
});
|
||||
assert.deepStrictEqual(actualSize, {width: 700, height: 500});
|
||||
});
|
||||
|
||||
it('returns undefined without reading layout metrics when a dialog is open', async () => {
|
||||
const {mcpPage, pptrPage} = await createMcpPage();
|
||||
pptrPage.windowId.rejects(new Error('Window APIs not supported'));
|
||||
pptrPage.emit('dialog', createMockDialog());
|
||||
|
||||
const actualSize = await mcpPage.resize(700, 500);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(pptrPage.resize, {
|
||||
contentWidth: 700,
|
||||
contentHeight: 500,
|
||||
});
|
||||
sinon.assert.neverCalledWith(
|
||||
pptrPage.cdpSession.send,
|
||||
'Page.getLayoutMetrics',
|
||||
);
|
||||
assert.strictEqual(actualSize, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dialogs', () => {
|
||||
it('returns the dialog and throws when unhandled', async () => {
|
||||
const {mcpPage, pptrPage} = await createMcpPage();
|
||||
|
||||
@@ -1537,85 +1537,6 @@ describe('pages', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('reports actual page dimensions when the browser clamps width or height', async () => {
|
||||
const {page, response, context, args} = createHandlerMocks();
|
||||
page.resize.resolves({width: 500, height: 100});
|
||||
|
||||
await resizePage(args).handler(
|
||||
{
|
||||
params: {width: 100, height: 100},
|
||||
page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(page.resize, 100, 100);
|
||||
sinon.assert.calledOnceWithExactly(
|
||||
response.appendResponseLine,
|
||||
'Requested 100x100, page is 500x100',
|
||||
);
|
||||
sinon.assert.calledOnceWithExactly(response.setIncludePages, true);
|
||||
|
||||
const heightMocks = createHandlerMocks();
|
||||
heightMocks.page.resize.resolves({width: 800, height: 232});
|
||||
|
||||
await resizePage(heightMocks.args).handler(
|
||||
{
|
||||
params: {width: 800, height: 100},
|
||||
page: heightMocks.page,
|
||||
},
|
||||
heightMocks.response,
|
||||
heightMocks.context,
|
||||
);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(heightMocks.page.resize, 800, 100);
|
||||
sinon.assert.calledOnceWithExactly(
|
||||
heightMocks.response.appendResponseLine,
|
||||
'Requested 800x100, page is 800x232',
|
||||
);
|
||||
sinon.assert.calledOnceWithExactly(
|
||||
heightMocks.response.setIncludePages,
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not append a size warning when the page matches requested dimensions', async () => {
|
||||
const {page, response, context, args} = createHandlerMocks();
|
||||
page.resize.resolves({width: 700, height: 500});
|
||||
|
||||
await resizePage(args).handler(
|
||||
{
|
||||
params: {width: 700, height: 500},
|
||||
page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(page.resize, 700, 500);
|
||||
sinon.assert.notCalled(response.appendResponseLine);
|
||||
sinon.assert.calledOnceWithExactly(response.setIncludePages, true);
|
||||
});
|
||||
|
||||
it('does not append a size line when the actual page size is unknown', async () => {
|
||||
const {page, response, context, args} = createHandlerMocks();
|
||||
page.resize.resolves(undefined);
|
||||
|
||||
await resizePage(args).handler(
|
||||
{
|
||||
params: {width: 700, height: 500},
|
||||
page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(page.resize, 700, 500);
|
||||
sinon.assert.notCalled(response.appendResponseLine);
|
||||
sinon.assert.calledOnceWithExactly(response.setIncludePages, true);
|
||||
});
|
||||
|
||||
it('resize when window state is normal', async () => {
|
||||
await withMcpContext(async (response, context, args) => {
|
||||
const page = context.getSelectedMcpPage().pptrPage;
|
||||
|
||||
Reference in new issue
Block a user