qutebrowser/tests/unit/javascript/conftest.py

271 lines
9.1 KiB
Python
Raw Normal View History

# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2017-05-09 21:37:03 +02:00
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# 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 <http://www.gnu.org/licenses/>.
"""pylint conftest file for javascript test."""
import os
import os.path
2015-05-12 17:44:06 +02:00
import logging
import pytest
import jinja2
from helpers.utils import CallbackChecker
2017-11-09 06:07:54 +01:00
from PyQt5.QtCore import QUrl
2016-09-05 18:45:50 +02:00
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
2017-11-09 06:07:54 +01:00
try:
from PyQt5.QtWebEngineWidgets import (QWebEnginePage,
QWebEngineSettings,
QWebEngineScript)
except ImportError:
QWebEnginePage = None
QWebEngineSettings = None
QWebEngineScript = None
from qutebrowser.utils import utils
2016-09-05 18:45:50 +02:00
if QWebPage is None:
TestWebPage = None
else:
class TestWebPage(QWebPage):
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
"""QWebPage subclass which overrides some test methods.
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
Attributes:
_logger: The logger used for alerts.
"""
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
def __init__(self, parent=None):
super().__init__(parent)
self._logger = logging.getLogger('js-tests')
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
def javaScriptAlert(self, _frame, msg):
"""Log javascript alerts."""
self._logger.info("js alert: {}".format(msg))
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
def javaScriptConfirm(self, _frame, msg):
"""Fail tests on js confirm() as that should never happen."""
pytest.fail("js confirm: {}".format(msg))
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
def javaScriptPrompt(self, _frame, msg, _default):
"""Fail tests on js prompt() as that should never happen."""
pytest.fail("js prompt: {}".format(msg))
2015-05-12 17:44:06 +02:00
2016-09-05 18:45:50 +02:00
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))
2015-05-12 17:44:06 +02:00
2017-11-09 06:07:54 +01:00
if QWebEnginePage is None:
TestWebEnginePage = None
else:
class TestWebEnginePage(QWebEnginePage):
2017-11-09 06:07:54 +01:00
"""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."""
2017-11-09 06:07:54 +01:00
pytest.fail("[{}] js console ({}:{}): {}".format(level, source,
line, msg))
2015-05-12 17:44:06 +02:00
class 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):
self.webview = webview
2015-05-12 17:44:06 +02:00
self.webview.setPage(TestWebPage(self.webview))
self._qtbot = qtbot
loader = jinja2.FileSystemLoader(os.path.dirname(__file__))
self._jinja_env = jinja2.Environment(loader=loader, autoescape=True)
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
2015-05-12 19:08:54 +02:00
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.
2015-05-12 19:08:54 +02:00
**kwargs: Passed to jinja's template.render().
"""
template = self._jinja_env.get_template(path)
with self._qtbot.waitSignal(self.webview.loadFinished) as blocker:
2015-05-12 19:08:54 +02:00
self.webview.setHtml(template.render(**kwargs))
assert blocker.args == [True]
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)
2017-11-09 06:07:54 +01:00
class JSWebEngineTester:
2017-11-09 06:07:54 +01:00
"""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, 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):
2017-11-09 06:07:54 +01:00
"""Load and display the given jinja 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]
2017-11-09 05:46:12 +01:00
def load_file(self, path: str, force=False):
2017-11-09 06:07:54 +01:00
"""Load a file from disk.
Args:
path: The string path from disk to load (relative to this file)
force: Whether to force loading even if the file is invalid.
"""
self.load_url(QUrl.fromLocalFile(
2017-11-09 05:46:12 +01:00
os.path.join(os.path.dirname(__file__), path)), force)
2017-11-09 06:07:54 +01:00
def load_url(self, url: QUrl, force: bool = False):
"""Load a given QUrl.
Args:
url: The QUrl to load.
force: Whether to force loading even if the file is invalid.
"""
with self._qtbot.waitSignal(self.webview.loadFinished) as blocker:
self.webview.load(url)
2017-11-09 05:46:12 +01:00
if not force:
assert blocker.args == [True]
2017-11-09 06:07:54 +01:00
def run_file(self, filename: str, expected) -> None:
"""Run a javascript file.
Args:
filename: The javascript filename, relative to
qutebrowser/javascript.
2017-11-09 06:07:54 +01:00
expected: The value expected return from the javascript execution
"""
source = utils.read_file(os.path.join('javascript', filename))
self.run(source, expected)
2017-11-09 06:07:54 +01:00
def run(self, source: str, expected,
world=QWebEngineScript.ApplicationWorld) -> None:
"""Run the given javascript source.
Args:
source: The source to run as a string.
2017-11-09 06:07:54 +01:00
expected: The value expected return from the javascript execution
world: The scope the javascript will run in
"""
callback_checker = CallbackChecker(self._qtbot)
assert self.webview.settings().testAttribute(
QWebEngineSettings.JavascriptEnabled)
self.webview.page().runJavaScript(source, world,
callback_checker.callback)
callback_checker.check(expected)
@pytest.fixture
2015-08-23 18:17:22 +02:00
def js_tester(webview, qtbot):
2017-11-09 06:07:54 +01:00
"""Fixture to test javascript snippets in webkit."""
return JSTester(webview, qtbot)
@pytest.fixture
def js_tester_webengine(callback_checker, webengineview, qtbot):
2017-11-09 06:07:54 +01:00
"""Fixture to test javascript snippets in webengine."""
return JSWebEngineTester(webengineview, callback_checker, qtbot)