Fixes #491 When `--start-maximized` or `--window-size` is passed as a browser arg, Playwright's default viewport (1280x720) overrides the browser's own window sizing, making those flags have no effect on the page content. This change auto-detects those args and sets `viewport: null` so Playwright defers to the browser's window size. Explicit viewport values still take priority. Also allows `viewport: null` in the launch protocol for agents that want to disable viewport emulation directly.
This commit is contained in:
@@ -484,6 +484,42 @@ describe('BrowserManager', () => {
|
||||
expect(size?.width).toBe(1920);
|
||||
expect(size?.height).toBe(1080);
|
||||
});
|
||||
|
||||
it('should disable viewport when --start-maximized is in args', async () => {
|
||||
const testBrowser = new BrowserManager();
|
||||
await testBrowser.launch({ headless: true, args: ['--start-maximized'] });
|
||||
const page = testBrowser.getPage();
|
||||
expect(page.viewportSize()).toBeNull();
|
||||
await testBrowser.close();
|
||||
});
|
||||
|
||||
it('should disable viewport when --window-size is in args', async () => {
|
||||
const testBrowser = new BrowserManager();
|
||||
await testBrowser.launch({ headless: true, args: ['--window-size=800,600'] });
|
||||
const page = testBrowser.getPage();
|
||||
expect(page.viewportSize()).toBeNull();
|
||||
await testBrowser.close();
|
||||
});
|
||||
|
||||
it('should use default viewport when no window size args', async () => {
|
||||
const testBrowser = new BrowserManager();
|
||||
await testBrowser.launch({ headless: true });
|
||||
const page = testBrowser.getPage();
|
||||
expect(page.viewportSize()).toEqual({ width: 1280, height: 720 });
|
||||
await testBrowser.close();
|
||||
});
|
||||
|
||||
it('should use explicit viewport even with --start-maximized', async () => {
|
||||
const testBrowser = new BrowserManager();
|
||||
await testBrowser.launch({
|
||||
headless: true,
|
||||
args: ['--start-maximized'],
|
||||
viewport: { width: 800, height: 600 },
|
||||
});
|
||||
const page = testBrowser.getPage();
|
||||
expect(page.viewportSize()).toEqual({ width: 800, height: 600 });
|
||||
await testBrowser.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('snapshot', () => {
|
||||
|
||||
+17
-6
@@ -1156,7 +1156,6 @@ export class BrowserManager {
|
||||
|
||||
const launcher =
|
||||
browserType === 'firefox' ? firefox : browserType === 'webkit' ? webkit : chromium;
|
||||
const viewport = options.viewport ?? { width: 1280, height: 720 };
|
||||
|
||||
// Build base args array with file access flags if enabled
|
||||
// --allow-file-access-from-files: allows file:// URLs to read other file:// URLs via XHR/fetch
|
||||
@@ -1170,6 +1169,18 @@ export class BrowserManager {
|
||||
? fileAccessArgs
|
||||
: undefined;
|
||||
|
||||
// Auto-detect args that control window size and disable viewport emulation
|
||||
// so Playwright doesn't override the browser's own sizing behavior
|
||||
const hasWindowSizeArgs = baseArgs?.some(
|
||||
(arg) => arg === '--start-maximized' || arg.startsWith('--window-size=')
|
||||
);
|
||||
const viewport =
|
||||
options.viewport !== undefined
|
||||
? options.viewport
|
||||
: hasWindowSizeArgs
|
||||
? null
|
||||
: { width: 1280, height: 720 };
|
||||
|
||||
let context: BrowserContext;
|
||||
if (hasExtensions) {
|
||||
// Extensions require persistent context in a temp directory
|
||||
@@ -1597,16 +1608,16 @@ export class BrowserManager {
|
||||
/**
|
||||
* Create a new window (new context)
|
||||
*/
|
||||
async newWindow(viewport?: {
|
||||
width: number;
|
||||
height: number;
|
||||
}): Promise<{ index: number; total: number }> {
|
||||
async newWindow(viewport?: { width: number; height: number } | null): Promise<{
|
||||
index: number;
|
||||
total: number;
|
||||
}> {
|
||||
if (!this.browser) {
|
||||
throw new Error('Browser not launched');
|
||||
}
|
||||
|
||||
const context = await this.browser.newContext({
|
||||
viewport: viewport ?? { width: 1280, height: 720 },
|
||||
viewport: viewport === undefined ? { width: 1280, height: 720 } : viewport,
|
||||
});
|
||||
context.setDefaultTimeout(60000);
|
||||
this.contexts.push(context);
|
||||
|
||||
@@ -598,6 +598,31 @@ describe('parseCommand', () => {
|
||||
expect(result.command.allowFileAccess).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('should parse launch with viewport dimensions', () => {
|
||||
const result = parseCommand(
|
||||
cmd({ id: '1', action: 'launch', viewport: { width: 1920, height: 1080 } })
|
||||
);
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.command.viewport).toEqual({ width: 1920, height: 1080 });
|
||||
}
|
||||
});
|
||||
|
||||
it('should parse launch with viewport null', () => {
|
||||
const result = parseCommand(cmd({ id: '1', action: 'launch', viewport: null }));
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.command.viewport).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject launch with invalid viewport', () => {
|
||||
const result = parseCommand(
|
||||
cmd({ id: '1', action: 'launch', viewport: { width: -1, height: 720 } })
|
||||
);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mouse actions', () => {
|
||||
|
||||
@@ -16,6 +16,7 @@ const launchSchema = baseCommandSchema.extend({
|
||||
width: z.number().positive(),
|
||||
height: z.number().positive(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
browser: z.enum(['chromium', 'firefox', 'webkit']).optional(),
|
||||
cdpPort: z.number().positive().optional(),
|
||||
@@ -822,6 +823,7 @@ const windowNewSchema = baseCommandSchema.extend({
|
||||
width: z.number().positive(),
|
||||
height: z.number().positive(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ export interface BaseCommand {
|
||||
export interface LaunchCommand extends BaseCommand {
|
||||
action: 'launch';
|
||||
headless?: boolean;
|
||||
viewport?: { width: number; height: number };
|
||||
viewport?: { width: number; height: number } | null;
|
||||
browser?: 'chromium' | 'firefox' | 'webkit';
|
||||
headers?: Record<string, string>;
|
||||
executablePath?: string;
|
||||
@@ -850,7 +850,7 @@ export interface TabCloseCommand extends BaseCommand {
|
||||
|
||||
export interface WindowNewCommand extends BaseCommand {
|
||||
action: 'window_new';
|
||||
viewport?: { width: number; height: number };
|
||||
viewport?: { width: number; height: number } | null;
|
||||
}
|
||||
|
||||
// Union of all command types
|
||||
|
||||
Reference in New Issue
Block a user