diff options
Diffstat (limited to 'test/unit/conftest.py')
-rw-r--r-- | test/unit/conftest.py | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/test/unit/conftest.py b/test/unit/conftest.py new file mode 100644 index 0000000..62cc1a0 --- /dev/null +++ b/test/unit/conftest.py @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +""" +Common fixtures for Haketilo unit tests +""" + +# This file is part of Haketilo. +# +# Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org> +# +# 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 +# license. Although I request that you do not make use this code in a +# proprietary program, I am not going to enforce this in court. + +import pytest + +from ..profiles import firefox_safe_mode +from ..server import do_an_internet +from ..script_loader import load_script + +@pytest.fixture(scope="package") +def proxy(): + httpd = do_an_internet() + yield httpd + httpd.shutdown() + +@pytest.fixture(scope="package") +def driver(proxy): + with firefox_safe_mode() as driver: + yield driver + driver.quit() + +script_injecting_script = '''\ +/* + * Selenium by default executes scripts in some weird one-time context. We want + * separately-loaded scripts to be able to access global variables defined + * before, including those declared with `const` or `let`. To achieve that, we + * run our scripts by injecting them into the page inside a <script> tag. We use + * custom properties of the `window` object to communicate with injected code. + */ + +const script_elem = document.createElement('script'); +script_elem.textContent = arguments[0]; + +delete window.haketilo_selenium_return_value; +delete window.haketilo_selenium_exception; +window.returnval = (val => window.haketilo_selenium_return_value = val); +window.arguments = arguments[1]; + +document.body.append(script_elem); + +/* + * To ease debugging, we want this script to forward signal all exceptions from + * the injectee. + */ +try { + if (window.haketilo_selenium_exception !== false) + throw 'Error in injected script! Check your geckodriver.log!'; +} finally { + script_elem.remove(); +} + +return window.haketilo_selenium_return_value; +''' + +def _execute_in_page_context(driver, script, args): + script = script + '\n;\nwindow.haketilo_selenium_exception = false;' + try: + return driver.execute_script(script_injecting_script, script, args) + except Exception as e: + import sys + lines = enumerate(script.split('\n'), 1) + for err_info in [('Failing script\n',), *lines]: + print(*err_info, file=sys.stderr) + + raise e from None + +@pytest.fixture(scope="package") +def execute_in_page(driver): + def do_execute(script, *args, **kwargs): + if 'page' in kwargs: + driver.get(kwargs['page']) + + return _execute_in_page_context(driver, script, args) + + yield do_execute + +@pytest.fixture(scope="package") +def load_into_page(driver): + def do_load(path, import_dirs, *args, **kwargs): + if 'page' in kwargs: + driver.get(kwargs['page']) + + _execute_in_page_context(driver, load_script(path, import_dirs), args) + + yield do_load |