diff --git a/tests/helpers/fixtures.py b/tests/helpers/fixtures.py index f8729d3f8..d1380a322 100644 --- a/tests/helpers/fixtures.py +++ b/tests/helpers/fixtures.py @@ -43,12 +43,24 @@ import helpers.stubs as stubsmod import helpers.utils from qutebrowser.config import (config, configdata, configtypes, configexc, configfiles) -from qutebrowser.utils import objreg, standarddir +from qutebrowser.utils import objreg, standarddir, utils +from qutebrowser.browser import greasemonkey from qutebrowser.browser.webkit import cookies from qutebrowser.misc import savemanager, sql from qutebrowser.keyinput import modeman +try: + from PyQt5.QtWebKitWidgets import QWebView +except ImportError: + QWebView = None + +try: + from PyQt5.QtWebEngineWidgets import QWebEngineView +except ImportError: + QWebEngineView = None + + class WinRegistryHelper: """Helper class for win_registry.""" @@ -143,6 +155,47 @@ def fake_web_tab(stubs, tab_registry, mode_manager, qapp): return stubs.FakeWebTab +@pytest.fixture +def greasemonkey_manager(data_tmpdir): + gm_manager = greasemonkey.GreasemonkeyManager() + objreg.register('greasemonkey', gm_manager) + yield + objreg.delete('greasemonkey') + + +@pytest.fixture +def webkit_tab(qtbot, tab_registry, cookiejar_and_cache, mode_manager, + session_manager_stub, greasemonkey_manager): + webkittab = pytest.importorskip('qutebrowser.browser.webkit.webkittab') + tab = webkittab.WebKitTab(win_id=0, mode_manager=mode_manager, + private=False) + qtbot.add_widget(tab) + return tab + + +@pytest.fixture +def webengine_tab(qtbot, tab_registry, fake_args, mode_manager, + session_manager_stub, greasemonkey_manager, + redirect_webengine_data): + webenginetab = pytest.importorskip( + 'qutebrowser.browser.webengine.webenginetab') + tab = webenginetab.WebEngineTab(win_id=0, mode_manager=mode_manager, + private=False) + qtbot.add_widget(tab) + return tab + + +@pytest.fixture(params=['webkit', 'webengine']) +def web_tab(request): + """A WebKitTab/WebEngineTab.""" + if request.param == 'webkit': + return request.getfixturevalue('webkit_tab') + elif request.param == 'webengine': + return request.getfixturevalue('webengine_tab') + else: + raise utils.Unreachable + + def _generate_cmdline_tests(): """Generate testcases for test_split_binding.""" @attr.s diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index b5e30bb0b..ea7cbf268 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -472,6 +472,9 @@ class SessionManagerStub: def list_sessions(self): return self.sessions + def save_autosave(self): + pass + class TabbedBrowserStub(QObject): diff --git a/tests/unit/browser/test_tab.py b/tests/unit/browser/test_tab.py deleted file mode 100644 index 05a178b81..000000000 --- a/tests/unit/browser/test_tab.py +++ /dev/null @@ -1,110 +0,0 @@ -# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: - -# Copyright 2016-2018 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 . - -import pytest - -from qutebrowser.browser import browsertab -from qutebrowser.utils import utils - -pytestmark = pytest.mark.usefixtures('redirect_webengine_data') - -try: - from PyQt5.QtWebKitWidgets import QWebView -except ImportError: - QWebView = None - -try: - from PyQt5.QtWebEngineWidgets import QWebEngineView -except ImportError: - QWebEngineView = None - - -@pytest.fixture(params=[QWebView, QWebEngineView]) -def view(qtbot, config_stub, request): - if request.param is None: - pytest.skip("View not available") - - v = request.param() - qtbot.add_widget(v) - return v - - -@pytest.fixture(params=['webkit', 'webengine']) -def tab(request, qtbot, tab_registry, cookiejar_and_cache, mode_manager): - if request.param == 'webkit': - webkittab = pytest.importorskip('qutebrowser.browser.webkit.webkittab') - tab_class = webkittab.WebKitTab - elif request.param == 'webengine': - webenginetab = pytest.importorskip( - 'qutebrowser.browser.webengine.webenginetab') - tab_class = webenginetab.WebEngineTab - else: - raise utils.Unreachable - - t = tab_class(win_id=0, mode_manager=mode_manager) - qtbot.add_widget(t) - yield t - - -class Zoom(browsertab.AbstractZoom): - - def _set_factor_internal(self, _factor): - pass - - def factor(self): - raise utils.Unreachable - - -class Tab(browsertab.AbstractTab): - - # pylint: disable=abstract-method - - def __init__(self, win_id, mode_manager, parent=None): - super().__init__(win_id=win_id, mode_manager=mode_manager, - parent=parent) - self.history = browsertab.AbstractHistory(self) - self.scroller = browsertab.AbstractScroller(self, parent=self) - self.caret = browsertab.AbstractCaret(mode_manager=mode_manager, - tab=self, parent=self) - self.zoom = Zoom(tab=self) - self.search = browsertab.AbstractSearch(parent=self) - self.printing = browsertab.AbstractPrinting() - self.elements = browsertab.AbstractElements(tab=self) - self.action = browsertab.AbstractAction(tab=self) - - def _install_event_filter(self): - pass - - -@pytest.mark.xfail(run=False, reason='Causes segfaults, see #1638') -def test_tab(qtbot, view, config_stub, tab_registry, mode_manager): - tab_w = Tab(win_id=0, mode_manager=mode_manager) - qtbot.add_widget(tab_w) - - assert tab_w.win_id == 0 - assert tab_w._widget is None - - tab_w._set_widget(view) - assert tab_w._widget is view - assert tab_w.history._tab is tab_w - assert tab_w.history._history is view.history() - assert view.parent() is tab_w - - with qtbot.waitExposed(tab_w): - tab_w.show() diff --git a/tests/unit/javascript/conftest.py b/tests/unit/javascript/conftest.py index 254ead335..f555d9530 100644 --- a/tests/unit/javascript/conftest.py +++ b/tests/unit/javascript/conftest.py @@ -27,91 +27,9 @@ import pytest import jinja2 from PyQt5.QtCore import QUrl -try: - from PyQt5.QtWebKit import QWebSettings - from PyQt5.QtWebKitWidgets import QWebPage -except ImportError: - # FIXME:qtwebengine Make these tests use the tab API - QWebSettings = None - QWebPage = None - -try: - from PyQt5.QtWebEngineWidgets import (QWebEnginePage, - QWebEngineSettings, - QWebEngineScript) -except ImportError: - QWebEnginePage = None - QWebEngineSettings = None - QWebEngineScript = None import helpers.utils -import qutebrowser.utils.debug -from qutebrowser.utils import utils - - -if QWebPage is None: - TestWebPage = None -else: - class TestWebPage(QWebPage): - - """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, msg, line, source): - """Fail tests on js console messages as they're used for errors.""" - pytest.fail("js console ({}:{}): {}".format(source, line, msg)) - -if QWebEnginePage is None: - TestWebEnginePage = None -else: - class TestWebEnginePage(QWebEnginePage): - - """QWebEnginePage which overrides javascript logging 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( - qutebrowser.utils.debug.qenum_key( - QWebEnginePage, level), source, line, msg)) +from qutebrowser.utils import utils, usertypes class JSTester: @@ -119,14 +37,14 @@ class JSTester: """Common subclass providing basic functionality for all JS testers. Attributes: - webview: The webview which is used. - _qtbot: The QtBot fixture from pytest-qt. + tab: The tab object which is used. + qtbot: The QtBot fixture from pytest-qt. _jinja_env: The jinja2 environment used to get templates. """ - def __init__(self, webview, qtbot): - self.webview = webview - self._qtbot = qtbot + def __init__(self, tab, qtbot): + self.tab = tab + self.qtbot = qtbot loader = jinja2.FileSystemLoader(os.path.dirname(__file__)) self._jinja_env = jinja2.Environment(loader=loader, autoescape=True) @@ -139,9 +57,9 @@ class JSTester: **kwargs: Passed to jinja's template.render(). """ template = self._jinja_env.get_template(path) - with self._qtbot.waitSignal(self.webview.loadFinished, - timeout=2000) as blocker: - self.webview.setHtml(template.render(**kwargs)) + with self.qtbot.waitSignal(self.tab.load_finished, + timeout=2000) as blocker: + self.tab.set_html(template.render(**kwargs)) assert blocker.args == [True] def load_file(self, path: str, force: bool = False): @@ -161,77 +79,13 @@ class JSTester: url: The QUrl to load. force: Whether to force loading even if the file is invalid. """ - with self._qtbot.waitSignal(self.webview.loadFinished, - timeout=2000) as blocker: - self.webview.load(url) + with self.qtbot.waitSignal(self.tab.load_finished, + timeout=2000) as blocker: + self.tab.openurl(url) if not force: assert blocker.args == [True] - -class JSWebKitTester(JSTester): - - """Object returned by js_tester 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, qtbot): - super().__init__(webview, qtbot) - self.webview.setPage(TestWebPage(self.webview)) - - def scroll_anchor(self, name): - """Scroll the main frame to the given anchor.""" - page = self.webview.page() - old_pos = page.mainFrame().scrollPosition() - page.mainFrame().scrollToAnchor(name) - new_pos = page.mainFrame().scrollPosition() - assert old_pos != new_pos - - def run_file(self, filename): - """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)) - return self.run(source) - - def run(self, source): - """Run the given javascript source. - - Args: - source: The source to run as a string. - - Return: - The javascript return value. - """ - assert self.webview.settings().testAttribute( - QWebSettings.JavascriptEnabled) - return self.webview.page().mainFrame().evaluateJavaScript(source) - - -class JSWebEngineTester(JSTester): - - """Object returned by js_tester_webengine which provides 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, qtbot): - super().__init__(webview, qtbot) - self.webview.setPage(TestWebEnginePage(self.webview)) - - def run_file(self, filename: str, expected) -> None: + def run_file(self, filename: str, expected=None) -> None: """Run a javascript file. Args: @@ -250,24 +104,34 @@ class JSWebEngineTester(JSTester): expected: The value expected return from the javascript execution world: The scope the javascript will run in """ - if world is None: - world = QWebEngineScript.ApplicationWorld - - callback_checker = helpers.utils.CallbackChecker(self._qtbot) - assert self.webview.settings().testAttribute( - QWebEngineSettings.JavascriptEnabled) - self.webview.page().runJavaScript(source, world, - callback_checker.callback) + callback_checker = helpers.utils.CallbackChecker(self.qtbot) + self.tab.run_js_async(source, callback_checker.callback, world=world) callback_checker.check(expected) + def scroll_anchor(self, name): + """Scroll the main frame to the given anchor.""" + # FIXME This might be useful in the tab API? + assert self.tab.backend == usertypes.Backend.QtWebKit + page = self.tab._widget.page() + old_pos = page.mainFrame().scrollPosition() + page.mainFrame().scrollToAnchor(name) + new_pos = page.mainFrame().scrollPosition() + assert old_pos != new_pos + @pytest.fixture -def js_tester_webkit(webview, qtbot): +def js_tester_webkit(webkit_tab, qtbot): """Fixture to test javascript snippets in webkit.""" - return JSWebKitTester(webview, qtbot) + return JSTester(webkit_tab, qtbot) @pytest.fixture -def js_tester_webengine(callback_checker, webengineview, qtbot): +def js_tester_webengine(webengine_tab, qtbot): """Fixture to test javascript snippets in webengine.""" - return JSWebEngineTester(webengineview, qtbot) + return JSTester(webengine_tab, qtbot) + + +@pytest.fixture +def js_tester(web_tab, qtbot): + """Fixture to test javascript snippets with both backends.""" + return JSTester(web_tab, qtbot) diff --git a/tests/unit/javascript/position_caret/test_position_caret.py b/tests/unit/javascript/position_caret/test_position_caret.py index c47f94e30..edfe502c8 100644 --- a/tests/unit/javascript/position_caret/test_position_caret.py +++ b/tests/unit/javascript/position_caret/test_position_caret.py @@ -21,8 +21,7 @@ import pytest -# FIXME:qtwebengine Make these tests use the tab API -pytest.importorskip('PyQt5.QtWebKit') +import helpers.utils from PyQt5.QtCore import Qt from PyQt5.QtWebKit import QWebSettings @@ -53,24 +52,26 @@ class CaretTester: def check(self): """Check whether the caret is before the MARKER text.""" self.js.run_file('position_caret.js') - self.js.webview.triggerPageAction(QWebPage.SelectNextWord) - assert self.js.webview.selectedText().rstrip() == "MARKER" + self.js.tab.caret.toggle_selection() + self.js.tab.caret.move_to_next_word() + + callback_checker = helpers.utils.CallbackChecker(self.js.qtbot) + self.js.tab.caret.selection(lambda text: + callback_checker.callback(text.rstrip())) + callback_checker.check('MARKER') def check_scrolled(self): """Check if the page is scrolled down.""" - frame = self.js.webview.page().mainFrame() - minimum = frame.scrollBarMinimum(Qt.Vertical) - value = frame.scrollBarValue(Qt.Vertical) - assert value > minimum + assert not self.js.tab.scroller.at_top() @pytest.fixture -def caret_tester(js_tester_webkit): +def caret_tester(js_tester): """Helper fixture to test caret browsing positions.""" - caret_tester = CaretTester(js_tester_webkit) + caret_tester = CaretTester(js_tester) # Showing webview here is necessary for test_scrolled_down_img to # succeed in some cases, see #1988 - caret_tester.js.webview.show() + caret_tester.js.tab.show() return caret_tester diff --git a/tests/unit/javascript/stylesheet/test_stylesheet.py b/tests/unit/javascript/stylesheet/test_stylesheet.py index df11d22a3..8a7b91ac6 100644 --- a/tests/unit/javascript/stylesheet/test_stylesheet.py +++ b/tests/unit/javascript/stylesheet/test_stylesheet.py @@ -56,9 +56,7 @@ class StylesheetTester: """Initialize the stylesheet with a provided css file.""" css_path = os.path.join(os.path.dirname(__file__), css_file) self.config_stub.val.content.user_stylesheets = css_path - profile = QWebEngineProfile.defaultProfile() - setter = webenginesettings.ProfileSetter(profile) - setter.init_stylesheet() + self.js.tab._init_stylesheet() def set_css(self, css): """Set document style to `css` via stylesheet.js.""" @@ -82,7 +80,7 @@ class StylesheetTester: def stylesheet_tester(js_tester_webengine, config_stub): """Helper fixture to test stylesheets.""" ss_tester = StylesheetTester(js_tester_webengine, config_stub) - ss_tester.js.webview.show() + ss_tester.js.tab.show() return ss_tester