From a9e9ff9eb066c0143a2fa79aa8869d99fb14cae0 Mon Sep 17 00:00:00 2001 From: munrocket Date: Mon, 26 May 2025 20:58:11 +0400 Subject: [PATCH] Precise browser resizing with integration_test and driver (#160678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #136109 P2 Related #148028 P1 Roadmap: - [x] find why not working (described in #136109) - [x] create new API with backward compatibility (`--browser-dimension=393×852@3`) - [x] fix edge cases - [x] internal testing - [x] add documentation (flutter drive -h) This PR: - Fixes Chrome bug from dart side - Adds pixelRatio mobile emulation in web - Adds new notation: 393,852 -> 393×852[@1] - Leaves previous behavior as it was, so 393,852 will give wrong size until Chrome will fix it. But you can use 393×852@1. --------- Co-authored-by: Mouad Debbar --- .../flutter_tools/lib/src/commands/drive.dart | 9 ++-- .../lib/src/drive/web_driver_service.dart | 52 ++++++++++++++----- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index be9543912c2..929762a81a6 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -140,11 +140,12 @@ class DriveCommand extends RunCommandBase { ) ..addOption( 'browser-dimension', - defaultsTo: '1600,1024', + defaultsTo: '1600x1024', help: 'The dimension of the browser when running a Flutter Web test. ' - 'This will affect screenshot and all offset-related actions.', - valueHelp: 'width,height', + 'Format is "width x height[@dpr]" where dpr is optional device pixel ratio. ' + 'This will affect screenshot dimensions and all offset-related actions.', + valueHelp: '1600x1024[@1]', ) ..addFlag( 'android-emulator', @@ -358,7 +359,7 @@ class DriveCommand extends RunCommandBase { chromeBinary: stringArg('chrome-binary'), headless: boolArg('headless'), webBrowserFlags: stringsArg(FlutterOptions.kWebBrowserFlag), - browserDimension: stringArg('browser-dimension')!.split(','), + browserDimension: stringArg('browser-dimension')!.split(RegExp('[,x@]')), browserName: stringArg('browser-name'), driverPort: stringArg('driver-port') != null ? int.tryParse(stringArg('driver-port')!) : null, diff --git a/packages/flutter_tools/lib/src/drive/web_driver_service.dart b/packages/flutter_tools/lib/src/drive/web_driver_service.dart index ab2907b254a..15d10fda07a 100644 --- a/packages/flutter_tools/lib/src/drive/web_driver_service.dart +++ b/packages/flutter_tools/lib/src/drive/web_driver_service.dart @@ -168,6 +168,38 @@ class WebDriverService extends DriverService { }) async { late async_io.WebDriver webDriver; final Browser browser = Browser.fromCliName(browserName); + final bool isAndroidChrome = browser == Browser.androidChrome; + late int width; + late int height; + Map? mobileEmulation; + + // Do not resize Android Chrome browser. + // For PC Chrome use mobileEmulation if dpr is provided. + if (!isAndroidChrome && browserDimension != null) { + try { + final int len = browserDimension.length; + if (len != 2 && len != 3) { + throw const FormatException(); + } + width = int.parse(browserDimension[0]); + height = int.parse(browserDimension[1]); + if (len == 3) { + mobileEmulation = { + 'deviceMetrics': { + 'width': width, + 'height': height, + 'pixelRatio': double.parse(browserDimension[2]), + }, + 'userAgent': + 'Mozilla/5.0 (Linux; Android 15) AppleWebKit/537.36 (KHTML, ' + 'like Gecko) Chrome/131.0.6778.200 Mobile Safari/537.36', + }; + } + } on FormatException { + throwToolExit('Browser dimension is invalid. Try --browser-dimension=1600x1024[@1]'); + } + } + try { webDriver = await async_io.createDriver( uri: Uri.parse('http://localhost:$driverPort/'), @@ -176,6 +208,7 @@ class WebDriverService extends DriverService { headless, webBrowserFlags: webBrowserFlags, chromeBinary: chromeBinary, + mobileEmulation: mobileEmulation, ), ); } on SocketException catch (error) { @@ -188,21 +221,10 @@ class WebDriverService extends DriverService { ); } - final bool isAndroidChrome = browser == Browser.androidChrome; - // Do not set the window size for android chrome browser. - if (!isAndroidChrome) { - assert(browserDimension!.length == 2); - late int x; - late int y; - try { - x = int.parse(browserDimension![0]); - y = int.parse(browserDimension[1]); - } on FormatException catch (ex) { - throwToolExit('Dimension provided to --browser-dimension is invalid: $ex'); - } + if (!isAndroidChrome && browserDimension != null) { final async_io.Window window = await webDriver.window; await window.setLocation(const math.Point(0, 0)); - await window.setSize(math.Rectangle(0, 0, x, y)); + await window.setSize(math.Rectangle(0, 0, width, height)); } final int result = await _processUtils.stream( [_dartSdkPath, ...arguments, testFile], @@ -305,6 +327,7 @@ Map getDesiredCapabilities( bool? headless, { List webBrowserFlags = const [], String? chromeBinary, + Map? mobileEmulation, }) => switch (browser) { Browser.chrome => { 'acceptInsecureCerts': true, @@ -314,7 +337,6 @@ Map getDesiredCapabilities( async_io.LogType.performance: 'ALL', }, 'goog:chromeOptions': { - if (chromeBinary != null) 'binary': chromeBinary, 'w3c': true, 'args': [ '--bwsi', @@ -335,6 +357,8 @@ Map getDesiredCapabilities( 'v8,blink.console,benchmark,blink,' 'blink.user_timing', }, + if (chromeBinary != null) 'binary': chromeBinary, + if (mobileEmulation != null) 'mobileEmulation': mobileEmulation, }, }, Browser.firefox => {