aboutsummaryrefslogtreecommitdiff
path: root/test/haketilo_test/unit/test_payload_create.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/haketilo_test/unit/test_payload_create.py')
-rw-r--r--test/haketilo_test/unit/test_payload_create.py248
1 files changed, 248 insertions, 0 deletions
diff --git a/test/haketilo_test/unit/test_payload_create.py b/test/haketilo_test/unit/test_payload_create.py
new file mode 100644
index 0000000..9689c37
--- /dev/null
+++ b/test/haketilo_test/unit/test_payload_create.py
@@ -0,0 +1,248 @@
+# SPDX-License-Identifier: CC0-1.0
+
+"""
+Haketilo unit tests - using a form to create simple site payload
+"""
+
+# This file is part of Haketilo
+#
+# Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the CC0 1.0 Universal License as published by
+# the Creative Commons Corporation.
+#
+# 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
+# CC0 1.0 Universal License for more details.
+
+import pytest
+import re
+from hashlib import sha256
+
+from selenium.webdriver.support.ui import WebDriverWait
+
+from ..extension_crafting import ExtraHTML
+from ..script_loader import load_script
+from .utils import *
+
+uuidv4_re = re.compile(
+ r'^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$',
+ re.IGNORECASE
+)
+
+sample_patterns = '''
+http://example.com/***
+
+https://*.example.org/**'''
+
+sample_form_data = {
+ 'identifier': 'someid',
+ 'long_name': 'Some Name',
+ 'description': 'blah blah blah',
+ 'patterns': sample_patterns,
+ 'script': sample_files['hello.js']['contents']
+}
+
+def fill_form_with_sample_data(execute_in_page, sample_data_override={},
+ form_ctx='form_ctx'):
+ form_data = sample_form_data.copy()
+ form_data.update(sample_data_override)
+ execute_in_page(
+ f'''
+ for (const [key, value] of Object.entries(arguments[0]))
+ {form_ctx}[key].value = value;
+ ''',
+ form_data)
+ return form_data
+
+cleared_form_inputs = {
+ 'identifier': '',
+ 'long_name': '',
+ 'description': '',
+ 'patterns': 'https://example.com/***',
+ 'script': 'console.log("Hello, World!");'
+}
+def assert_form_contents(execute_in_page, inputs=cleared_form_inputs):
+ inputs_keys = [*inputs.keys()]
+ values = execute_in_page(
+ 'returnval(arguments[0].map(i => form_ctx[i].value));',
+ inputs_keys
+ )
+ for key, value in zip(inputs_keys, values):
+ assert inputs[key] == value
+
+@pytest.mark.ext_data({
+ 'background_script': broker_js,
+ 'extra_html': ExtraHTML('html/payload_create.html', {}),
+ 'navigate_to': 'html/payload_create.html'
+})
+@pytest.mark.usefixtures('webextension')
+def test_payload_create_normal_usage(driver, execute_in_page):
+ """
+ A test case of normal usage of simple payload creation form.
+ """
+ execute_in_page(load_script('html/payload_create.js'))
+
+ create_but, form_container, dialog_container = execute_in_page(
+ '''
+ const form_ctx = payload_create_form();
+ document.body.append(form_ctx.main_div);
+ returnval([form_ctx.create_but, form_ctx.form_container,
+ form_ctx.dialog_container]);
+ ''')
+
+ assert patterns_doc_url == \
+ driver.find_element_by_link_text('URL patterns').get_attribute('href')
+
+ assert form_container.is_displayed()
+ assert not dialog_container.is_displayed()
+
+ assert_form_contents(execute_in_page)
+
+ form_data = fill_form_with_sample_data(execute_in_page)
+
+ create_but.click()
+
+ assert not form_container.is_displayed()
+ assert dialog_container.is_displayed()
+
+ def success_reported(driver):
+ return 'Successfully saved payload' in dialog_container.text
+
+ WebDriverWait(driver, 10).until(success_reported)
+ execute_in_page('form_ctx.dialog_ctx.ok_but.click();')
+
+ assert form_container.is_displayed()
+ assert not dialog_container.is_displayed()
+
+ def assert_db_contents():
+ db_contents = get_db_contents(execute_in_page)
+
+ assert uuidv4_re.match(db_contents['resource'][0]['uuid'])
+
+ localid = f'local-{form_data["identifier"]}'
+ long_name = form_data['long_name'] or form_data['identifier']
+ payloads = dict([(pat, {'identifier': localid})
+ for pat in form_data['patterns'].split('\n') if pat])
+
+ assert db_contents['resource'] == [{
+ 'source_name': localid,
+ 'source_copyright': [],
+ 'type': 'resource',
+ 'identifier': localid,
+ 'uuid': db_contents['resource'][0]['uuid'],
+ 'version': [1],
+ 'description': form_data['description'],
+ 'dependencies': [],
+ 'long_name': long_name,
+ 'scripts': [{
+ 'file': 'payload.js',
+ 'sha256': sha256(form_data['script'].encode()).digest().hex()
+ }]
+ }]
+
+ assert uuidv4_re.match(db_contents['mapping'][0]['uuid'])
+ assert db_contents['mapping'] == [{
+ 'source_name': localid,
+ 'source_copyright': [],
+ 'type': 'mapping',
+ 'identifier': localid,
+ 'uuid': db_contents['mapping'][0]['uuid'],
+ 'version': [1],
+ 'description': form_data['description'],
+ 'long_name': long_name,
+ 'payloads': payloads
+ }]
+
+ assert_db_contents()
+
+ form_data = fill_form_with_sample_data(execute_in_page, {
+ 'long_name': '',
+ 'description': 'bam bam bam',
+ 'patterns': 'https://new.example.com/***',
+ 'script': sample_files['bye.js']['contents']
+ })
+
+ create_but.click()
+
+ for type in ('Resource', 'Mapping'):
+ def override_asked(driver):
+ return f"{type} 'local-someid' already exists. Override?" \
+ in dialog_container.text
+ WebDriverWait(driver, 10).until(override_asked)
+ execute_in_page('form_ctx.dialog_ctx.yes_but.click();')
+
+ assert_db_contents()
+
+@pytest.mark.ext_data({
+ 'background_script': broker_js,
+ 'extra_html': ExtraHTML('html/payload_create.html', {}),
+ 'navigate_to': 'html/payload_create.html'
+})
+@pytest.mark.usefixtures('webextension')
+def test_payload_create_errors(driver, execute_in_page):
+ """
+ A test case of various error the simple payload form might show.
+ """
+ execute_in_page(load_script('html/payload_create.js'))
+
+ create_but, dialog_container = execute_in_page(
+ '''
+ const form_ctx = payload_create_form();
+ document.body.append(form_ctx.main_div);
+ returnval([form_ctx.create_but, form_ctx.dialog_container]);
+ ''')
+
+ for data_override, expected_msg in [
+ ({'identifier': ''}, "The 'identifier' field is required!"),
+ ({'identifier': ':('}, 'Identifier may only contain '),
+ ({'script': ''}, "The 'script' field is required!"),
+ ({'patterns': ''}, "The 'URL patterns' field is required!"),
+ ({'patterns': ':d'}, "':d' is not a valid URL pattern. See here for more details."),
+ ({'patterns': '\n'.join(['http://example.com'] * 2)},
+ "Pattern 'http://example.com' specified multiple times!")
+ ]:
+ # Attempt creating the payload
+ form_data = fill_form_with_sample_data(execute_in_page, data_override)
+ create_but.click()
+ # Verify the error message
+ assert expected_msg in dialog_container.text
+
+ # Verify patterns documentation <a> link.
+ if expected_msg == {'patterns': ':d'}:
+ doc_link_elem = driver.find_element_by_link_text('here')
+ assert doc_link.get_attribute('href') == patterns_doc_url
+
+ # Verify the form was NOT cleared upon failed saving.
+ execute_in_page('form_ctx.dialog_ctx.ok_but.click();')
+ assert_form_contents(execute_in_page, form_data)
+
+ # Add a sample item and attempt overriding it.
+ fill_form_with_sample_data(execute_in_page)
+ create_but.click()
+ WebDriverWait(driver, 10).until(lambda _: 'Succes' in dialog_container.text)
+ execute_in_page('form_ctx.dialog_ctx.ok_but.click();')
+
+ # Verify that denying override leads to saving failure.
+ form_data = fill_form_with_sample_data(execute_in_page)
+ create_but.click()
+ WebDriverWait(driver, 10).until(lambda _: 'Overri' in dialog_container.text)
+ execute_in_page('form_ctx.dialog_ctx.no_but.click();')
+ assert 'Failed to save payload :(' in dialog_container.text
+ execute_in_page('form_ctx.dialog_ctx.ok_but.click();')
+ assert_form_contents(execute_in_page, form_data)
+
+ # Verify that IndexedDB errors get caught and reported as saving failures.
+ execute_in_page('haketilodb.get = async () => {throw "someerror";}')
+ form_data = fill_form_with_sample_data(execute_in_page, {'identifier': 'o'})
+ create_but.click()
+ WebDriverWait(driver, 10).until(lambda _: 'Failed' in dialog_container.text)
+ execute_in_page('form_ctx.dialog_ctx.ok_but.click();')
+ assert_form_contents(execute_in_page, form_data)
+
+ # Verify that the loading message gets shown during IndexedDB operations.
+ execute_in_page('haketilodb.get = () => new Promise(cb => null);')
+ create_but.click()
+ assert 'Saving payload...' in dialog_container.text