aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-01-31 18:06:13 +0100
committerWojtek Kosior <koszko@koszko.org>2022-01-31 18:06:13 +0100
commitad69f9c86b950cc84ca103e65824b9c9129d3999 (patch)
treea4314c8a5031b9fb2a278021b2388b86190c2823
parent4c6a2323d90e9321ec2b78e226167b3013ea69ab (diff)
downloadbrowser-extension-ad69f9c86b950cc84ca103e65824b9c9129d3999.tar.gz
browser-extension-ad69f9c86b950cc84ca103e65824b9c9129d3999.zip
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.
-rw-r--r--Makefile.in3
-rw-r--r--common/broadcast.js4
-rw-r--r--common/entities.js4
-rw-r--r--common/indexeddb.js2
-rw-r--r--common/patterns_query_tree.js2
-rwxr-xr-xconfigure73
-rw-r--r--html/file_preview.html48
-rw-r--r--html/file_preview.js75
-rw-r--r--html/item_list.js7
-rw-r--r--html/item_preview.js46
-rw-r--r--manifest.json2
-rw-r--r--test/data/pages/scripts_to_block_1.html2
-rw-r--r--test/misc_constants.py12
-rwxr-xr-xtest/profiles.py6
-rw-r--r--test/unit/test_indexeddb.py23
-rw-r--r--test/unit/test_item_list.py34
-rw-r--r--test/unit/test_item_preview.py51
-rw-r--r--test/unit/test_patterns_query_manager.py29
-rw-r--r--test/unit/test_popup.py32
19 files changed, 315 insertions, 140 deletions
diff --git a/Makefile.in b/Makefile.in
index 570260b..76aaf8e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -16,6 +16,7 @@ SHELL = /bin/sh
VPATH = <<VPATH>>
version = <<VERSION>>
+PYTEST = <<PYTEST>>
extension_files = background/ common/ content/ html/ licenses/ \
copyright default_settings.json manifest.json
@@ -70,7 +71,7 @@ test/certs/rootCA.pem: test/certs/rootCA.key
-subj "/CN=Haketilo Test"
test: test/certs/rootCA.pem test/certs/site.key $(default_target)-build.zip
- MOZ_HEADLESS=whatever pytest
+ MOZ_HEADLESS=whatever $(PYTEST)
test-environment: test/certs/rootCA.pem test/certs/site.key
python3 -m test
diff --git a/common/broadcast.js b/common/broadcast.js
index 4dcac2b..4fc5237 100644
--- a/common/broadcast.js
+++ b/common/broadcast.js
@@ -46,6 +46,7 @@
function sender_connection()
{
return {
+ type: "sender",
port: connect_to_background("broadcast_send")
};
}
@@ -92,6 +93,7 @@ function flush(sender_conn)
function listener_connection(cb)
{
const conn = {
+ type: "listener",
port: connect_to_background("broadcast_listen")
};
@@ -115,6 +117,8 @@ function unsubscribe(listener_conn, channel_name)
function close(conn)
{
+ if (conn.type === "sender")
+ flush(conn);
conn.port.disconnect();
}
#EXPORT close
diff --git a/common/entities.js b/common/entities.js
index 3ccbf04..96de5cb 100644
--- a/common/entities.js
+++ b/common/entities.js
@@ -74,7 +74,7 @@ function item_id_string(...args) {
#EXPORT item_id_string
/* vers should be an array of comparable values. Return the greatest one. */
-const max = vals => Array.reduce(vals, (v1, v2) => v1 > v2 ? v1 : v2);
+const max = vals => vals.reduce((v1, v2) => v1 > v2 ? v1 : v2);
/*
* versioned_item should be a dict with keys being version strings and values
@@ -167,6 +167,6 @@ const version_reductor = (acc, n) => [...(n || acc.length ? [n] : []), ...acc];
*
* Returns a *new* array. Doesn't modify its argument.
*/
-const normalize_version = ver => Array.reduceRight(ver, version_reductor, []);
+const normalize_version = ver => ver.reduceRight(version_reductor, []);
#ENDIF
diff --git a/common/indexeddb.js b/common/indexeddb.js
index 271dfce..f916162 100644
--- a/common/indexeddb.js
+++ b/common/indexeddb.js
@@ -56,7 +56,7 @@ let initial_data = (
const db_version = [1, 0, 0];
const nr_reductor = ([i, s], num) => [i - 1, s + num * 1024 ** i];
-const version_nr = ver => Array.reduce(ver.slice(0, 3), nr_reductor, [2, 0])[1];
+const version_nr = ver => ver.slice(0, 3).reduce(nr_reductor, [2, 0])[1];
const stores = [
["files", {keyPath: "hash_key"}],
diff --git a/common/patterns_query_tree.js b/common/patterns_query_tree.js
index ec1d989..ea3607e 100644
--- a/common/patterns_query_tree.js
+++ b/common/patterns_query_tree.js
@@ -68,7 +68,7 @@ function is_empty_node(tree_node) {
return false;
}
- if (Array.reduce(tree_node.wildcard_matches, (a, b) => b && a !== null, 1))
+ if (tree_node.wildcard_matches.reduce((a, b) => b && a !== null, 1))
return false;
return tree_node.literal_match === null;
diff --git a/configure b/configure
index 06a43eb..bd7800f 100755
--- a/configure
+++ b/configure
@@ -18,16 +18,29 @@ set -e
BROWSERPATH=''
SRCDIR=''
TARGET=''
+BROWSER_BINARY=''
+CLEAN_PROFILE=''
+DRIVER=''
+PYTEST=''
# Parse command line options
while [ "x$1" != x ]; do
case "$1" in
- --srcdir=*) SRCDIR="$(echo "$1" | cut -c 10-)";;
- --srcdir) SRCDIR="$2"; shift;;
- "DESTDIR"=*) DESTDIR="$(echo "$1" | cut -c 9-)";;
- "UPDATE_URL"=*) UPDATE_URL="$(echo "$1" | cut -c 12-)";;
- --host=*) TARGET="$(echo "$1" | cut -c 8-)";;
- --host) TARGET="$2"; shift;;
+ --srcdir=*) SRCDIR="$(printf %s "$1" | cut -c 10-)";;
+ --srcdir) SRCDIR="$2"; shift;;
+ --browser-binary=*) BROWSER_BINARY="$(printf %s "$1" | cut -c 18-)";;
+ --browser-binary) BROWSER_BINARY="$2"; shift;;
+ --clean-profile=*) CLEAN_PROFILE="$(printf %s "$1" | cut -c 17-)";;
+ --clean-profile) CLEAN_PROFILE="$2"; shift;;
+ --driver=*) DRIVER="$(printf %s "$1" | cut -c 10-)";;
+ --driver) DRIVER="$2"; shift;;
+ --pytest=*) PYTEST="$(printf %s "$1" | cut -c 10-)";;
+ --pytest) PYTEST="$2"; shift;;
+ --srcdir) SRCDIR="$2"; shift;;
+ "DESTDIR"=*) DESTDIR="$(printf %s "$1" | cut -c 9-)";;
+ "UPDATE_URL"=*) UPDATE_URL="$(printf %s "$1" | cut -c 12-)";;
+ --host=*) TARGET="$(printf %s "$1" | cut -c 8-)";;
+ --host) TARGET="$2"; shift;;
# browsers
chromium | chrome | google-chrome | mozilla |\
@@ -70,6 +83,20 @@ else
BROWSERPATH="$(realpath "$(which $TARGET)")"
fi
+# Autodetect browser binary (needed for Selenium)
+if [ "x$BROWSER_BINARY" = x ]; then
+ if [ "x$TARGET" = xabrowser ]; then
+ # Trisquel's path to Abrowser
+ BROWSER_BINARY=/usr/lib/abrowser/abrowser
+ if [ "x$TARGET" = xabrowser ]; then
+ # Debian's path to Librewolf
+ BROWSER_BINARY=/usr/share/librewolf/librewolf
+ elif [ "x$TARGET" = xicecat ]; then
+ # Parabola's path to IceCat
+ BROWSER_BINARY=/usr/lib/icecat/icecat
+ fi
+fi
+
# Check and standardize target
case "$TARGET" in
mozilla | firefox | abrowser | icecat | iceweasel-uxp |\
@@ -79,6 +106,27 @@ case "$TARGET" in
*) echo Invalid target "'$TARGET'" >&2; exit 2;;
esac
+# Autodetect Selenium driver
+if [ "x$DRIVER" = x ]; then
+ if [ "x$TARGET" = mozilla ]; then
+ DRIVER=geckodriver
+ fi
+fi
+
+# Autodetect clean profile directory for use in selenium tests
+if [ "x$CLEAN_PROFILE" = x ]; then
+ if [ "x$TARGET" = mozilla ]; then
+ CLEAN_PROFILE="$SRCDIR"/test/default_profile/icecat_empty
+ fi
+fi
+
+# Autodetect pytest
+for PYTEST_GUESS in pytest pytest-3 pytest3; do
+ if [ "x$PYTEST" = x ]; then
+ PYTEST="$(which $PYTEST_GUESS || true)"
+ fi
+done
+
# Autodetect DESTDIR (no check needed)
if [ "x$DESTDIR" = x ]; then
echo Guessing installation directory.
@@ -95,11 +143,14 @@ if [ "x$DESTDIR" = x ]; then
fi
# Write record.conf (LEAVE SRCDIR FIRST)
-echo srcdir = "$SRCDIR" > record.conf
-echo default_target = "$TARGET" >> record.conf
-echo DESTDIR = "$DESTDIR" >> record.conf
-echo UPDATE_URL = "$UPDATE_URL" >> record.conf
-
+printf '%s\n' "srcdir = $SRCDIR" > record.conf
+printf '%s\n' "default_target = $TARGET" >> record.conf
+printf '%s\n' "DESTDIR = $DESTDIR" >> record.conf
+printf '%s\n' "UPDATE_URL = $UPDATE_URL" >> record.conf
+printf '%s\n' "DRIVER = $DRIVER" >> record.conf
+printf '%s\n' "BROWSER_BINARY = $BROWSER_BINARY" >> record.conf
+printf '%s\n' "CLEAN_PROFILE = $CLEAN_PROFILE" >> record.conf
+printf '%s\n' "PYTEST = $PYTEST" >> record.conf
# Prepare and run write_makefile.sh (as config.status)
if [ ! -e config.status ]; then
diff --git a/html/file_preview.html b/html/file_preview.html
new file mode 100644
index 0000000..20e2392
--- /dev/null
+++ b/html/file_preview.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+ SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
+
+ Haketilo's preview of a file kept in IndexedDB
+
+ This file is part of Haketilo.
+
+ Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
+
+ File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+ I, Wojtek Kosior, thereby promise not to sue for violation of this file's
+ licenses. 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.
+ -->
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>File preview</title>
+#LOADCSS html/reset.css
+#LOADCSS html/base.css
+ <style>
+ .error_msg {
+ color: #a33;
+ /* also italics maybe?*/
+ }
+ </style>
+ </head>
+ <body>
+ <div id="info_msg">loading...</div>
+ <div id="error_msg" class="hide"></div>
+#LOADJS html/file_preview.js
+ </body>
+</html>
diff --git a/html/file_preview.js b/html/file_preview.js
new file mode 100644
index 0000000..3e22225
--- /dev/null
+++ b/html/file_preview.js
@@ -0,0 +1,75 @@
+/**
+ * This file is part of Haketilo.
+ *
+ * Function: Haketilo's preview of a file kept in IndexedDB.
+ *
+ * Copyright (C) 2022 Wojtek Kosior
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * I, Wojtek Kosior, thereby promise not to sue for violation of this 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 common/indexeddb.js AS haketilodb
+
+#FROM html/DOM_helpers.js IMPORT by_id
+
+const error_msg = by_id("error_msg"), info_msg = by_id("info_msg");
+
+function error(msg) {
+ info_msg.remove();
+ error_msg.classList.remove("hide");
+ error_msg.innerText = msg;
+}
+
+async function show_preview(hash_key) {
+ const db = await haketilodb.get();
+ const file = await haketilodb.idb_get(db.transaction("files"),
+ "files", hash_key);
+ if (file === undefined) {
+ error("Couldn't find file in Haketilo's internal database :(");
+ } else {
+ const blobby_opts = {type: "text/plain;charset=UTF-8"};
+ const blobby = new Blob([file.contents], blobby_opts);
+ location.replace(URL.createObjectURL(blobby));
+ }
+}
+
+const match = /^[^#]*#(.*)$/.exec(document.URL);
+if (!match) {
+ error("Bad URL :(");
+} else {
+ const hash_key = match[1];
+ show_preview(hash_key);
+}
diff --git a/html/item_list.js b/html/item_list.js
index a616713..bc1acb9 100644
--- a/html/item_list.js
+++ b/html/item_list.js
@@ -52,11 +52,8 @@ function preview_item(list_ctx, item, ignore_dialog=false)
if (list_ctx.dialog_ctx.shown && !ignore_dialog)
return;
- list_ctx.preview_ctx = list_ctx.preview_cb(
- item.definition,
- list_ctx.preview_ctx,
- list_ctx.dialog_ctx
- );
+ list_ctx.preview_ctx =
+ list_ctx.preview_cb(item.definition, list_ctx.preview_ctx);
list_ctx.preview_container.prepend(list_ctx.preview_ctx.main_div);
if (list_ctx.previewed_item !== null)
diff --git a/html/item_preview.js b/html/item_preview.js
index dccf2d4..c55183c 100644
--- a/html/item_preview.js
+++ b/html/item_preview.js
@@ -44,10 +44,10 @@
#IMPORT common/indexeddb.js AS haketilodb
#IMPORT html/dialog.js
+#FROM common/browser.js IMPORT browser
#FROM html/DOM_helpers.js IMPORT clone_template
-function populate_list(ul, items)
-{
+function populate_list(ul, items) {
for (const item of items) {
const li = document.createElement("li");
li.append(item);
@@ -55,41 +55,21 @@ function populate_list(ul, items)
}
}
-/* Link click handler used in make_file_link(). */
-async function file_link_clicked(preview_object, file_ref, event)
-{
- event.preventDefault();
-
- const db = await haketilodb.get();
- const file = await haketilodb.idb_get(db.transaction("files"),
- "files", file_ref.hash_key);
- if (file === undefined) {
- dialog.error(preview_object.dialog_context,
- "File missing from Haketilo's internal database :(");
- } else {
- const encoded_file = encodeURIComponent(file.contents);
- open(`data:text/plain;charset=utf8,${encoded_file}`, '_blank');
- }
-}
+const file_preview_link = browser.runtime.getURL("html/file_preview.html");
/*
* The default function to use to create file preview link. Links it creates can
* be used to view files from IndexedDB.
*/
-function make_file_link(preview_object, file_ref)
-{
+function make_file_link(preview_object, file_ref) {
const a = document.createElement("a");
- a.href = "javascript:void(0)";
+ a.href = `${file_preview_link}#${file_ref.hash_key}`;
a.innerText = file_ref.file;
- a.addEventListener("click",
- e => file_link_clicked(preview_object, file_ref, e));
-
+ a.target = "_blank";
return a;
}
-function resource_preview(resource, preview_object, dialog_context,
- make_link_cb=make_file_link)
-{
+function resource_preview(resource, preview_object, link_cb=make_file_link) {
if (preview_object === undefined)
preview_object = clone_template("resource_preview");
@@ -104,7 +84,7 @@ function resource_preview(resource, preview_object, dialog_context,
[...preview_object.dependencies.childNodes].forEach(n => n.remove());
populate_list(preview_object.dependencies, resource.dependencies);
- const link_maker = file_ref => make_link_cb(preview_object, file_ref);
+ const link_maker = file_ref => link_cb(preview_object, file_ref);
[...preview_object.scripts.childNodes].forEach(n => n.remove());
populate_list(preview_object.scripts, resource.scripts.map(link_maker));
@@ -113,15 +93,11 @@ function resource_preview(resource, preview_object, dialog_context,
populate_list(preview_object.copyright,
resource.source_copyright.map(link_maker));
- preview_object.dialog_context = dialog_context;
-
return preview_object;
}
#EXPORT resource_preview
-function mapping_preview(mapping, preview_object, dialog_context,
- make_link_cb=make_file_link)
-{
+function mapping_preview(mapping, preview_object, link_cb=make_file_link) {
if (preview_object === undefined)
preview_object = clone_template("mapping_preview");
@@ -145,14 +121,12 @@ function mapping_preview(mapping, preview_object, dialog_context,
}
}
- const link_maker = file_ref => make_link_cb(preview_object, file_ref);
+ const link_maker = file_ref => link_cb(preview_object, file_ref);
[...preview_object.copyright.childNodes].forEach(n => n.remove());
populate_list(preview_object.copyright,
mapping.source_copyright.map(link_maker));
- preview_object.dialog_context = dialog_context;
-
return preview_object;
}
#EXPORT mapping_preview
diff --git a/manifest.json b/manifest.json
index 25b5a1a..350c39a 100644
--- a/manifest.json
+++ b/manifest.json
@@ -68,6 +68,8 @@
"16": "icons/haketilo16.png"
},
"default_title": "Haketilo",
+ // Both popup.html and settings.html depend on file_preview.html.
+#LOADHTML html/file_preview.html
#LOADHTML html/popup.html
"default_popup": "html/popup.html"
},
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!
</a>
- <iframe src="javascript:window.parent.__run = [...(window.parent.__run || []), 'src'];">
+ <iframe src="javascript:void(window.parent.__run = [...(window.parent.__run || []), 'src']);">
</iframe>
<object data="javascript:window.__run = [...(window.__run || []), 'data'];">
</object>
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()