test_window_rect.py (13176B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 import unittest 5 6 import mozinfo 7 8 from marionette_driver.errors import InvalidArgumentException 9 from marionette_harness import MarionetteTestCase 10 11 12 class TestWindowRect(MarionetteTestCase): 13 def setUp(self): 14 super(TestWindowRect, self).setUp() 15 16 self.original_rect = self.marionette.window_rect 17 18 self.max = self.marionette.execute_script( 19 """ 20 return { 21 width: window.screen.availWidth, 22 height: window.screen.availHeight, 23 }""", 24 sandbox=None, 25 ) 26 27 # WebDriver spec says a resize cannot result in window being 28 # maximised, an error is returned if that is the case; therefore if 29 # the window is maximised at the start of this test, returning to 30 # the original size via set_window_rect size will result in error; 31 # so reset to original size minus 1 pixel width 32 start_size = { 33 "height": self.original_rect["height"], 34 "width": self.original_rect["width"], 35 } 36 if ( 37 start_size["width"] == self.max["width"] 38 and start_size["height"] == self.max["height"] 39 ): 40 start_size["width"] -= 10 41 start_size["height"] -= 10 42 self.marionette.set_window_rect( 43 height=start_size["height"], width=start_size["width"] 44 ) 45 46 def tearDown(self): 47 x, y = self.original_rect["x"], self.original_rect["y"] 48 height, width = self.original_rect["height"], self.original_rect["width"] 49 50 self.marionette.set_window_rect(x=x, y=y, height=height, width=width) 51 52 is_fullscreen = self.marionette.execute_script( 53 "return document.fullscreenElement;", sandbox=None 54 ) 55 if is_fullscreen: 56 self.marionette.fullscreen() 57 58 super(TestWindowRect, self).tearDown() 59 60 def test_get_types(self): 61 rect = self.marionette.window_rect 62 self.assertIn("x", rect) 63 self.assertIn("y", rect) 64 self.assertIn("height", rect) 65 self.assertIn("width", rect) 66 self.assertIsInstance(rect["x"], int) 67 self.assertIsInstance(rect["y"], int) 68 self.assertIsInstance(rect["height"], int) 69 self.assertIsInstance(rect["width"], int) 70 71 def test_set_types(self): 72 invalid_rects = ( 73 ["a", "b", "h", "w"], 74 [1.2, 3.4, 4.5, 5.6], 75 [True, False, True, False], 76 [[], [], [], []], 77 [{}, {}, {}, {}], 78 ) 79 for x, y, h, w in invalid_rects: 80 print("testing invalid type position ({},{})".format(x, y)) 81 with self.assertRaises(InvalidArgumentException): 82 self.marionette.set_window_rect(x=x, y=y, height=h, width=w) 83 84 def test_setting_window_rect_with_nulls_errors(self): 85 with self.assertRaises(InvalidArgumentException): 86 self.marionette.set_window_rect(height=None, width=None, x=None, y=None) 87 88 @unittest.skipIf( 89 mozinfo.display == "wayland", "Wayland doesn't support window positioning" 90 ) 91 def test_set_position(self): 92 old_position = self.marionette.window_rect 93 wanted_position = {"x": old_position["x"] + 10, "y": old_position["y"] + 10} 94 95 new_position = self.marionette.set_window_rect( 96 x=wanted_position["x"], y=wanted_position["y"] 97 ) 98 expected_position = self.marionette.window_rect 99 100 self.assertEqual(new_position["x"], wanted_position["x"]) 101 self.assertEqual(new_position["y"], wanted_position["y"]) 102 self.assertEqual(new_position["x"], expected_position["x"]) 103 self.assertEqual(new_position["y"], expected_position["y"]) 104 105 def test_set_size(self): 106 old_size = self.marionette.window_rect 107 wanted_size = { 108 "height": old_size["height"] - 50, 109 "width": old_size["width"] - 50, 110 } 111 112 new_size = self.marionette.set_window_rect( 113 height=wanted_size["height"], width=wanted_size["width"] 114 ) 115 expected_size = self.marionette.window_rect 116 117 self.assertEqual( 118 new_size["width"], 119 wanted_size["width"], 120 "New width is {0} but should be {1}".format( 121 new_size["width"], wanted_size["width"] 122 ), 123 ) 124 self.assertEqual( 125 new_size["height"], 126 wanted_size["height"], 127 "New height is {0} but should be {1}".format( 128 new_size["height"], wanted_size["height"] 129 ), 130 ) 131 self.assertEqual( 132 new_size["width"], 133 expected_size["width"], 134 "New width is {0} but should be {1}".format( 135 new_size["width"], expected_size["width"] 136 ), 137 ) 138 self.assertEqual( 139 new_size["height"], 140 expected_size["height"], 141 "New height is {0} but should be {1}".format( 142 new_size["height"], expected_size["height"] 143 ), 144 ) 145 146 def test_set_position_and_size(self): 147 old_rect = self.marionette.window_rect 148 wanted_rect = { 149 "x": old_rect["x"] + 10, 150 "y": old_rect["y"] + 10, 151 "width": old_rect["width"] - 50, 152 "height": old_rect["height"] - 50, 153 } 154 155 new_rect = self.marionette.set_window_rect( 156 x=wanted_rect["x"], 157 y=wanted_rect["y"], 158 width=wanted_rect["width"], 159 height=wanted_rect["height"], 160 ) 161 expected_rect = self.marionette.window_rect 162 163 if mozinfo.display != "wayland": 164 self.assertEqual(new_rect["x"], wanted_rect["x"]) 165 self.assertEqual(new_rect["y"], wanted_rect["y"]) 166 167 self.assertEqual( 168 new_rect["width"], 169 wanted_rect["width"], 170 "New width is {0} but should be {1}".format( 171 new_rect["width"], wanted_rect["width"] 172 ), 173 ) 174 self.assertEqual( 175 new_rect["height"], 176 wanted_rect["height"], 177 "New height is {0} but should be {1}".format( 178 new_rect["height"], wanted_rect["height"] 179 ), 180 ) 181 182 if mozinfo.display != "wayland": 183 self.assertEqual(new_rect["x"], wanted_rect["x"]) 184 self.assertEqual(new_rect["y"], wanted_rect["y"]) 185 186 self.assertEqual( 187 new_rect["width"], 188 expected_rect["width"], 189 "New width is {0} but should be {1}".format( 190 new_rect["width"], expected_rect["width"] 191 ), 192 ) 193 self.assertEqual( 194 new_rect["height"], 195 expected_rect["height"], 196 "New height is {0} but should be {1}".format( 197 new_rect["height"], expected_rect["height"] 198 ), 199 ) 200 201 def test_move_to_current_position(self): 202 old_position = self.marionette.window_rect 203 new_position = self.marionette.set_window_rect( 204 x=old_position["x"], y=old_position["y"] 205 ) 206 207 self.assertEqual(new_position["x"], old_position["x"]) 208 self.assertEqual(new_position["y"], old_position["y"]) 209 210 def test_move_to_current_size(self): 211 old_size = self.marionette.window_rect 212 new_size = self.marionette.set_window_rect( 213 height=old_size["height"], width=old_size["width"] 214 ) 215 216 self.assertEqual(new_size["height"], old_size["height"]) 217 self.assertEqual(new_size["width"], old_size["width"]) 218 219 def test_move_to_current_position_and_size(self): 220 old_position_and_size = self.marionette.window_rect 221 new_position_and_size = self.marionette.set_window_rect( 222 x=old_position_and_size["x"], 223 y=old_position_and_size["y"], 224 height=old_position_and_size["height"], 225 width=old_position_and_size["width"], 226 ) 227 228 self.assertEqual(new_position_and_size["x"], old_position_and_size["x"]) 229 self.assertEqual(new_position_and_size["y"], old_position_and_size["y"]) 230 self.assertEqual(new_position_and_size["width"], old_position_and_size["width"]) 231 self.assertEqual( 232 new_position_and_size["height"], old_position_and_size["height"] 233 ) 234 235 def test_move_to_negative_coordinates(self): 236 old_position = self.marionette.window_rect 237 print("Current position: {}".format(old_position["x"], old_position["y"])) 238 new_position = self.marionette.set_window_rect(x=-8, y=-8) 239 print( 240 "Position after requesting move to negative coordinates: {}, {}".format( 241 new_position["x"], new_position["y"] 242 ) 243 ) 244 245 # Different systems will report more or less than (-8,-8) 246 # depending on the characteristics of the window manager, since 247 # the screenX/screenY position measures the chrome boundaries, 248 # including any WM decorations. 249 # 250 # This makes this hard to reliably test across different 251 # environments. Generally we are happy when calling 252 # marionette.set_window_position with negative coordinates does 253 # not throw. 254 # 255 # Because we have to cater to an unknown set of environments, 256 # the following assertions are the most common denominator that 257 # make this test pass, irregardless of system characteristics. 258 259 os = self.marionette.session_capabilities["platformName"] 260 version = self.marionette.session_capabilities["moz:platformVersion"] 261 262 # Regardless of platform, headless always supports being positioned 263 # off-screen. 264 if self.marionette.session_capabilities["moz:headless"]: 265 self.assertEqual(-8, new_position["x"]) 266 self.assertEqual(-8, new_position["y"]) 267 268 # Certain WMs prohibit windows from being moved off-screen, 269 # but we don't have this information. It should be safe to 270 # assume a window can be moved to (0,0) or less. 271 # Wayland doesn't supports being positioned at all. 272 elif os == "linux" and mozinfo.display != "wayland": 273 # certain WMs prohibit windows from being moved off-screen 274 self.assertLessEqual(new_position["x"], 0) 275 self.assertLessEqual(new_position["y"], 0) 276 277 # On macOS, windows can only be moved off the screen on the 278 # horizontal axis. The system menu bar also blocks windows from 279 # being moved to (0,0). 280 elif os == "mac": 281 self.assertEqual(-8, new_position["x"]) 282 # as of osx 11 (darwin 20), we have a 24 pixel menu bar 283 # https://phabricator.services.mozilla.com/D224403#7737386 284 if int(version.split(".")[0]) >= 20: 285 self.assertEqual(25, new_position["y"]) 286 else: 287 self.assertEqual(23, new_position["y"]) 288 289 # It turns out that Windows is the only platform on which the 290 # window can be reliably positioned off-screen. 291 elif os == "windows": 292 self.assertEqual(-8, new_position["x"]) 293 self.assertEqual(-8, new_position["y"]) 294 295 def test_resize_larger_than_screen(self): 296 new_size = self.marionette.set_window_rect( 297 width=self.max["width"] * 2, height=self.max["height"] * 2 298 ) 299 actual_size = self.marionette.window_rect 300 301 # in X the window size may be greater than the bounds of the screen 302 self.assertGreaterEqual(new_size["width"], self.max["width"]) 303 self.assertGreaterEqual(new_size["height"], self.max["height"]) 304 self.assertEqual(actual_size["width"], new_size["width"]) 305 self.assertEqual(actual_size["height"], new_size["height"]) 306 307 def test_resize_to_available_screen_size(self): 308 expected_size = self.marionette.set_window_rect( 309 width=self.max["width"], height=self.max["height"] 310 ) 311 result_size = self.marionette.window_rect 312 313 self.assertGreaterEqual(expected_size["width"], self.max["width"]) 314 self.assertGreaterEqual(expected_size["height"], self.max["height"]) 315 self.assertEqual(result_size["width"], expected_size["width"]) 316 self.assertEqual(result_size["height"], expected_size["height"]) 317 318 def test_resize_while_fullscreen(self): 319 self.marionette.fullscreen() 320 expected_size = self.marionette.set_window_rect( 321 width=self.max["width"] - 100, height=self.max["height"] - 100 322 ) 323 result_size = self.marionette.window_rect 324 325 self.assertTrue( 326 self.marionette.execute_script( 327 "return window.fullscreenElement == null", sandbox=None 328 ) 329 ) 330 self.assertEqual(self.max["width"] - 100, expected_size["width"]) 331 self.assertEqual(self.max["height"] - 100, expected_size["height"]) 332 self.assertEqual(result_size["width"], expected_size["width"]) 333 self.assertEqual(result_size["height"], expected_size["height"])