1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
#!/usr/bin/env python
import unittest
import pytest
import pbtest
from selenium.common.exceptions import (
NoSuchElementException,
TimeoutException,
)
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.ui import WebDriverWait
class OptionsTest(pbtest.PBSeleniumTest):
"""Make sure the options page works correctly."""
def assert_domain_toggle_state(self, domain, action, failure_msg):
clicker = self.find_el_by_css(f'div[data-origin="{domain}"]')
assert clicker.get_dom_attribute("class") == "clicker userset", failure_msg
switches_div = clicker.find_element(By.CSS_SELECTOR, ".switch-container")
assert switches_div.get_dom_attribute("class") == f"switch-container {action}", failure_msg
def find_domain_toggle_by_xpath(self, domain):
toggles_div = self.driver.find_element(By.ID, "blockedResourcesInner")
return toggles_div.find_element(By.XPATH, (
'.//div[@data-origin="{domain}"]'
# test that "origin" is one of the classes on the element:
# https://stackoverflow.com/a/1390680
'//div[contains(concat(" ", normalize-space(@class), " "), " origin ")]'
'//span[text()="{domain}"]'
).format(domain=domain))
def select_domain_list_tab(self):
self.find_el_by_css('a[href="#tab-tracking-domains"]').click()
def select_manage_data_tab(self):
self.find_el_by_css('a[href="#tab-manage-data"]').click()
def load_options_page(self):
self.load_url(self.options_url + '?all')
self.wait_for_script("return window.OPTIONS_INITIALIZED")
def test_reloading_should_reapply_filters(self):
FILTERVAL = "user"
self.load_options_page()
self.select_domain_list_tab()
# change a domain list filter
Select(self.find_el_by_css('#tracking-domains-type-filter')).select_by_value(FILTERVAL)
# reload page and assert filters are set
self.driver.refresh()
sel = Select(self.find_el_by_css('#tracking-domains-type-filter'))
assert sel.first_selected_option.get_property('value') == FILTERVAL
# open options page in a new window and assert filters are not set
self.open_window()
self.load_options_page()
self.select_domain_list_tab()
sel = Select(self.find_el_by_css('#tracking-domains-type-filter'))
assert not sel.first_selected_option.get_property('value')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type == "edge")
def test_adding_domain(self):
"""Ensure domain and tracker count are displayed."""
self.clear_tracker_data()
self.add_domain("pbtest.org", "block")
self.load_options_page()
self.select_domain_list_tab()
error_message = "The 'multiple tracker' message should be displayed after adding a domain"
assert self.driver.find_element(By.ID, "options_domain_list_trackers").is_displayed(), error_message
assert not self.driver.find_element(By.ID, "options_domain_list_no_trackers").is_displayed(), error_message
try:
self.find_domain_toggle_by_xpath("pbtest.org")
except NoSuchElementException:
self.fail("Tracking domain is not displayed")
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type == "edge")
def test_removing_domain(self):
"""Ensure domain is removed properly."""
self.clear_tracker_data()
self.add_domain("pbtest.org", "block")
self.load_options_page()
self.select_domain_list_tab()
domains = self.driver.find_elements(By.CSS_SELECTOR, 'div.clicker')
assert len(domains) == 1, "Should see exactly one domain in the list"
# remove displayed domain
remove_domain_element = self.find_el_by_xpath(
'.//div[@data-origin="pbtest.org"]'
'//a[@class="removeOrigin"]')
remove_domain_element.click()
# Make sure the alert is present. Otherwise we get intermittent errors.
WebDriverWait(self.driver, 3).until(EC.alert_is_present())
self.driver.switch_to.alert.accept()
# verify that only the 'no trackers' message is displayed
try:
WebDriverWait(self.driver, 5).until(
EC.visibility_of_element_located((By.ID, "options_domain_list_no_trackers")))
except TimeoutException:
self.fail("There should be a 'no trackers' message after deleting domain")
error_message = "Only the 'no trackers' message should be displayed"
assert not self.driver.find_element(By.ID, "options_domain_list_trackers").is_displayed(), error_message
# verify that no domains are displayed
try:
domains = self.driver.find_elements(By.CSS_SELECTOR, 'div.clicker')
except NoSuchElementException:
domains = []
assert len(domains) == 0, "No domains should be displayed after removal"
def test_reset_data(self):
self.load_options_page()
self.select_domain_list_tab()
# make sure the default tracker list includes many trackers
error_message = "By default, the tracker list should contain many trackers"
assert self.driver.find_element(By.ID, "options_domain_list_trackers").is_displayed(), error_message
assert not self.driver.find_element(By.ID, "options_domain_list_no_trackers").is_displayed(), error_message
# get the number of trackers in the seed data
default_summary_text = self.driver.find_element(By.ID, "options_domain_list_trackers").text
# Click on the "remove all data" button to empty the tracker lists, and
# click "OK" in the popup that ensues
self.select_manage_data_tab()
with self.wait_for_reload():
self.driver.find_element(By.ID, 'removeAllData').click()
self.driver.switch_to.alert.accept()
# now make sure the tracker list is empty
self.select_domain_list_tab()
error_message = "No trackers should be displayed after removing all data"
assert not self.driver.find_element(By.ID, "options_domain_list_trackers").is_displayed(), error_message
assert self.driver.find_element(By.ID, "options_domain_list_no_trackers").is_displayed(), error_message
# add new blocked domains
self.add_domain("pbtest.org", "block")
self.add_domain("pbtest1.org", "block")
# reload the options page
self.load_options_page()
self.select_domain_list_tab()
# make sure only two trackers are displayed now
actual_text = self.driver.find_element(By.ID, "options_domain_list_trackers").text
expected_text = self.js("return chrome.i18n.getMessage("
"'options_domain_list_trackers', [2, '']);").replace("</a>", "")
assert actual_text == expected_text
# click the "reset data" button to restore seed data and get rid of the
# domains we learned
self.select_manage_data_tab()
with self.wait_for_reload():
self.driver.find_element(By.ID, 'resetData').click()
self.driver.switch_to.alert.accept()
# make sure the same number of trackers are displayed as by default
self.select_domain_list_tab()
error_message = "After resetting data, tracker count should return to default"
assert self.driver.find_element(By.ID, "options_domain_list_trackers").text == default_summary_text, error_message
def tracking_user_overwrite(self, original_action, overwrite_action):
"""Ensure preferences are persisted when a user overwrites
PB's default behaviour for a domain."""
DOMAIN = "pbtest.org"
self.clear_tracker_data()
self.add_domain(DOMAIN, original_action)
self.load_options_page()
self.wait_for_script("return window.OPTIONS_INITIALIZED")
self.find_el_by_css('a[href="#tab-general-settings"]').click()
# enable learning to reveal the show-not-yet-blocked checkbox
self.find_el_by_css('#local-learning-checkbox').click()
self.select_domain_list_tab()
self.find_el_by_css('#tracking-domains-show-not-yet-blocked').click()
# wait for toggles to finish rendering
self.wait_for_script("return window.SLIDERS_DONE")
# Change user preferences
domain_id = DOMAIN.replace(".", "-")
self.wait_for_script(f"return $('#{overwrite_action}-{domain_id}')[0];")
self.js(f"$('#{overwrite_action}-{domain_id}').trigger('click');")
# Re-open the tab
self.load_options_page()
self.select_domain_list_tab()
self.find_el_by_css('#tracking-domains-show-not-yet-blocked').click()
# wait for toggles to finish rendering
self.wait_for_script("return window.SLIDERS_DONE")
# Check the user preferences for the domains are still displayed
failure_msg = (
f"Domain should be displayed as {overwrite_action} "
f"after user overwrite of PB's decision to {original_action}")
self.assert_domain_toggle_state(DOMAIN, overwrite_action, failure_msg)
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_allowed_block(self):
self.tracking_user_overwrite('allow', 'block')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_allowed_cookieblock(self):
self.tracking_user_overwrite('allow', 'cookieblock')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_cookieblocked_allow(self):
self.tracking_user_overwrite('cookieblock', 'allow')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_cookieblocked_block(self):
self.tracking_user_overwrite('cookieblock', 'block')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_blocked_allow(self):
self.tracking_user_overwrite('block', 'allow')
@pytest.mark.flaky(reruns=5, condition=pbtest.shim.browser_type in ("chrome", "edge"))
def test_tracking_user_overwrite_blocked_cookieblock(self):
self.tracking_user_overwrite('block', 'cookieblock')
# early-warning check for the open_in_tab attribute of options_ui
# https://github.com/EFForg/privacybadger/pull/1775#pullrequestreview-76940251
def test_options_ui_open_in_tab(self):
# open options page manually
self.open_window()
self.load_options_page()
# open the new user intro page
self.open_window()
self.load_url(self.first_run_url)
# save open windows
handles_before = set(self.driver.window_handles)
# open options page using dedicated chrome API
self.js("chrome.runtime.openOptionsPage();")
# if we switched to the previously manually opened options page, all good
# if we haven't, this must mean options_ui's open_in_tab no longer works
new_handles = set(self.driver.window_handles).difference(handles_before)
num_newly_opened_windows = len(new_handles)
if num_newly_opened_windows:
self.driver.switch_to.window(new_handles.pop())
assert num_newly_opened_windows == 0, (
"Expected to switch to existing options page, "
f"opened a new page ({self.driver.title}) instead: "
f"{self.driver.current_url}")
if __name__ == "__main__":
unittest.main()
|