From ad69f9c86b950cc84ca103e65824b9c9129d3999 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 31 Jan 2022 18:06:13 +0100 Subject: add support for testing with other browsers (especially Abrowser and Librewolf) There are still some spurious failures when running under those newer browsers. Those will be systematically investigated and fixed. --- test/data/pages/scripts_to_block_1.html | 2 +- test/misc_constants.py | 12 +++++--- test/profiles.py | 6 ++-- test/unit/test_indexeddb.py | 23 +++++++------- test/unit/test_item_list.py | 34 --------------------- test/unit/test_item_preview.py | 51 ++++++++++++++++++++++++-------- test/unit/test_patterns_query_manager.py | 29 +++++++++++------- test/unit/test_popup.py | 32 ++++++++++++++++---- 8 files changed, 106 insertions(+), 83 deletions(-) (limited to 'test') diff --git a/test/data/pages/scripts_to_block_1.html b/test/data/pages/scripts_to_block_1.html index 1aa49ee..164979d 100644 --- a/test/data/pages/scripts_to_block_1.html +++ b/test/data/pages/scripts_to_block_1.html @@ -37,7 +37,7 @@ href="javascript:window.__run = [...(window.__run || []), 'href'];void(0);"> Click Meee! - diff --git a/test/misc_constants.py b/test/misc_constants.py index db9f3f1..51602b3 100644 --- a/test/misc_constants.py +++ b/test/misc_constants.py @@ -27,6 +27,7 @@ Miscellaneous data that were found useful # file's license. Although I request that you do not make use of this code # in a proprietary program, I am not going to enforce this in court. +import re from pathlib import Path here = Path(__file__).resolve().parent @@ -36,10 +37,13 @@ awk_script_name = 'compute_scripts.awk' unit_test_defines = ['-D', 'MOZILLA', '-D', 'MV2', '-D', 'TEST', '-D', 'UNIT_TEST', '-D', 'DEBUG'] -default_firefox_binary = '/usr/lib/icecat/icecat' -# The browser might be loading some globally-installed add-ons by default. They -# could interfere with the tests, so we'll disable all of them. -default_clean_profile_dir = here / 'default_profile' / 'icecat_empty' +conf_line_regex = re.compile(r'^([^=]+)=(.*)$') +conf_settings = {} +with open(here.parent / 'record.conf', 'rt') as conf: + for line in conf.readlines(): + match = conf_line_regex.match(line) + if match: + conf_settings[match.group(1).strip()] = match.group(2).strip() default_proxy_host = '127.0.0.1' default_proxy_port = 1337 diff --git a/test/profiles.py b/test/profiles.py index 4892894..ae997fc 100755 --- a/test/profiles.py +++ b/test/profiles.py @@ -80,7 +80,7 @@ def set_webextension_uuid(profile, extension_id, uuid=default_extension_uuid): profile.set_preference('extensions.webextensions.uuids', json.dumps({extension_id: uuid})) -def firefox_safe_mode(firefox_binary=default_firefox_binary, +def firefox_safe_mode(firefox_binary=conf_settings['BROWSER_BINARY'], proxy_host=default_proxy_host, proxy_port=default_proxy_port): """ @@ -97,8 +97,8 @@ def firefox_safe_mode(firefox_binary=default_firefox_binary, return HaketiloFirefox(options=options, firefox_profile=profile, firefox_binary=firefox_binary) -def firefox_with_profile(firefox_binary=default_firefox_binary, - profile_dir=default_clean_profile_dir, +def firefox_with_profile(firefox_binary=conf_settings['BROWSER_BINARY'], + profile_dir=conf_settings['CLEAN_PROFILE'], proxy_host=default_proxy_host, proxy_port=default_proxy_port): """ diff --git a/test/unit/test_indexeddb.py b/test/unit/test_indexeddb.py index 550b923..7ce4781 100644 --- a/test/unit/test_indexeddb.py +++ b/test/unit/test_indexeddb.py @@ -323,17 +323,18 @@ def test_haketilodb_track(driver, execute_in_page, wait_elem_text): # Create elements that will have tracked data inserted under them. driver.switch_to.window(windows[0]) - execute_in_page(''' - for (const store_name of trackable) { - const h2 = document.createElement("h2"); - h2.innerText = store_name; - document.body.append(h2); - - const ul = document.createElement("ul"); - ul.id = store_name; - document.body.append(ul); - } - ''') + execute_in_page( + ''' + for (const store_name of trackable) { + const h2 = document.createElement("h2"); + h2.innerText = store_name; + document.body.append(h2); + + const ul = document.createElement("ul"); + ul.id = store_name; + document.body.append(ul); + } + ''') # Mock initial_data. sample_resource = make_sample_resource() diff --git a/test/unit/test_item_list.py b/test/unit/test_item_list.py index ff532f8..0702129 100644 --- a/test/unit/test_item_list.py +++ b/test/unit/test_item_list.py @@ -217,17 +217,6 @@ def test_item_list_displaying(driver, execute_in_page, item_type): assert f'item{i}' in text assert f'Item {i}' in text - # Check that file preview link works. - window0 = driver.window_handles[0] - driver.find_element_by_link_text('report.spdx').click() - WebDriverWait(driver, 10).until(lambda _: len(driver.window_handles) == 2) - window1 = next(filter(lambda w: w != window0, driver.window_handles)) - driver.switch_to.window(window1) - assert 'dummy report' in driver.page_source - - driver.close() - driver.switch_to.window(window0) - # Check that item removal confirmation dialog is displayed correctly. execute_in_page('list_ctx.remove_but.click();') WebDriverWait(driver, 10).until(lambda _: dialog_container.is_displayed()) @@ -271,29 +260,6 @@ def test_item_list_displaying(driver, execute_in_page, item_type): execute_in_page('list_ctx.ul.children[1].click();') - # Check that missing file causes the right error dialog to appear. - execute_in_page( - '''{ - async function steal_file(hash_key) - { - const db = await haketilodb.get(); - const transaction = db.transaction("files", "readwrite"); - transaction.objectStore("files").delete(hash_key); - } - returnval(steal_file(arguments[0])); - }''', - sample_files['LICENSES/CC0-1.0.txt']['hash_key']) - driver.find_element_by_link_text('LICENSES/CC0-1.0.txt').click() - WebDriverWait(driver, 10).until(lambda _: dialog_container.is_displayed()) - assert 'list_disabled' in ul.get_attribute('class') - assert not preview_container.is_displayed() - - msg = execute_in_page('returnval(list_ctx.dialog_ctx.msg.textContent);') - assert msg == "File missing from Haketilo's internal database :(" - - execute_in_page('returnval(list_ctx.dialog_ctx.ok_but.click());') - WebDriverWait(driver, 10).until(lambda _: preview_container.is_displayed()) - # Check that item removal failure causes the right error dialog to appear. execute_in_page('haketilodb.finalize_transaction = () => {throw "sth";};') remove_current_item() diff --git a/test/unit/test_item_preview.py b/test/unit/test_item_preview.py index 6148bc2..8b2b161 100644 --- a/test/unit/test_item_preview.py +++ b/test/unit/test_item_preview.py @@ -19,6 +19,7 @@ Haketilo unit tests - displaying resources and mappings details import pytest from selenium.webdriver.support.ui import WebDriverWait +from selenium.common.exceptions import NoSuchWindowException from ..extension_crafting import ExtraHTML from ..script_loader import load_script @@ -138,7 +139,10 @@ def test_mapping_preview(driver, execute_in_page): @pytest.mark.ext_data({ 'background_script': broker_js, - 'extra_html': ExtraHTML('html/item_preview.html', {}), + 'extra_html': [ + ExtraHTML('html/item_preview.html', {}), + ExtraHTML('html/file_preview.html', {}, wrap_into_htmldoc=False) + ], 'navigate_to': 'html/item_preview.html' }) @pytest.mark.usefixtures('webextension') @@ -148,8 +152,6 @@ def test_file_preview_link(driver, execute_in_page): referenced file to be previewed. """ execute_in_page(load_script('html/item_preview.js')) - # Mock dialog - execute_in_page('dialog.error = (...args) => window.error_args = args;') sample_data = make_complete_sample_data() sample_data['mappings'] = {} @@ -162,22 +164,45 @@ def test_file_preview_link(driver, execute_in_page): execute_in_page( ''' - let resource_preview_object = - resource_preview(arguments[0], undefined, "dummy dialog ctx"); + let resource_preview_object = resource_preview(arguments[0], undefined); document.body.append(resource_preview_object.main_div); ''', sample_resource) window0 = driver.window_handles[0] driver.find_element_by_link_text('hello.js').click() - WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > 1) - window1 = [wh for wh in driver.window_handles if wh != window0][0] - driver.switch_to.window(window1) - assert sample_files['hello.js']['contents'] in driver.page_source + def blob_url_navigated(driver): + if len(driver.window_handles) < 2: + return + window1 = [wh for wh in driver.window_handles if wh != window0][0] + driver.switch_to.window(window1) + try: + return driver.current_url.startswith('blob') + except NoSuchWindowException: + pass + + WebDriverWait(driver, 10).until(blob_url_navigated) + + assert sample_files['hello.js']['contents'].strip() \ + in driver.find_element_by_tag_name("pre").text + + driver.close() driver.switch_to.window(window0) + driver.find_element_by_link_text('bye.js').click() - assert driver.execute_script('return window.error_args;') == [ - 'dummy dialog ctx', - "File missing from Haketilo's internal database :(" - ] + + def get_error_span(driver): + if len(driver.window_handles) < 2: + return + window1 = [wh for wh in driver.window_handles if wh != window0][0] + driver.switch_to.window(window1) + try: + return driver.find_element_by_id('error_msg') + except NoSuchWindowException: + pass + + error_span = WebDriverWait(driver, 10).until(get_error_span) + assert error_span.is_displayed() + assert "Couldn't find file in Haketilo's internal database :(" \ + in error_span.text diff --git a/test/unit/test_patterns_query_manager.py b/test/unit/test_patterns_query_manager.py index 5daf3a0..4662e8a 100644 --- a/test/unit/test_patterns_query_manager.py +++ b/test/unit/test_patterns_query_manager.py @@ -20,6 +20,7 @@ Haketilo unit tests - building pattern tree and putting it in a content script import pytest import json from selenium.webdriver.support.ui import WebDriverWait +from selenium.common.exceptions import TimeoutException from ..script_loader import load_script @@ -240,25 +241,31 @@ def background_js(): @pytest.mark.usefixtures('webextension') def test_pqm_script_injection(driver, execute_in_page): # Let's open a normal page in a second window. Window 0 will be used to make - # changed to IndexedDB and window 1 to test the working of content scripts. + # changes to IndexedDB and window 1 to test the working of content scripts. driver.execute_script('window.open("about:blank", "_blank");') WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2) windows = [*driver.window_handles] - def run_content_script(): - driver.switch_to.window(windows[1]) - driver.get('https://gotmyowndoma.in/index.html') - windows[1] = driver.window_handles[1] + def get_tree_json(driver): return driver.execute_script( ''' return (document.getElementById("tree-json") || {}).innerText; ''') - for attempt in range(10): + def run_content_script(): + driver.switch_to.window(windows[1]) + driver.get('https://gotmyowndoma.in/index.html') + windows[1] = driver.current_window_handle + try: + return WebDriverWait(driver, 10).until(get_tree_json) + except TimeoutException: + pass + + for attempt in range(2): json_txt = run_content_script() - if json.loads(json_txt) == {}: + if json_txt and json.loads(json_txt) == {}: break; - assert attempt != 9 + assert attempt != 2 driver.switch_to.window(windows[0]) execute_in_page(load_script('common/indexeddb.js')) @@ -271,12 +278,12 @@ def test_pqm_script_injection(driver, execute_in_page): } execute_in_page('returnval(save_items(arguments[0]));', sample_data) - for attempt in range(10): - tree_json = run_content_script() + for attempt in range(2): + tree_json = run_content_script() or '{}' json.loads(tree_json) if all([m['identifier'] in tree_json for m in sample_mappings]): break - assert attempt != 9 + assert attempt != 2 driver.switch_to.window(windows[0]) execute_in_page( diff --git a/test/unit/test_popup.py b/test/unit/test_popup.py index da1812d..da125ec 100644 --- a/test/unit/test_popup.py +++ b/test/unit/test_popup.py @@ -20,6 +20,7 @@ Haketilo unit tests - repository querying import pytest import json from selenium.webdriver.support.ui import WebDriverWait +from selenium.common.exceptions import ElementNotInteractableException from ..extension_crafting import ExtraHTML from ..script_loader import load_script @@ -146,10 +147,16 @@ def test_popup_display(driver, execute_in_page, page_info_key): """ reload_with_target(driver, f'mock_page_info-{page_info_key}') - by_id = driver.execute_script(''' - const nodes = [...document.querySelectorAll("[id]")]; - return nodes.reduce((ob, node) => Object.assign(ob, {[node.id]: node}), {}); - '''); + def get_nodes_by_id(driver): + by_id = driver.execute_script( + ''' + const nodes = [...document.querySelectorAll("[id]")]; + const reductor = (ob, node) => Object.assign(ob, {[node.id]: node}); + return nodes.reduce(reductor, {}); + '''); + return by_id if by_id and 'repo_query_container' in by_id else None + + by_id = WebDriverWait(driver, 10).until(get_nodes_by_id) if page_info_key == '': error_msg = 'Page info not avaialable. Try reloading the page.' @@ -213,9 +220,22 @@ def test_popup_repo_query(driver, execute_in_page): """ reload_with_target(driver, f'mock_page_info-blocked_rule') + driver.implicitly_wait(10) search_but = driver.find_element_by_id("search_resources_but") - WebDriverWait(driver, 10).until(lambda d: search_but.is_displayed()) - search_but.click() + driver.implicitly_wait(0) + + # For unknown reasons waiting for search_but.is_displayed() to return True + # does not guarantee the button will be interactable afterwards under newer + # browsers. Hence, this workaround. + def click_search_but(driver): + try: + search_but.click() + return True + except ElementNotInteractableException: + pass + + WebDriverWait(driver, 10).until(click_search_but) + containers = dict([(name, driver.find_element_by_id(f'{name}_container')) for name in ('page_info', 'repo_query')]) assert not containers['page_info'].is_displayed() -- cgit v1.2.3