summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/script_loader.py55
-rw-r--r--test/unit/conftest.py8
-rw-r--r--test/unit/test_basic.py6
-rw-r--r--test/unit/test_broadcast.py54
-rw-r--r--test/unit/test_indexeddb.py32
-rw-r--r--test/unit/test_patterns.py12
-rw-r--r--test/unit/test_patterns_query_tree.py52
7 files changed, 85 insertions, 134 deletions
diff --git a/test/script_loader.py b/test/script_loader.py
index 8f30944..edf8143 100644
--- a/test/script_loader.py
+++ b/test/script_loader.py
@@ -41,54 +41,29 @@ def make_relative_path(path):
return path
-"""Used to ignore hidden files and emacs auto-save files."""
-script_name_regex = re.compile(r'^[^.#].*\.js$')
+script_cache = {}
-def available_scripts(directory):
- for script in directory.rglob('*.js'):
- if script_name_regex.match(script.name):
- yield script
-
-def wrapped_script(script_path, wrap_partially=True):
- if script_path == 'exports_init.js':
- if not (script_root / 'exports_init.js').exists():
- subprocess.run([str(script_root / 'write_exports_init.sh'),
- 'mozilla', '.', 'default_settings.json'],
- cwd=script_root, check=True)
-
- with open(script_root / 'exports_init.js') as script:
- return script.read()
-
- command = 'partially_wrapped_code' if wrap_partially else 'wrapped_code'
- awk_command = ['awk', '-f', str(awk_script), command, str(script_path)]
- awk = subprocess.run(awk_command, stdout=subprocess.PIPE, cwd=script_root,
- check=True)
-
- return awk.stdout.decode()
-
-def load_script(path, import_dirs):
+def load_script(path):
"""
- `path` and `import_dirs` are .js file path and a list of directory paths,
- respectively. They may be absolute or specified relative to Haketilo's
- project directory.
+ `path` is a .js file path in Haketilo sources. It may be absolute or
+ specified relative to Haketilo's project directory.
Return a string containing script from `path` together with all other
- scripts it depends. Dependencies are wrapped in the same way Haketilo's
+ scripts it depends on. Dependencies are wrapped in the same way Haketilo's
build system wraps them, with imports properly satisfied. The main script
being loaded is wrapped partially - it also has its imports satisfied, but
- its code is not placed inside an anonymous function, so the
+ its code is executed in global scope instead of within an anonymous function
+ and imported variables are defined with `let` instead of `const` to allow
+ a dependency to be substituted by a mocked value.
"""
path = make_relative_path(path)
+ if str(path) in script_cache:
+ return script_cache[str(path)]
- import_dirs = [make_relative_path(dir) for dir in import_dirs]
- available = [s for dir in import_dirs for s in available_scripts(dir)]
-
- awk = subprocess.run(['awk', '-f', str(awk_script), 'script_dependencies',
- str(path), *[str(s) for s in available]],
+ awk = subprocess.run(['awk', '-f', str(awk_script), '--', '-D', 'MOZILLA',
+ '-D', 'MV2', '--output=amalgamate-js:' + str(path)],
stdout=subprocess.PIPE, cwd=script_root, check=True)
+ script = awk.stdout.decode()
+ script_cache[str(path)] = script
- to_load = awk.stdout.decode().split()
- texts = [wrapped_script(path, wrap_partially=(i == len(to_load) - 1))
- for i, path in enumerate(to_load)]
-
- return '\n'.join(texts)
+ return script
diff --git a/test/unit/conftest.py b/test/unit/conftest.py
index eec311c..f9a17f8 100644
--- a/test/unit/conftest.py
+++ b/test/unit/conftest.py
@@ -33,7 +33,6 @@ from selenium.webdriver.support import expected_conditions as EC
from ..profiles import firefox_safe_mode
from ..server import do_an_internet
-from ..script_loader import load_script
from ..extension_crafting import make_extension
@pytest.fixture(scope="package")
@@ -140,13 +139,6 @@ def execute_in_page(driver):
yield do_execute
@pytest.fixture()
-def load_into_page(driver):
- def do_load(path, import_dirs, *args):
- _execute_in_page_context(driver, load_script(path, import_dirs), args)
-
- yield do_load
-
-@pytest.fixture()
def wait_elem_text(driver):
def do_wait(id, text):
WebDriverWait(driver, 10).until(
diff --git a/test/unit/test_basic.py b/test/unit/test_basic.py
index ca956e7..2564e9d 100644
--- a/test/unit/test_basic.py
+++ b/test/unit/test_basic.py
@@ -19,6 +19,8 @@ Haketilo unit tests - base
import pytest
+from ..script_loader import load_script
+
def test_driver(driver):
"""
A trivial test case that verifies mocked web pages served by proxy can be
@@ -32,12 +34,12 @@ def test_driver(driver):
assert "Schrodinger's Document" in title
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_script_loader(execute_in_page, load_into_page):
+def test_script_loader(execute_in_page):
"""
A trivial test case that verifies Haketilo's .js files can be properly
loaded into a test page together with their dependencies.
"""
- load_into_page('common/stored_types.js', ['common'])
+ execute_in_page(load_script('common/stored_types.js'))
assert execute_in_page('returnval(TYPE_PREFIX.VAR);') == '_'
diff --git a/test/unit/test_broadcast.py b/test/unit/test_broadcast.py
index 11a61b0..1213b17 100644
--- a/test/unit/test_broadcast.py
+++ b/test/unit/test_broadcast.py
@@ -21,12 +21,9 @@ import pytest
from ..script_loader import load_script
-def broker_js():
- js = load_script('background/broadcast_broker.js', ['common', 'background'])
- return js + ';start_broadcast_broker();'
+broker_js = lambda: load_script('background/broadcast_broker.js') + ';start();'
-def broadcast_js():
- return load_script('common/broadcast.js', ['common'])
+broadcast_js = lambda: load_script('common/broadcast.js')
test_page_html = '''
<!DOCTYPE html>
@@ -53,7 +50,6 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
API and implemented in `background/broadcast_broker.js` and
`common/broadcast.js` works correctly.
"""
-
# The broadcast facility is meant to enable message distribution between
# multiple contexts (e.g. different tabs/windows). Let's open the same
# extension's test page in a second window.
@@ -71,15 +67,15 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
'''
const divs = [0, 1, 2].map(n => document.getElementById("d" + n));
let appender = n => (t => divs[n].append("\\n" + `[${t[0]}, ${t[1]}]`));
- let listener0 = broadcast.listener_connection(appender(0));
- broadcast.subscribe(listener0, "somebodyoncetoldme");
+ let listener0 = listener_connection(appender(0));
+ subscribe(listener0, "somebodyoncetoldme");
''')
driver.switch_to.window(windows[1])
execute_in_page(
'''
- let sender0 = broadcast.sender_connection();
- broadcast.out(sender0, "somebodyoncetoldme", "iaintthesharpesttool");
+ let sender0 = sender_connection();
+ out(sender0, "somebodyoncetoldme", "iaintthesharpesttool");
''')
driver.switch_to.window(windows[0])
@@ -89,11 +85,11 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(windows[0])
execute_in_page(
'''
- let listener1 = broadcast.listener_connection(appender(1));
- broadcast.subscribe(listener1, "worldisgonnarollme");
- let listener2 = broadcast.listener_connection(appender(2));
- broadcast.subscribe(listener2, "worldisgonnarollme");
- broadcast.subscribe(listener2, "somebodyoncetoldme");
+ let listener1 = listener_connection(appender(1));
+ subscribe(listener1, "worldisgonnarollme");
+ let listener2 = listener_connection(appender(2));
+ subscribe(listener2, "worldisgonnarollme");
+ subscribe(listener2, "somebodyoncetoldme");
''')
# Let's send one message to one channel and one to the other. Verify they
@@ -101,8 +97,8 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(windows[1])
execute_in_page(
'''
- broadcast.out(sender0, "somebodyoncetoldme", "intheshed");
- broadcast.out(sender0, "worldisgonnarollme", "shewaslooking");
+ out(sender0, "somebodyoncetoldme", "intheshed");
+ out(sender0, "worldisgonnarollme", "shewaslooking");
''')
driver.switch_to.window(windows[0])
@@ -121,9 +117,9 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(windows[2])
execute_in_page(
'''
- let sender1 = broadcast.sender_connection();
- broadcast.prepare(sender1, "somebodyoncetoldme", "kindadumb");
- broadcast.out(sender1, "worldisgonnarollme", "withherfinger");
+ let sender1 = sender_connection();
+ prepare(sender1, "somebodyoncetoldme", "kindadumb");
+ out(sender1, "worldisgonnarollme", "withherfinger");
''')
driver.switch_to.window(windows[0])
@@ -132,7 +128,7 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
assert 'kindadumb' not in text
driver.switch_to.window(windows[2])
- execute_in_page('broadcast.flush(sender1);')
+ execute_in_page('flush(sender1);')
driver.switch_to.window(windows[0])
wait_elem_text('d0', 'kindadumb')
@@ -142,10 +138,10 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(windows[2])
execute_in_page(
'''
- broadcast.prepare(sender1, "somebodyoncetoldme", "andherthumb");
- broadcast.discard(sender1);
- broadcast.prepare(sender1, "somebodyoncetoldme", "andhermiddlefinger");
- broadcast.flush(sender1);
+ prepare(sender1, "somebodyoncetoldme", "andherthumb");
+ discard(sender1);
+ prepare(sender1, "somebodyoncetoldme", "andhermiddlefinger");
+ flush(sender1);
''')
driver.switch_to.window(windows[0])
@@ -158,7 +154,7 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(windows[2])
execute_in_page(
'''
- broadcast.prepare(sender1, "worldisgonnarollme", "intheshape", 500);
+ prepare(sender1, "worldisgonnarollme", "intheshape", 500);
''')
driver.close()
@@ -166,11 +162,11 @@ def test_broadcast(driver, execute_in_page, wait_elem_text):
wait_elem_text('d2', 'intheshape')
# Verify listener's connection gets closed properly.
- execute_in_page('broadcast.close(listener0); broadcast.close(listener1);')
+ execute_in_page('close(listener0); close(listener1);')
driver.switch_to.window(windows[1])
- execute_in_page('broadcast.out(sender0, "worldisgonnarollme", "ofanL");')
- execute_in_page('broadcast.out(sender0, "somebodyoncetoldme", "forehead");')
+ execute_in_page('out(sender0, "worldisgonnarollme", "ofanL");')
+ execute_in_page('out(sender0, "somebodyoncetoldme", "forehead");')
driver.switch_to.window(windows[0])
wait_elem_text('d2', 'ofanL')
diff --git a/test/unit/test_indexeddb.py b/test/unit/test_indexeddb.py
index 3604ee9..af60e1c 100644
--- a/test/unit/test_indexeddb.py
+++ b/test/unit/test_indexeddb.py
@@ -27,8 +27,8 @@ from selenium.common.exceptions import WebDriverException
from ..script_loader import load_script
-def indexeddb_js():
- return load_script('common/indexeddb.js', ['common'])
+indexeddb_js = lambda: load_script('common/indexeddb.js')
+broker_js = lambda: load_script('background/broadcast_broker.js') + ';start();'
def sample_file(contents):
return {
@@ -118,7 +118,7 @@ def test_haketilodb_save_remove(execute_in_page):
'''
async function get_database_contents()
{
- const db = await haketilodb.get();
+ const db = await get_db();
const transaction = db.transaction(db.objectStoreNames);
const store_names_reqs = [...db.objectStoreNames]
@@ -226,7 +226,7 @@ def test_haketilodb_save_remove(execute_in_page):
for i, item_type in enumerate(['resource', 'mapping']):
results[i] = execute_in_page(
f'''{{
- const remover = haketilodb.remove_{item_type};
+ const remover = remove_{item_type};
const promise =
start_items_transaction(["{item_type}s"], {{}})
.then(ctx => remover('helloapple', ctx).then(() => ctx))
@@ -282,10 +282,6 @@ def test_haketilodb_save_remove(execute_in_page):
assert database_contents['resources'] == [sample_resource]
assert database_contents['mappings'] == [sample_mapping]
-def broker_js():
- js = load_script('background/broadcast_broker.js', ['common', 'background'])
- return js + ';start_broadcast_broker();'
-
test_page_html = '''
<!DOCTYPE html>
<script src="/testpage.js"></script>
@@ -336,8 +332,7 @@ def test_haketilodb_track(driver, execute_in_page, wait_elem_text):
driver.switch_to.window(window)
execute_in_page('initial_data = arguments[0];', initial_data)
- # See if haketilodb.track_*() functions properly return the already-existing
- # items.
+ # See if track_*() functions properly return the already-existing items.
execute_in_page(
'''
function update_item(store_name, change)
@@ -361,9 +356,9 @@ def test_haketilodb_track(driver, execute_in_page, wait_elem_text):
const update_mapping = change => update_item("mappings", change);
[resource_tracking, resource_items] =
- await haketilodb.track_resources(update_resource);
+ await track_resources(update_resource);
[mapping_tracking, mapping_items] =
- await haketilodb.track_mappings(update_mapping);
+ await track_mappings(update_mapping);
for (const item of resource_items)
update_resource({identifier: item.identifier, new_val: item});
@@ -404,8 +399,7 @@ def test_haketilodb_track(driver, execute_in_page, wait_elem_text):
},
'files': sample_files_by_hash
}
- execute_in_page('returnval(haketilodb.save_items(arguments[0]));',
- sample_data)
+ execute_in_page('returnval(save_items(arguments[0]));', sample_data)
driver.switch_to.window(windows[0])
driver.implicitly_wait(10)
@@ -421,11 +415,11 @@ def test_haketilodb_track(driver, execute_in_page, wait_elem_text):
'''{
async function remove_items()
{
- const store_names = ["resources", "mappings"];
- const ctx = await haketilodb.start_items_transaction(store_names, {});
- await haketilodb.remove_resource("helloapple", ctx);
- await haketilodb.remove_mapping("helloapple-copy", ctx);
- await haketilodb.finalize_items_transaction(ctx);
+ const store_names = ["resources", "mappings"];
+ const ctx = await start_items_transaction(store_names, {});
+ await remove_resource("helloapple", ctx);
+ await remove_mapping("helloapple-copy", ctx);
+ await finalize_items_transaction(ctx);
}
returnval(remove_items());
}''')
diff --git a/test/unit/test_patterns.py b/test/unit/test_patterns.py
index 99e1ed5..f2eeaf8 100644
--- a/test/unit/test_patterns.py
+++ b/test/unit/test_patterns.py
@@ -21,17 +21,13 @@ import pytest
from ..script_loader import load_script
-@pytest.fixture(scope="session")
-def patterns_code():
- yield load_script('common/patterns.js', ['common'])
-
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_regexes(execute_in_page, patterns_code):
+def test_regexes(execute_in_page):
"""
patterns.js contains regexes used for URL parsing.
Verify they work properly.
"""
- execute_in_page(patterns_code)
+ execute_in_page(load_script('common/patterns.js'))
valid_url = 'https://example.com/a/b?ver=1.2.3#heading2'
valid_url_rest = 'example.com/a/b?ver=1.2.3#heading2'
@@ -92,12 +88,12 @@ def test_regexes(execute_in_page, patterns_code):
assert match is None
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_deconstruct_url(execute_in_page, patterns_code):
+def test_deconstruct_url(execute_in_page):
"""
patterns.js contains deconstruct_url() function that handles URL parsing.
Verify it works properly.
"""
- execute_in_page(patterns_code)
+ execute_in_page(load_script('common/patterns.js'))
deco = execute_in_page('returnval(deconstruct_url(arguments[0]));',
'https://eXaMpLe.com/a/b?ver=1.2.3#heading2')
diff --git a/test/unit/test_patterns_query_tree.py b/test/unit/test_patterns_query_tree.py
index a67e22f..80bf554 100644
--- a/test/unit/test_patterns_query_tree.py
+++ b/test/unit/test_patterns_query_tree.py
@@ -21,18 +21,14 @@ import pytest
from ..script_loader import load_script
-@pytest.fixture(scope="session")
-def patterns_tree_code():
- yield load_script('common/patterns_query_tree.js', ['common'])
-
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_modify_branch(execute_in_page, patterns_tree_code):
+def test_modify_branch(execute_in_page):
"""
patterns_query_tree.js contains Pattern Tree data structure that allows
arrays of string labels to be mapped to items.
Verify operations modifying a single branch of such tree work properly.
"""
- execute_in_page(patterns_tree_code)
+ execute_in_page(load_script('common/patterns_query_tree.js'))
execute_in_page(
'''
let items_added;
@@ -197,13 +193,13 @@ def test_modify_branch(execute_in_page, patterns_tree_code):
}
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_search_branch(execute_in_page, patterns_tree_code):
+def test_search_branch(execute_in_page):
"""
patterns_query_tree.js contains Pattern Tree data structure that allows
arrays of string labels to be mapped to items.
Verify searching a single branch of such tree work properly.
"""
- execute_in_page(patterns_tree_code)
+ execute_in_page(load_script('common/patterns_query_tree.js'))
execute_in_page(
'''
const item_adder = item => (array => [...(array || []), item]);
@@ -285,13 +281,13 @@ def test_search_branch(execute_in_page, patterns_tree_code):
raise e from None
@pytest.mark.get_page('https://gotmyowndoma.in')
-def test_pattern_tree(execute_in_page, patterns_tree_code):
+def test_pattern_tree(execute_in_page):
"""
patterns_query_tree.js contains Pattern Tree data structure that allows
arrays of string labels to be mapped to items.
Verify operations on entire such tree work properly.
"""
- execute_in_page(patterns_tree_code)
+ execute_in_page(load_script('common/patterns_query_tree.js'))
# Perform tests with all possible patterns for a simple URL.
url = 'https://example.com'
@@ -315,12 +311,12 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
tree, result = execute_in_page(
'''{
- const tree = pattern_tree.make();
+ const tree = pattern_tree_make();
for (const pattern of arguments[0].concat(arguments[1])) {
- pattern_tree.register(tree, pattern, 'key', pattern);
- pattern_tree.register(tree, pattern + '/', 'key', pattern + '/');
+ pattern_tree_register(tree, pattern, 'key', pattern);
+ pattern_tree_register(tree, pattern + '/', 'key', pattern + '/');
}
- returnval([tree, [...pattern_tree.search(tree, arguments[2])]]);
+ returnval([tree, [...pattern_tree_search(tree, arguments[2])]]);
}''',
patterns, bad_patterns, url)
assert expected == result
@@ -333,10 +329,10 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
'''{
const tree = arguments[0];
for (const pattern of arguments[1]) {
- pattern_tree.deregister(tree, pattern, 'key');
- pattern_tree.deregister(tree, pattern + '/', 'key');
+ pattern_tree_deregister(tree, pattern, 'key');
+ pattern_tree_deregister(tree, pattern + '/', 'key');
}
- returnval([tree, [...pattern_tree.search(tree, arguments[2])]]);
+ returnval([tree, [...pattern_tree_search(tree, arguments[2])]]);
}''',
tree, patterns_removed, url)
assert expected == result
@@ -346,8 +342,8 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
'''{
const tree = arguments[0];
for (const pattern of arguments[1].concat(arguments[2])) {
- pattern_tree.deregister(tree, pattern, 'key');
- pattern_tree.deregister(tree, pattern + '/', 'key');
+ pattern_tree_deregister(tree, pattern, 'key');
+ pattern_tree_deregister(tree, pattern + '/', 'key');
}
returnval(tree);
}''',
@@ -439,12 +435,12 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
tree, result = execute_in_page(
'''{
- const tree = pattern_tree.make();
+ const tree = pattern_tree_make();
for (const pattern of arguments[0].concat(arguments[1])) {
- pattern_tree.register(tree, pattern, 'key', pattern);
- pattern_tree.register(tree, pattern + '/', 'key', pattern + '/');
+ pattern_tree_register(tree, pattern, 'key', pattern);
+ pattern_tree_register(tree, pattern + '/', 'key', pattern + '/');
}
- returnval([tree, [...pattern_tree.search(tree, arguments[2])]]);
+ returnval([tree, [...pattern_tree_search(tree, arguments[2])]]);
}''',
patterns, bad_patterns, url)
assert expected == result
@@ -456,8 +452,8 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
'''{
const tree = arguments[0];
for (const pattern of arguments[1])
- pattern_tree.deregister(tree, pattern + '/', 'key');
- returnval([tree, [...pattern_tree.search(tree, arguments[2])]]);
+ pattern_tree_deregister(tree, pattern + '/', 'key');
+ returnval([tree, [...pattern_tree_search(tree, arguments[2])]]);
}''',
tree, patterns, url)
assert expected == result
@@ -467,10 +463,10 @@ def test_pattern_tree(execute_in_page, patterns_tree_code):
'''{
const tree = arguments[0];
for (const pattern of arguments[1])
- pattern_tree.deregister(tree, pattern, 'key');
+ pattern_tree_deregister(tree, pattern, 'key');
for (const pattern of arguments[2]) {
- pattern_tree.deregister(tree, pattern, 'key');
- pattern_tree.deregister(tree, pattern + '/', 'key');
+ pattern_tree_deregister(tree, pattern, 'key');
+ pattern_tree_deregister(tree, pattern + '/', 'key');
}
returnval(tree);
}''',