1
0
Fork 0
privacybadger/tests/selenium/widgets_test.py
Daniel Baumann 51333c7ef4
Adding upstream version 2020.10.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 23:00:13 +02:00

344 lines
12 KiB
Python

#!/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()