diff --git a/tests/unit/javascript/conftest.py b/tests/unit/javascript/conftest.py index b9f013ecf..788daf568 100644 --- a/tests/unit/javascript/conftest.py +++ b/tests/unit/javascript/conftest.py @@ -25,10 +25,12 @@ import logging import pytest import jinja2 +from tests.helpers.fixtures import CallbackChecker try: from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKitWidgets import QWebPage + from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineSettings except ImportError: # FIXME:qtwebengine Make these tests use the tab API QWebSettings = None @@ -68,6 +70,34 @@ else: """Fail tests on js console messages as they're used for errors.""" pytest.fail("js console ({}:{}): {}".format(source, line, msg)) + class TestWebEnginePage(QWebEnginePage): + + """QWebPage subclass which overrides some test methods. + + Attributes: + _logger: The logger used for alerts. + """ + + def __init__(self, parent=None): + super().__init__(parent) + self._logger = logging.getLogger('js-tests') + + def javaScriptAlert(self, _frame, msg): + """Log javascript alerts.""" + self._logger.info("js alert: {}".format(msg)) + + def javaScriptConfirm(self, _frame, msg): + """Fail tests on js confirm() as that should never happen.""" + pytest.fail("js confirm: {}".format(msg)) + + def javaScriptPrompt(self, _frame, msg, _default): + """Fail tests on js prompt() as that should never happen.""" + pytest.fail("js prompt: {}".format(msg)) + + def javaScriptConsoleMessage(self, level, msg, line, source): + """Fail tests on js console messages as they're used for errors.""" + pytest.fail("[{}] js console ({}:{}): {}".format(level, source, line, msg)) + class JSTester: @@ -133,8 +163,75 @@ class JSTester: QWebSettings.JavascriptEnabled) return self.webview.page().mainFrame().evaluateJavaScript(source) +class JSWebEngineTester: + + """Object returned by js_tester_webengine which provides test data and a webview. + + Attributes: + webview: The webview which is used. + _qtbot: The QtBot fixture from pytest-qt. + _jinja_env: The jinja2 environment used to get templates. + """ + + def __init__(self, webview, callback_checker, qtbot): + self.webview = webview + self.webview.setPage(TestWebEnginePage(self.webview)) + self.callback_checker = callback_checker + self._qtbot = qtbot + loader = jinja2.FileSystemLoader(os.path.dirname(__file__)) + self._jinja_env = jinja2.Environment(loader=loader, autoescape=True) + + def load(self, path, **kwargs): + """Load and display the given test data. + + Args: + path: The path to the test file, relative to the javascript/ + folder. + **kwargs: Passed to jinja's template.render(). + """ + template = self._jinja_env.get_template(path) + with self._qtbot.waitSignal(self.webview.loadFinished) as blocker: + self.webview.setHtml(template.render(**kwargs)) + assert blocker.args == [True] + + def run_file(self, filename, expected): + """Run a javascript file. + + Args: + filename: The javascript filename, relative to + qutebrowser/javascript. + + Return: + The javascript return value. + """ + source = utils.read_file(os.path.join('javascript', filename)) + self.run(source, expected) + + def run(self, source, expected): + """Run the given javascript source. + + Args: + source: The source to run as a string. + + Return: + The javascript return value. + """ + # TODO how to do this properly + callback_checker = CallbackChecker(self._qtbot) + assert self.webview.settings().testAttribute(QWebEngineSettings.JavascriptEnabled) + self.webview.page().runJavaScript(source, callback_checker.callback) + callback_checker.check(expected) + @pytest.fixture def js_tester(webview, qtbot): """Fixture to test javascript snippets.""" return JSTester(webview, qtbot) + + +@pytest.fixture +def js_tester_webengine(callback_checker, webengineview, qtbot): + """Fixture to test javascript snippets.""" + webengineview.settings().setAttribute( + QWebEngineSettings.JavascriptEnabled, True) + return JSWebEngineTester(webengineview, callback_checker, qtbot) diff --git a/tests/unit/javascript/stylesheet/simple.html b/tests/unit/javascript/stylesheet/simple.html new file mode 100644 index 000000000..4073672a4 --- /dev/null +++ b/tests/unit/javascript/stylesheet/simple.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} +{% block content %} +

Hello World!

+{% endblock %} diff --git a/tests/unit/javascript/stylesheet/test_stylesheet.py b/tests/unit/javascript/stylesheet/test_stylesheet.py new file mode 100644 index 000000000..38c1fd116 --- /dev/null +++ b/tests/unit/javascript/stylesheet/test_stylesheet.py @@ -0,0 +1,65 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2015-2017 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser 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. +# +# qutebrowser 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 qutebrowser. If not, see . + +"""Tests for position_caret.js.""" + +import os +import pytest +from qutebrowser.utils import javascript +from qutebrowser.browser import shared +from qutebrowser.config import config +from PyQt5.QtWebEngineWidgets import QWebEngineSettings + +class StylesheetTester: + + """Helper class (for the caret_tester fixture) for asserts. + + Attributes: + js: The js_tester fixture. + """ + + def __init__(self, js_tester): + self.js = js_tester + + def check(self): + """Check whether the caret is before the MARKER text.""" + self.js.run('window._qutebrowser = window._qutebrowser || {};', {}) + self.js.run_file('stylesheet.js', {}) + code = javascript.assemble('stylesheet', 'set_css', + "body {background-color: lightblue;}") + self.js.run(code, None) + self.js.run("window.getComputedStyle(document.body, null).getPropertyValue('background-color')", "rgb(173, 216, 230)") + + +@pytest.fixture +@pytest.mark.usefixtures('redirect_webengine_data') +def stylesheet_tester(js_tester_webengine): + """Helper fixture to test caret browsing positions.""" + ss_tester = StylesheetTester(js_tester_webengine) + # Showing webview here is necessary for test_scrolled_down_img to + # succeed in some cases, see #1988 + ss_tester.js.webview.show() + return ss_tester + + +@pytest.mark.integration +def test_simple(stylesheet_tester): + """Test with a simple (one-line) HTML text.""" + stylesheet_tester.js.load('stylesheet/simple.html') + stylesheet_tester.check()