tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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")