diff options
Diffstat (limited to '')
-rw-r--r-- | tests/selenium/widgets_test.py | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/tests/selenium/widgets_test.py b/tests/selenium/widgets_test.py new file mode 100644 index 0000000..d8bc2b5 --- /dev/null +++ b/tests/selenium/widgets_test.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +import unittest + +import pbtest + +from time import sleep + +from selenium.common.exceptions import ( + NoSuchElementException, + StaleElementReferenceException, + TimeoutException +) +from selenium.webdriver.common.keys import Keys + + +class WidgetsTest(pbtest.PBSeleniumTest): + + FIXTURES_URL = "https://efforg.github.io/privacybadger-test-fixtures/html/" + BASIC_FIXTURE_URL = FIXTURES_URL + "widget_basic.html" + DYNAMIC_FIXTURE_URL = FIXTURES_URL + "widget_dynamic.html" + THIRD_PARTY_DOMAIN = "privacybadger-tests.eff.org" + TYPE3_WIDGET_NAME = "Type 3 Widget" + TYPE4_WIDGET_NAME = "Type 4 Widget" + TYPE4_WIDGET_CLASS = "pb-type4-test-widget" + + def setUp(self): + self.set_up_widgets() + + def set_up_widgets(self): + """Reinitializes Privacy Badger's widget replacement definitions.""" + + widgetsJson = { + self.TYPE3_WIDGET_NAME: { + "domain": self.THIRD_PARTY_DOMAIN, + "buttonSelectors": [ + "iframe#pb-type3-test-widget" + ], + "replacementButton": { + "unblockDomains": [ + self.THIRD_PARTY_DOMAIN + ], + "type": 3 + } + }, + self.TYPE4_WIDGET_NAME: { + "domains": [ + self.THIRD_PARTY_DOMAIN + ], + "buttonSelectors": [ + "div." + self.TYPE4_WIDGET_CLASS + ], + "scriptSelectors": [ + "script." + self.TYPE4_WIDGET_CLASS + ], + "replacementButton": { + "unblockDomains": [ + self.THIRD_PARTY_DOMAIN + ], + "type": 4 + } + } + } + + # reinitialize widgets using above JSON + self.load_url(self.options_url) + self.js(( + "(function (widgetsJson) {" + " let bg = chrome.extension.getBackgroundPage();" + " bg.badger.widgetList = bg.widgetLoader.initializeWidgets(widgetsJson);" + "}(arguments[0]));" + ), widgetsJson) + + def switch_to_frame(self, selector): + self.wait_for_and_switch_to_frame(selector, timeout=1) + + def assert_widget(self, kind="type3"): + if kind == "type3": + self._assert_type3_widget() + elif kind == "type4": + self._assert_type4_widget() + else: + self.fail("Unknown widget type") + + def _assert_type3_widget(self): + try: + self.switch_to_frame('iframe[src]') + except (StaleElementReferenceException, TimeoutException): + self.fail("Unable to find widget frame") + + try: + self.wait_for_text('body', "Hello world!") + except TimeoutException: + self.fail("Unable to find expected widget text") + + self.driver.switch_to.default_content() + + def _assert_type4_widget(self): + try: + self.wait_for_text('div.' + self.TYPE4_WIDGET_CLASS, + "A third-party widget script was here") + except TimeoutException: + self.fail("Unable to find expected widget output") + + def assert_replacement(self, widget_name=None): + if not widget_name: + widget_name = self.TYPE3_WIDGET_NAME + + try: + self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name)) + except (StaleElementReferenceException, TimeoutException): + self.fail("Unable to find widget placeholder frame") + + try: + self.find_el_by_css("button[id^='btn-once-']") + self.find_el_by_css("button[id^='btn-site-']") + except TimeoutException: + self.fail("Unable to find expected widget placeholder buttons") + + self.driver.switch_to.default_content() + + def assert_widget_blocked(self): + try: + self.switch_to_frame('iframe[src]') + except TimeoutException: + self.fail("Widget frame should still be here") + + self.assertFalse( + self.txt_by_css('body'), "Widget frame should be empty") + + self.driver.switch_to.default_content() + + def assert_no_widget(self): + try: + self.switch_to_frame('iframe[src]') + self.fail("Widget frame should be missing") + except TimeoutException: + pass + self.driver.switch_to.default_content() + + def assert_no_replacement(self, widget_name=None): + if not widget_name: + widget_name = self.TYPE3_WIDGET_NAME + try: + self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name)) + self.fail("Widget placeholder frame should be missing") + except TimeoutException: + pass + self.driver.switch_to.default_content() + + def activate_widget(self, widget_name=None, once=True): + if not widget_name: + widget_name = self.TYPE3_WIDGET_NAME + id_prefix = 'btn-once' if once else 'btn-site' + self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name)) + self.find_el_by_css("button[id^='%s']" % id_prefix).click() + self.driver.switch_to.default_content() + + def test_replacement_basic(self): + # visit the basic widget fixture + self.load_url(self.BASIC_FIXTURE_URL) + # verify the widget is present + self.assert_widget() + + # block the test widget's domain + self.block_domain(self.THIRD_PARTY_DOMAIN) + + # revisit the fixture + self.load_url(self.BASIC_FIXTURE_URL) + # verify the widget got replaced + self.assert_replacement() + + def test_replacement_dynamic(self): + # visit the dynamic widget fixture + self.load_url(self.DYNAMIC_FIXTURE_URL) + # verify the widget is initially missing + self.assert_no_widget() + + # verify the widget shows up once you click on the trigger element + self.find_el_by_css('#widget-trigger').click() + self.assert_widget() + + # block the test widget's domain + self.block_domain(self.THIRD_PARTY_DOMAIN) + + # revisit the fixture + self.load_url(self.DYNAMIC_FIXTURE_URL) + # click on the trigger element + self.find_el_by_css('#widget-trigger').click() + # verify the widget got replaced + self.assert_replacement() + + def test_activation(self): + self.block_domain(self.THIRD_PARTY_DOMAIN) + self.load_url(self.BASIC_FIXTURE_URL) + self.assert_replacement() + + # click the "allow once" button + self.activate_widget() + + # verify the original widget is restored + self.assert_widget() + + # verify the type 4 widget is still replaced + try: + self.driver.find_element_by_css_selector( + 'div.' + self.TYPE4_WIDGET_CLASS) + self.fail("Widget output container div should be missing") + except NoSuchElementException: + pass + self.assert_replacement(self.TYPE4_WIDGET_NAME) + + self.activate_widget(self.TYPE4_WIDGET_NAME) + + # assert all script attributes were copied + script_el = self.driver.find_element_by_css_selector( + 'script.' + self.TYPE4_WIDGET_CLASS) + self.assertEqual(script_el.get_attribute('async'), "true") + self.assertEqual(script_el.get_attribute('data-foo'), "bar") + + self.assert_widget("type4") + + def test_activation_site(self): + self.block_domain(self.THIRD_PARTY_DOMAIN) + self.load_url(self.BASIC_FIXTURE_URL) + self.assert_replacement() + + # click the "allow once" button + self.activate_widget() + + # verify the original widget is restored + self.assert_widget() + + # open a new window (to get around widget activation caching) + self.open_window() + self.load_url(self.BASIC_FIXTURE_URL) + + # verify the widget got replaced + self.assert_replacement() + + # click the "allow on site" button + self.activate_widget(once=False) + + # verify the original widget is restored + self.assert_widget() + + # open a new window (to get around widget activation caching) + self.open_window() + self.load_url(self.BASIC_FIXTURE_URL) + + # verify basic widget is neither replaced nor blocked + self.assert_no_replacement() + self.assert_widget() + + def test_disabling_site(self): + self.block_domain(self.THIRD_PARTY_DOMAIN) + + self.disable_badger_on_site(self.BASIC_FIXTURE_URL) + + # verify basic widget is neither replaced nor blocked + self.load_url(self.BASIC_FIXTURE_URL) + self.assert_no_replacement() + self.assert_widget() + # type 4 replacement should also be missing + self.assert_no_replacement(self.TYPE4_WIDGET_NAME) + # while the type 4 widget script should have executed + self.assert_widget("type4") + + # verify dynamic widget is neither replaced nor blocked + self.load_url(self.DYNAMIC_FIXTURE_URL) + self.find_el_by_css('#widget-trigger').click() + self.assert_no_replacement() + self.assert_widget() + + def test_disabling_all_replacement(self): + self.block_domain(self.THIRD_PARTY_DOMAIN) + + # disable widget replacement + self.load_url(self.options_url) + self.wait_for_script("return window.OPTIONS_INITIALIZED") + self.find_el_by_css('a[href="#tab-manage-widgets"]').click() + self.driver.find_element_by_id('replace-widgets-checkbox').click() + + # verify basic widget is no longer replaced + self.load_url(self.BASIC_FIXTURE_URL) + self.assert_no_replacement() + self.assert_widget_blocked() + # type 4 replacement should also be missing + self.assert_no_replacement(self.TYPE4_WIDGET_NAME) + # type 4 widget should also have gotten blocked + try: + widget_div = self.driver.find_element_by_css_selector( + 'div.pb-type4-test-widget') + except NoSuchElementException: + self.fail("Widget div should still be here") + # check the div's text a few times to make sure it stays empty + for _ in range(3): + self.assertFalse(widget_div.text, + "Widget output container should remain empty") + sleep(1) + + # verify dynamic widget is no longer replaced + self.load_url(self.DYNAMIC_FIXTURE_URL) + self.find_el_by_css('#widget-trigger').click() + self.assert_no_replacement() + self.assert_widget_blocked() + + def test_disabling_replacement_for_one_widget(self): + self.block_domain(self.THIRD_PARTY_DOMAIN) + + # add the widget to the list of exceptions + self.load_url(self.options_url) + self.wait_for_script("return window.OPTIONS_INITIALIZED") + self.find_el_by_css('a[href="#tab-manage-widgets"]').click() + self.find_el_by_css('input[type="search"]').send_keys( + self.TYPE3_WIDGET_NAME, Keys.ENTER) + + # verify basic widget is no longer replaced + self.load_url(self.BASIC_FIXTURE_URL) + self.assert_no_replacement() + self.assert_widget_blocked() + # verify the type 4 widget is still replaced + self.assert_replacement(self.TYPE4_WIDGET_NAME) + + # verify dynamic widget is no longer replaced + self.load_url(self.DYNAMIC_FIXTURE_URL) + self.find_el_by_css('#widget-trigger').click() + self.assert_no_replacement() + self.assert_widget_blocked() + + def test_no_replacement_when_cookieblocked(self): + self.cookieblock_domain(self.THIRD_PARTY_DOMAIN) + self.load_url(self.BASIC_FIXTURE_URL) + + self.assert_no_replacement() + self.assert_no_replacement(self.TYPE4_WIDGET_NAME) + + self.assert_widget() + self.assert_widget("type4") + + +if __name__ == "__main__": + unittest.main() |