test_navigation.py (35250B)
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 5 import contextlib 6 import os 7 8 from urllib.parse import quote 9 10 from marionette_driver import By, errors, expected, Wait 11 from marionette_driver.keys import Keys 12 from marionette_driver.marionette import Alert 13 from marionette_harness import ( 14 MarionetteTestCase, 15 run_if_manage_instance, 16 WindowManagerMixin, 17 ) 18 19 here = os.path.abspath(os.path.dirname(__file__)) 20 21 22 BLACK_PIXEL = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" # noqa 23 RED_PIXEL = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=" # noqa 24 25 26 def inline(doc): 27 return "data:text/html;charset=utf-8,%s" % quote(doc) 28 29 30 def inline_image(data): 31 return "data:image/png;base64,%s" % data 32 33 34 class BaseNavigationTestCase(WindowManagerMixin, MarionetteTestCase): 35 def setUp(self): 36 super(BaseNavigationTestCase, self).setUp() 37 38 file_path = os.path.join(here, "data", "test.html").replace("\\", "/") 39 40 self.test_page_file_url = "file:///{}".format(file_path) 41 self.test_page_frameset = self.marionette.absolute_url("frameset.html") 42 self.test_page_insecure = self.fixtures.where_is("test.html", on="https") 43 self.test_page_not_remote = "about:robots" 44 self.test_page_push_state = self.marionette.absolute_url( 45 "navigation_pushstate.html" 46 ) 47 self.test_page_remote = self.marionette.absolute_url("test.html") 48 49 if self.marionette.session_capabilities["platformName"] == "mac": 50 self.mod_key = Keys.META 51 else: 52 self.mod_key = Keys.CONTROL 53 54 # Always use a blank new tab for an empty history 55 self.new_tab = self.open_tab() 56 self.marionette.switch_to_window(self.new_tab) 57 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 58 lambda _: self.history_length == 1, 59 message="The newly opened tab doesn't have a browser history length of 1", 60 ) 61 62 def tearDown(self): 63 self.marionette.timeout.reset() 64 65 self.close_all_tabs() 66 67 super(BaseNavigationTestCase, self).tearDown() 68 69 @property 70 def history_length(self): 71 return self.marionette.execute_script("return window.history.length;") 72 73 @property 74 def is_remote_tab(self): 75 with self.marionette.using_context("chrome"): 76 # TODO: DO NOT USE MOST RECENT WINDOW BUT CURRENT ONE 77 return self.marionette.execute_script( 78 """ 79 const { AppConstants } = ChromeUtils.importESModule( 80 "resource://gre/modules/AppConstants.sys.mjs" 81 ); 82 83 let win = null; 84 85 if (AppConstants.MOZ_APP_NAME == "fennec") { 86 win = Services.wm.getMostRecentWindow("navigator:browser"); 87 } else { 88 const { BrowserWindowTracker } = ChromeUtils.importESModule( 89 "resource:///modules/BrowserWindowTracker.sys.mjs" 90 ); 91 win = BrowserWindowTracker.getTopWindow(); 92 } 93 94 let tabBrowser = null; 95 96 // Fennec 97 if (win.BrowserApp) { 98 tabBrowser = win.BrowserApp.selectedBrowser; 99 100 // Firefox 101 } else if (win.gBrowser) { 102 tabBrowser = win.gBrowser.selectedBrowser; 103 104 } else { 105 return null; 106 } 107 108 return tabBrowser.isRemoteBrowser; 109 """ 110 ) 111 112 @property 113 def ready_state(self): 114 return self.marionette.execute_script( 115 "return window.document.readyState;", sandbox=None 116 ) 117 118 119 class TestNavigate(BaseNavigationTestCase): 120 def test_set_location_through_execute_script(self): 121 # To avoid unexpected remoteness changes and a hang in any non-navigation 122 # command (bug 1519354) when navigating via the location bar, already 123 # pre-load a page which causes a remoteness change. 124 self.marionette.navigate(self.test_page_push_state) 125 126 self.marionette.execute_script( 127 "window.location.href = arguments[0];", 128 script_args=(self.test_page_remote,), 129 sandbox=None, 130 ) 131 132 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 133 expected.element_present(*(By.ID, "testh1")), 134 message="Target element 'testh1' has not been found", 135 ) 136 137 self.assertEqual(self.test_page_remote, self.marionette.get_url()) 138 139 def test_navigate_chrome_unsupported_error(self): 140 with self.marionette.using_context("chrome"): 141 self.assertRaises( 142 errors.UnsupportedOperationException, 143 self.marionette.navigate, 144 "about:blank", 145 ) 146 self.assertRaises( 147 errors.UnsupportedOperationException, self.marionette.go_back 148 ) 149 self.assertRaises( 150 errors.UnsupportedOperationException, self.marionette.go_forward 151 ) 152 self.assertRaises( 153 errors.UnsupportedOperationException, self.marionette.refresh 154 ) 155 156 def test_get_current_url_returns_top_level_browsing_context_url(self): 157 page_iframe = self.marionette.absolute_url("test_iframe.html") 158 159 self.marionette.navigate(page_iframe) 160 self.assertEqual(page_iframe, self.marionette.get_url()) 161 frame = self.marionette.find_element(By.CSS_SELECTOR, "#test_iframe") 162 self.marionette.switch_to_frame(frame) 163 self.assertEqual(page_iframe, self.marionette.get_url()) 164 165 def test_get_current_url(self): 166 self.marionette.navigate(self.test_page_remote) 167 self.assertEqual(self.test_page_remote, self.marionette.get_url()) 168 self.marionette.navigate("about:blank") 169 self.assertEqual("about:blank", self.marionette.get_url()) 170 171 def test_navigate_in_child_frame_changes_to_top(self): 172 self.marionette.navigate(self.test_page_frameset) 173 frame = self.marionette.find_element(By.NAME, "third") 174 self.marionette.switch_to_frame(frame) 175 self.assertRaises( 176 errors.NoSuchElementException, 177 self.marionette.find_element, 178 By.NAME, 179 "third", 180 ) 181 182 self.marionette.navigate(self.test_page_frameset) 183 self.marionette.find_element(By.NAME, "third") 184 185 def test_invalid_url(self): 186 with self.assertRaises(errors.MarionetteException): 187 self.marionette.navigate("foo") 188 with self.assertRaises(errors.MarionetteException): 189 self.marionette.navigate("thisprotocoldoesnotexist://") 190 191 def test_find_element_state_complete(self): 192 self.marionette.navigate(self.test_page_remote) 193 self.assertEqual("complete", self.ready_state) 194 self.assertTrue(self.marionette.find_element(By.ID, "mozLink")) 195 196 def test_navigate_timeout_error_no_remoteness_change(self): 197 is_remote_before_timeout = self.is_remote_tab 198 self.marionette.timeout.page_load = 0.5 199 with self.assertRaises(errors.TimeoutException): 200 self.marionette.navigate(self.marionette.absolute_url("slow")) 201 self.assertEqual(self.is_remote_tab, is_remote_before_timeout) 202 203 def test_navigate_timeout_error_remoteness_change(self): 204 self.assertTrue(self.is_remote_tab) 205 self.marionette.navigate("about:robots") 206 self.assertFalse(self.is_remote_tab) 207 208 self.marionette.timeout.page_load = 0.5 209 with self.assertRaises(errors.TimeoutException): 210 self.marionette.navigate(self.marionette.absolute_url("slow")) 211 212 def test_navigate_to_same_image_document_twice(self): 213 self.marionette.navigate(self.fixtures.where_is("black.png")) 214 self.assertIn("black.png", self.marionette.title) 215 self.marionette.navigate(self.fixtures.where_is("black.png")) 216 self.assertIn("black.png", self.marionette.title) 217 218 def test_navigate_hash_change(self): 219 doc = inline("<p id=foo>") 220 self.marionette.navigate(doc) 221 self.marionette.execute_script("window.visited = true", sandbox=None) 222 self.marionette.navigate("{}#foo".format(doc)) 223 self.assertTrue( 224 self.marionette.execute_script("return window.visited", sandbox=None) 225 ) 226 227 def test_navigate_hash_argument_identical(self): 228 test_page = "{}#foo".format(inline("<p id=foo>")) 229 230 self.marionette.navigate(test_page) 231 self.marionette.find_element(By.ID, "foo") 232 self.marionette.navigate(test_page) 233 self.marionette.find_element(By.ID, "foo") 234 235 def test_navigate_hash_argument_differnt(self): 236 test_page = "{}#Foo".format(inline("<p id=foo>")) 237 238 self.marionette.navigate(test_page) 239 self.marionette.find_element(By.ID, "foo") 240 self.marionette.navigate(test_page.lower()) 241 self.marionette.find_element(By.ID, "foo") 242 243 def test_navigate_history_pushstate(self): 244 target_page = self.marionette.absolute_url("navigation_pushstate_target.html") 245 246 self.marionette.navigate(self.test_page_push_state) 247 self.marionette.find_element(By.ID, "forward").click() 248 249 # By using pushState() the URL is updated but the target page is not loaded 250 # and as such the element is not displayed 251 self.assertEqual(self.marionette.get_url(), target_page) 252 with self.assertRaises(errors.NoSuchElementException): 253 self.marionette.find_element(By.ID, "target") 254 255 self.marionette.go_back() 256 self.assertEqual(self.marionette.get_url(), self.test_page_push_state) 257 258 # The target page still gets not loaded 259 self.marionette.go_forward() 260 self.assertEqual(self.marionette.get_url(), target_page) 261 with self.assertRaises(errors.NoSuchElementException): 262 self.marionette.find_element(By.ID, "target") 263 264 # Navigating to a different page, and returning to the injected 265 # page, it will be loaded. 266 self.marionette.navigate(self.test_page_remote) 267 self.assertEqual(self.marionette.get_url(), self.test_page_remote) 268 269 self.marionette.go_back() 270 self.assertEqual(self.marionette.get_url(), target_page) 271 self.marionette.find_element(By.ID, "target") 272 273 self.marionette.go_back() 274 self.assertEqual(self.marionette.get_url(), self.test_page_push_state) 275 276 def test_navigate_file_url(self): 277 self.marionette.navigate(self.test_page_file_url) 278 self.marionette.find_element(By.ID, "file-url") 279 self.marionette.navigate(self.test_page_remote) 280 281 def test_navigate_file_url_remoteness_change(self): 282 self.marionette.navigate("about:robots") 283 self.assertFalse(self.is_remote_tab) 284 285 self.marionette.navigate(self.test_page_file_url) 286 self.assertTrue(self.is_remote_tab) 287 self.marionette.find_element(By.ID, "file-url") 288 289 self.marionette.navigate("about:robots") 290 self.assertFalse(self.is_remote_tab) 291 292 def test_no_such_element_after_remoteness_change(self): 293 self.marionette.navigate(self.test_page_file_url) 294 self.assertTrue(self.is_remote_tab) 295 elem = self.marionette.find_element(By.ID, "file-url") 296 297 self.marionette.navigate("about:robots") 298 self.assertFalse(self.is_remote_tab) 299 300 with self.assertRaises(errors.StaleElementException): 301 elem.click() 302 303 def test_about_blank_for_new_docshell(self): 304 self.assertEqual(self.marionette.get_url(), "about:blank") 305 306 self.marionette.navigate("about:blank") 307 308 def test_about_newtab(self): 309 self.marionette.navigate("about:newtab") 310 311 self.marionette.navigate(self.test_page_remote) 312 self.marionette.find_element(By.ID, "testDiv") 313 314 @run_if_manage_instance("Only runnable if Marionette manages the instance") 315 def test_focus_after_navigation(self): 316 self.marionette.restart() 317 318 self.marionette.navigate(inline("<input autofocus>")) 319 320 # Per spec, autofocus candidates will be 321 # flushed by next paint, so we use rAF here to 322 # ensure the candidates are flushed. 323 self.marionette.execute_async_script( 324 """ 325 const callback = arguments[arguments.length - 1]; 326 window.requestAnimationFrame(function() { 327 window.requestAnimationFrame(callback); 328 }); 329 """ 330 ) 331 focus_el = self.marionette.find_element(By.CSS_SELECTOR, ":focus") 332 self.assertEqual(self.marionette.get_active_element(), focus_el) 333 334 def test_no_hang_when_navigating_after_closing_original_tab(self): 335 # Close the start tab 336 self.marionette.switch_to_window(self.start_tab) 337 self.marionette.close() 338 339 self.marionette.switch_to_window(self.new_tab) 340 self.marionette.navigate(self.test_page_remote) 341 342 def test_type_to_non_remote_tab(self): 343 self.marionette.navigate(self.test_page_not_remote) 344 self.assertFalse(self.is_remote_tab) 345 346 with self.marionette.using_context("chrome"): 347 urlbar = self.marionette.execute_script("return gURLBar.inputField") 348 urlbar.send_keys(self.mod_key + "a") 349 urlbar.send_keys(self.mod_key + "x") 350 urlbar.send_keys("about:support" + Keys.ENTER) 351 352 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 353 lambda mn: mn.get_url() == "about:support", 354 message="'about:support' hasn't been loaded", 355 ) 356 self.assertFalse(self.is_remote_tab) 357 358 def test_type_to_remote_tab(self): 359 self.assertTrue(self.is_remote_tab) 360 361 with self.marionette.using_context("chrome"): 362 urlbar = self.marionette.execute_script("return gURLBar.inputField") 363 urlbar.send_keys(self.mod_key + "a") 364 urlbar.send_keys(self.mod_key + "x") 365 urlbar.send_keys(self.test_page_remote + Keys.ENTER) 366 367 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 368 lambda mn: mn.get_url() == self.test_page_remote, 369 message="'{}' hasn't been loaded".format(self.test_page_remote), 370 ) 371 self.assertTrue(self.is_remote_tab) 372 373 def test_navigate_after_deleting_session(self): 374 self.marionette.delete_session() 375 self.marionette.start_session() 376 377 self.marionette.navigate(self.test_page_remote) 378 self.assertEqual(self.test_page_remote, self.marionette.get_url()) 379 380 381 class TestBackForwardNavigation(BaseNavigationTestCase): 382 def run_bfcache_test(self, test_pages): 383 # Helper method to run simple back and forward testcases. 384 385 def check_page_status(page, expected_history_length): 386 if "alert_text" in page: 387 self.assertEqual(Alert(self.marionette).text, page["alert_text"]) 388 389 self.assertEqual(self.marionette.get_url(), page["url"]) 390 self.assertEqual(self.history_length, expected_history_length) 391 392 if "is_remote" in page: 393 self.assertEqual( 394 page["is_remote"], 395 self.is_remote_tab, 396 "'{}' doesn't match expected remoteness state: {}".format( 397 page["url"], page["is_remote"] 398 ), 399 ) 400 401 if "callback" in page and callable(page["callback"]): 402 page["callback"]() 403 404 for index, page in enumerate(test_pages): 405 if "error" in page: 406 with self.assertRaises(page["error"]): 407 self.marionette.navigate(page["url"]) 408 else: 409 self.marionette.navigate(page["url"]) 410 411 check_page_status(page, index + 1) 412 413 # Now going back in history for all test pages by backward iterating 414 # through the list (-1) and skipping the first entry at the end (-2). 415 for page in test_pages[-2::-1]: 416 if "error" in page: 417 with self.assertRaises(page["error"]): 418 self.marionette.go_back() 419 else: 420 self.marionette.go_back() 421 422 check_page_status(page, len(test_pages)) 423 424 # Now going forward in history by skipping the first entry. 425 for page in test_pages[1::]: 426 if "error" in page: 427 with self.assertRaises(page["error"]): 428 self.marionette.go_forward() 429 else: 430 self.marionette.go_forward() 431 432 check_page_status(page, len(test_pages)) 433 434 def test_no_history_items(self): 435 # Both methods should not raise a failure if no navigation is possible 436 self.marionette.go_back() 437 self.marionette.go_forward() 438 439 def test_data_urls(self): 440 test_pages = [ 441 {"url": inline("<p>foobar</p>")}, 442 {"url": self.test_page_remote}, 443 {"url": inline("<p>foobar</p>")}, 444 ] 445 self.run_bfcache_test(test_pages) 446 447 def test_same_document_hash_change(self): 448 test_pages = [ 449 {"url": "{}#23".format(self.test_page_remote)}, 450 {"url": self.test_page_remote}, 451 {"url": "{}#42".format(self.test_page_remote)}, 452 ] 453 self.run_bfcache_test(test_pages) 454 455 def test_file_url(self): 456 test_pages = [ 457 {"url": self.test_page_remote}, 458 {"url": self.test_page_file_url}, 459 {"url": self.test_page_remote}, 460 ] 461 self.run_bfcache_test(test_pages) 462 463 def test_frameset(self): 464 test_pages = [ 465 {"url": self.marionette.absolute_url("frameset.html")}, 466 {"url": self.test_page_remote}, 467 {"url": self.marionette.absolute_url("frameset.html")}, 468 ] 469 self.run_bfcache_test(test_pages) 470 471 def test_frameset_after_navigating_in_frame(self): 472 test_element_locator = (By.ID, "email") 473 474 self.marionette.navigate(self.test_page_remote) 475 self.assertEqual(self.marionette.get_url(), self.test_page_remote) 476 self.assertEqual(self.history_length, 1) 477 page = self.marionette.absolute_url("frameset.html") 478 self.marionette.navigate(page) 479 self.assertEqual(self.marionette.get_url(), page) 480 self.assertEqual(self.history_length, 2) 481 frame = self.marionette.find_element(By.ID, "fifth") 482 self.marionette.switch_to_frame(frame) 483 link = self.marionette.find_element(By.ID, "linkId") 484 link.click() 485 486 # We cannot use get_url() to wait until the target page has been loaded, 487 # because it will return the URL of the top browsing context and doesn't 488 # wait for the page load to be complete. 489 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 490 expected.element_present(*test_element_locator), 491 message="Target element 'email' has not been found", 492 ) 493 self.assertEqual(self.history_length, 3) 494 495 # Go back to the frame the click navigated away from 496 self.marionette.go_back() 497 self.assertEqual(self.marionette.get_url(), page) 498 with self.assertRaises(errors.NoSuchElementException): 499 self.marionette.find_element(*test_element_locator) 500 501 # Go back to the non-frameset page 502 self.marionette.switch_to_parent_frame() 503 self.marionette.go_back() 504 self.assertEqual(self.marionette.get_url(), self.test_page_remote) 505 506 # Go forward to the frameset page 507 self.marionette.go_forward() 508 self.assertEqual(self.marionette.get_url(), page) 509 510 # Go forward to the frame the click navigated to 511 # TODO: See above for automatic browser context switches. Hard to do here 512 frame = self.marionette.find_element(By.ID, "fifth") 513 self.marionette.switch_to_frame(frame) 514 self.marionette.go_forward() 515 self.marionette.find_element(*test_element_locator) 516 self.assertEqual(self.marionette.get_url(), page) 517 518 def test_image_to_html_to_image(self): 519 test_pages = [ 520 {"url": self.marionette.absolute_url("black.png")}, 521 {"url": self.test_page_remote}, 522 {"url": self.marionette.absolute_url("white.png")}, 523 ] 524 self.run_bfcache_test(test_pages) 525 526 def test_image_to_image(self): 527 test_pages = [ 528 {"url": self.marionette.absolute_url("black.png")}, 529 {"url": self.marionette.absolute_url("white.png")}, 530 {"url": inline_image(RED_PIXEL)}, 531 {"url": inline_image(BLACK_PIXEL)}, 532 {"url": self.marionette.absolute_url("black.png")}, 533 ] 534 self.run_bfcache_test(test_pages) 535 536 def test_remoteness_change(self): 537 test_pages = [ 538 {"url": "about:robots", "is_remote": False}, 539 {"url": self.test_page_remote, "is_remote": True}, 540 {"url": "about:robots", "is_remote": False}, 541 ] 542 self.run_bfcache_test(test_pages) 543 544 def test_non_remote_about_pages(self): 545 test_pages = [ 546 {"url": "about:preferences", "is_remote": False}, 547 {"url": "about:robots", "is_remote": False}, 548 {"url": "about:support", "is_remote": False}, 549 ] 550 self.run_bfcache_test(test_pages) 551 552 def test_navigate_to_requested_about_page_after_error_page(self): 553 test_pages = [ 554 {"url": "about:neterror"}, 555 {"url": self.test_page_remote}, 556 {"url": "about:blocked"}, 557 ] 558 self.run_bfcache_test(test_pages) 559 560 def test_timeout_error(self): 561 urls = [ 562 self.marionette.absolute_url("slow?delay=3"), 563 self.test_page_remote, 564 self.marionette.absolute_url("slow?delay=4"), 565 ] 566 567 # First, load all pages completely to get them added to the cache 568 for index, url in enumerate(urls): 569 self.marionette.navigate(url) 570 self.assertEqual(url, self.marionette.get_url()) 571 self.assertEqual(self.history_length, index + 1) 572 573 self.marionette.go_back() 574 self.assertEqual(urls[1], self.marionette.get_url()) 575 576 # Force triggering a timeout error 577 self.marionette.timeout.page_load = 0.5 578 with self.assertRaises(errors.TimeoutException): 579 self.marionette.go_back() 580 self.marionette.timeout.reset() 581 582 delay = Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 583 expected.element_present(By.ID, "delay"), 584 message="Target element 'delay' has not been found after timeout in 'back'", 585 ) 586 self.assertEqual(delay.text, "3") 587 588 self.marionette.go_forward() 589 self.assertEqual(urls[1], self.marionette.get_url()) 590 591 # Force triggering a timeout error 592 self.marionette.timeout.page_load = 0.5 593 with self.assertRaises(errors.TimeoutException): 594 self.marionette.go_forward() 595 self.marionette.timeout.reset() 596 597 delay = Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 598 expected.element_present(By.ID, "delay"), 599 message="Target element 'delay' has not been found after timeout in 'forward'", 600 ) 601 self.assertEqual(delay.text, "4") 602 603 def test_certificate_error(self): 604 test_pages = [ 605 { 606 "url": self.test_page_insecure, 607 "error": errors.InsecureCertificateException, 608 }, 609 {"url": self.test_page_remote}, 610 { 611 "url": self.test_page_insecure, 612 "error": errors.InsecureCertificateException, 613 }, 614 ] 615 self.run_bfcache_test(test_pages) 616 617 618 class TestRefresh(BaseNavigationTestCase): 619 def test_basic(self): 620 self.marionette.navigate(self.test_page_remote) 621 self.assertEqual(self.test_page_remote, self.marionette.get_url()) 622 623 self.marionette.execute_script( 624 """ 625 let elem = window.document.createElement('div'); 626 elem.id = 'someDiv'; 627 window.document.body.appendChild(elem); 628 """ 629 ) 630 self.marionette.find_element(By.ID, "someDiv") 631 632 self.marionette.refresh() 633 self.assertEqual(self.test_page_remote, self.marionette.get_url()) 634 with self.assertRaises(errors.NoSuchElementException): 635 self.marionette.find_element(By.ID, "someDiv") 636 637 def test_refresh_in_child_frame_navigates_to_top(self): 638 self.marionette.navigate(self.test_page_frameset) 639 self.assertEqual(self.test_page_frameset, self.marionette.get_url()) 640 641 frame = self.marionette.find_element(By.NAME, "third") 642 self.marionette.switch_to_frame(frame) 643 self.assertRaises( 644 errors.NoSuchElementException, 645 self.marionette.find_element, 646 By.NAME, 647 "third", 648 ) 649 650 self.marionette.refresh() 651 self.marionette.find_element(By.NAME, "third") 652 653 def test_file_url(self): 654 self.marionette.navigate(self.test_page_file_url) 655 self.assertEqual(self.test_page_file_url, self.marionette.get_url()) 656 657 self.marionette.refresh() 658 self.assertEqual(self.test_page_file_url, self.marionette.get_url()) 659 660 def test_image(self): 661 image = self.marionette.absolute_url("black.png") 662 663 self.marionette.navigate(image) 664 self.assertEqual(image, self.marionette.get_url()) 665 666 self.marionette.refresh() 667 self.assertEqual(image, self.marionette.get_url()) 668 669 def test_history_pushstate(self): 670 target_page = self.marionette.absolute_url("navigation_pushstate_target.html") 671 672 self.marionette.navigate(self.test_page_push_state) 673 self.marionette.find_element(By.ID, "forward").click() 674 675 # By using pushState() the URL is updated but the target page is not loaded 676 # and as such the element is not displayed 677 self.assertEqual(self.marionette.get_url(), target_page) 678 with self.assertRaises(errors.NoSuchElementException): 679 self.marionette.find_element(By.ID, "target") 680 681 # Refreshing the target page will trigger a full page load. 682 self.marionette.refresh() 683 self.assertEqual(self.marionette.get_url(), target_page) 684 self.marionette.find_element(By.ID, "target") 685 686 self.marionette.go_back() 687 self.assertEqual(self.marionette.get_url(), self.test_page_push_state) 688 689 def test_timeout_error(self): 690 slow_page = self.marionette.absolute_url("slow?delay=3") 691 692 self.marionette.navigate(slow_page) 693 self.assertEqual(slow_page, self.marionette.get_url()) 694 695 self.marionette.timeout.page_load = 0.5 696 with self.assertRaises(errors.TimeoutException): 697 self.marionette.refresh() 698 self.assertEqual(slow_page, self.marionette.get_url()) 699 700 def test_insecure_error(self): 701 with self.assertRaises(errors.InsecureCertificateException): 702 self.marionette.navigate(self.test_page_insecure) 703 self.assertEqual(self.marionette.get_url(), self.test_page_insecure) 704 705 with self.assertRaises(errors.InsecureCertificateException): 706 self.marionette.refresh() 707 708 709 class TestTLSNavigation(BaseNavigationTestCase): 710 insecure_tls = {"acceptInsecureCerts": True} 711 secure_tls = {"acceptInsecureCerts": False} 712 713 def setUp(self): 714 super(TestTLSNavigation, self).setUp() 715 716 self.test_page_insecure = self.fixtures.where_is("test.html", on="https") 717 718 self.marionette.delete_session() 719 self.capabilities = self.marionette.start_session(self.insecure_tls) 720 721 def tearDown(self): 722 try: 723 self.marionette.delete_session() 724 self.marionette.start_session() 725 except: 726 pass 727 728 super(TestTLSNavigation, self).tearDown() 729 730 @contextlib.contextmanager 731 def safe_session(self): 732 try: 733 self.capabilities = self.marionette.start_session(self.secure_tls) 734 self.assertFalse(self.capabilities["acceptInsecureCerts"]) 735 # Always use a blank new tab for an empty history 736 self.new_tab = self.open_tab() 737 self.marionette.switch_to_window(self.new_tab) 738 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 739 lambda _: self.history_length == 1, 740 message="The newly opened tab doesn't have a browser history length of 1", 741 ) 742 yield self.marionette 743 finally: 744 self.close_all_tabs() 745 self.marionette.delete_session() 746 747 @contextlib.contextmanager 748 def unsafe_session(self): 749 try: 750 self.capabilities = self.marionette.start_session(self.insecure_tls) 751 self.assertTrue(self.capabilities["acceptInsecureCerts"]) 752 # Always use a blank new tab for an empty history 753 self.new_tab = self.open_tab() 754 self.marionette.switch_to_window(self.new_tab) 755 Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( 756 lambda _: self.history_length == 1, 757 message="The newly opened tab doesn't have a browser history length of 1", 758 ) 759 yield self.marionette 760 finally: 761 self.close_all_tabs() 762 self.marionette.delete_session() 763 764 def test_navigate_by_command(self): 765 self.marionette.navigate(self.test_page_insecure) 766 self.assertIn("https", self.marionette.get_url()) 767 768 def test_navigate_by_click(self): 769 link_url = self.test_page_insecure 770 self.marionette.navigate( 771 inline("<a href=%s>https is the future</a>" % link_url) 772 ) 773 self.marionette.find_element(By.TAG_NAME, "a").click() 774 self.assertIn("https", self.marionette.get_url()) 775 776 def test_deactivation(self): 777 invalid_cert_url = self.test_page_insecure 778 779 self.marionette.delete_session() 780 781 print("with safe session") 782 with self.safe_session() as session: 783 with self.assertRaises(errors.InsecureCertificateException): 784 session.navigate(invalid_cert_url) 785 786 print("with unsafe session") 787 with self.unsafe_session() as session: 788 session.navigate(invalid_cert_url) 789 790 print("with safe session again") 791 with self.safe_session() as session: 792 with self.assertRaises(errors.InsecureCertificateException): 793 session.navigate(invalid_cert_url) 794 795 796 class TestPageLoadStrategy(BaseNavigationTestCase): 797 def setUp(self): 798 super(TestPageLoadStrategy, self).setUp() 799 800 # Test page that delays the response and as such the document to be 801 # loaded. It is used for testing the page load strategy "none". 802 self.test_page_slow = self.marionette.absolute_url("slow") 803 804 # Similar to "slow" but additionally triggers a cross group navigation 805 # which triggers a replacement of the top-level browsing context. 806 self.test_page_slow_coop = self.marionette.absolute_url("slow-coop") 807 808 # Test page that contains a slow loading <img> element which delays the 809 # "load" but not the "DOMContentLoaded" event. 810 self.test_page_slow_resource = self.marionette.absolute_url( 811 "slow_resource.html" 812 ) 813 814 def tearDown(self): 815 self.marionette.delete_session() 816 self.marionette.start_session() 817 818 super(TestPageLoadStrategy, self).tearDown() 819 820 def test_none(self): 821 self.marionette.delete_session() 822 self.marionette.start_session({"pageLoadStrategy": "none"}) 823 824 # Navigate will return immediately. As such wait for the target URL to 825 # be the current location, and the element to exist. 826 self.marionette.navigate(self.test_page_slow) 827 with self.assertRaises(errors.NoSuchElementException): 828 self.marionette.find_element(By.ID, "delay") 829 830 Wait( 831 self.marionette, 832 ignored_exceptions=errors.NoSuchElementException, 833 timeout=self.marionette.timeout.page_load, 834 ).until(lambda _: self.marionette.find_element(By.ID, "delay")) 835 836 self.assertEqual(self.marionette.get_url(), self.test_page_slow) 837 838 def test_none_with_new_session_waits_for_page_loaded(self): 839 self.marionette.delete_session() 840 self.marionette.start_session({"pageLoadStrategy": "none"}) 841 842 # Navigate will return immediately. 843 self.marionette.navigate(self.test_page_slow) 844 845 # Make sure that when creating a new session right away it waits 846 # until the page has been finished loading. 847 self.marionette.delete_session() 848 self.marionette.start_session() 849 850 self.assertEqual(self.marionette.get_url(), self.test_page_slow) 851 self.assertEqual(self.ready_state, "complete") 852 self.marionette.find_element(By.ID, "delay") 853 854 def test_none_with_new_session_waits_for_page_loaded_remoteness_change(self): 855 self.marionette.delete_session() 856 self.marionette.start_session({"pageLoadStrategy": "none"}) 857 858 # Navigate will return immediately. 859 self.marionette.navigate(self.test_page_slow_coop) 860 861 # Make sure that when creating a new session right away it waits 862 # until the page has been finished loading. 863 self.marionette.delete_session() 864 self.marionette.start_session() 865 866 self.assertEqual(self.marionette.get_url(), self.test_page_slow_coop) 867 self.assertEqual(self.ready_state, "complete") 868 self.marionette.find_element(By.ID, "delay") 869 870 def test_eager(self): 871 self.marionette.delete_session() 872 self.marionette.start_session({"pageLoadStrategy": "eager"}) 873 874 self.marionette.navigate(self.test_page_slow_resource) 875 self.assertEqual(self.ready_state, "interactive") 876 self.assertEqual(self.marionette.get_url(), self.test_page_slow_resource) 877 self.marionette.find_element(By.ID, "slow") 878 879 def test_normal(self): 880 self.marionette.delete_session() 881 self.marionette.start_session({"pageLoadStrategy": "normal"}) 882 883 self.marionette.navigate(self.test_page_slow_resource) 884 self.assertEqual(self.marionette.get_url(), self.test_page_slow_resource) 885 self.assertEqual(self.ready_state, "complete") 886 self.marionette.find_element(By.ID, "slow") 887 888 def test_strategy_after_remoteness_change(self): 889 """Bug 1378191 - Reset of capabilities after listener reload.""" 890 self.marionette.delete_session() 891 self.marionette.start_session({"pageLoadStrategy": "eager"}) 892 893 # Trigger a remoteness change which will reload the listener script 894 self.assertTrue( 895 self.is_remote_tab, "Initial tab doesn't have remoteness flag set" 896 ) 897 self.marionette.navigate("about:robots") 898 self.assertFalse(self.is_remote_tab, "Tab has remoteness flag set") 899 self.marionette.navigate(self.test_page_slow_resource) 900 self.assertEqual(self.ready_state, "interactive")