Merge branch 'webengine-createwindow'
This commit is contained in:
commit
050507c0a6
@ -12,6 +12,9 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
env: DOCKER=archlinux
|
env: DOCKER=archlinux
|
||||||
services: docker
|
services: docker
|
||||||
|
- os: linux
|
||||||
|
env: DOCKER=archlinux QUTE_BDD_WEBENGINE=true
|
||||||
|
services: docker
|
||||||
- os: linux
|
- os: linux
|
||||||
env: DOCKER=ubuntu-xenial
|
env: DOCKER=ubuntu-xenial
|
||||||
services: docker
|
services: docker
|
||||||
|
@ -107,6 +107,8 @@ Changed
|
|||||||
- Lots of improvements to and bugfixes for the QtWebEngine backend, such as
|
- Lots of improvements to and bugfixes for the QtWebEngine backend, such as
|
||||||
working hints. However, using qutebrowser directly from git is still advised
|
working hints. However, using qutebrowser directly from git is still advised
|
||||||
when using `--backend webengine`.
|
when using `--backend webengine`.
|
||||||
|
- `content -> javascript-can-open-windows` got renamed to
|
||||||
|
`javascript-can-open-windows-automatically`.
|
||||||
|
|
||||||
Deprecated
|
Deprecated
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
@ -157,7 +157,7 @@
|
|||||||
|<<content-hyperlink-auditing,hyperlink-auditing>>|Enable or disable hyperlink auditing (<a ping>).
|
|<<content-hyperlink-auditing,hyperlink-auditing>>|Enable or disable hyperlink auditing (<a ping>).
|
||||||
|<<content-geolocation,geolocation>>|Allow websites to request geolocations.
|
|<<content-geolocation,geolocation>>|Allow websites to request geolocations.
|
||||||
|<<content-notifications,notifications>>|Allow websites to show notifications.
|
|<<content-notifications,notifications>>|Allow websites to show notifications.
|
||||||
|<<content-javascript-can-open-windows,javascript-can-open-windows>>|Whether JavaScript programs can open new windows.
|
|<<content-javascript-can-open-windows-automatically,javascript-can-open-windows-automatically>>|Whether JavaScript programs can open new windows without user interaction.
|
||||||
|<<content-javascript-can-close-windows,javascript-can-close-windows>>|Whether JavaScript programs can close windows.
|
|<<content-javascript-can-close-windows,javascript-can-close-windows>>|Whether JavaScript programs can close windows.
|
||||||
|<<content-javascript-can-access-clipboard,javascript-can-access-clipboard>>|Whether JavaScript programs can read or write to the clipboard.
|
|<<content-javascript-can-access-clipboard,javascript-can-access-clipboard>>|Whether JavaScript programs can read or write to the clipboard.
|
||||||
|<<content-ignore-javascript-prompt,ignore-javascript-prompt>>|Whether all javascript prompts should be ignored.
|
|<<content-ignore-javascript-prompt,ignore-javascript-prompt>>|Whether all javascript prompts should be ignored.
|
||||||
@ -1427,9 +1427,9 @@ Valid values:
|
|||||||
|
|
||||||
Default: +pass:[ask]+
|
Default: +pass:[ask]+
|
||||||
|
|
||||||
[[content-javascript-can-open-windows]]
|
[[content-javascript-can-open-windows-automatically]]
|
||||||
=== javascript-can-open-windows
|
=== javascript-can-open-windows-automatically
|
||||||
Whether JavaScript programs can open new windows.
|
Whether JavaScript programs can open new windows without user interaction.
|
||||||
|
|
||||||
Valid values:
|
Valid values:
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ markers =
|
|||||||
flaky_once: Try to rerun this test once if it fails
|
flaky_once: Try to rerun this test once if it fails
|
||||||
qtwebengine_todo: Features still missing with QtWebEngine
|
qtwebengine_todo: Features still missing with QtWebEngine
|
||||||
qtwebengine_skip: Tests not applicable with QtWebEngine
|
qtwebengine_skip: Tests not applicable with QtWebEngine
|
||||||
|
qtwebkit_skip: Tests not applicable with QtWebKit
|
||||||
|
qtwebengine_createWindow: Tests using createWindow with QtWebEngine (QTBUG-54419)
|
||||||
qt_log_level_fail = WARNING
|
qt_log_level_fail = WARNING
|
||||||
qt_log_ignore =
|
qt_log_ignore =
|
||||||
^SpellCheck: .*
|
^SpellCheck: .*
|
||||||
|
@ -112,7 +112,7 @@ MAPPINGS = {
|
|||||||
Attribute(QWebEngineSettings.AutoLoadImages),
|
Attribute(QWebEngineSettings.AutoLoadImages),
|
||||||
'allow-javascript':
|
'allow-javascript':
|
||||||
Attribute(QWebEngineSettings.JavascriptEnabled),
|
Attribute(QWebEngineSettings.JavascriptEnabled),
|
||||||
'javascript-can-open-windows':
|
'javascript-can-open-windows-automatically':
|
||||||
Attribute(QWebEngineSettings.JavascriptCanOpenWindows),
|
Attribute(QWebEngineSettings.JavascriptCanOpenWindows),
|
||||||
'javascript-can-access-clipboard':
|
'javascript-can-access-clipboard':
|
||||||
Attribute(QWebEngineSettings.JavascriptCanAccessClipboard),
|
Attribute(QWebEngineSettings.JavascriptCanAccessClipboard),
|
||||||
|
@ -381,7 +381,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
|
|
||||||
def __init__(self, win_id, mode_manager, parent=None):
|
def __init__(self, win_id, mode_manager, parent=None):
|
||||||
super().__init__(win_id)
|
super().__init__(win_id)
|
||||||
widget = webview.WebEngineView(tabdata=self.data)
|
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id)
|
||||||
self.history = WebEngineHistory(self)
|
self.history = WebEngineHistory(self)
|
||||||
self.scroller = WebEngineScroller(self, parent=self)
|
self.scroller = WebEngineScroller(self, parent=self)
|
||||||
self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager,
|
self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager,
|
||||||
@ -406,9 +406,9 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
])
|
])
|
||||||
script = QWebEngineScript()
|
script = QWebEngineScript()
|
||||||
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
||||||
page = self._widget.page()
|
|
||||||
script.setSourceCode(js_code)
|
script.setSourceCode(js_code)
|
||||||
|
|
||||||
|
page = self._widget.page()
|
||||||
try:
|
try:
|
||||||
page.runJavaScript("", QWebEngineScript.ApplicationWorld)
|
page.runJavaScript("", QWebEngineScript.ApplicationWorld)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@ -504,6 +504,11 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
if title == title_url.toDisplayString(QUrl.RemoveScheme).strip('/'):
|
if title == title_url.toDisplayString(QUrl.RemoveScheme).strip('/'):
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
|
# Don't add history entry if the URL is invalid anyways
|
||||||
|
if not url.isValid():
|
||||||
|
log.misc.debug("Ignoring invalid URL being added to history")
|
||||||
|
return
|
||||||
|
|
||||||
self.add_history_item.emit(url, requested_url, title)
|
self.add_history_item.emit(url, requested_url, title)
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
"""The main browser widget for QtWebEngine."""
|
"""The main browser widget for QtWebEngine."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QUrl
|
from PyQt5.QtCore import pyqtSignal, QUrl
|
||||||
# pylint: disable=no-name-in-module,import-error,useless-suppression
|
# pylint: disable=no-name-in-module,import-error,useless-suppression
|
||||||
@ -26,17 +27,73 @@ from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
|
|||||||
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import log, debug, usertypes
|
from qutebrowser.utils import log, debug, usertypes, objreg, qtutils, message
|
||||||
|
|
||||||
|
|
||||||
class WebEngineView(QWebEngineView):
|
class WebEngineView(QWebEngineView):
|
||||||
|
|
||||||
"""Custom QWebEngineView subclass with qutebrowser-specific features."""
|
"""Custom QWebEngineView subclass with qutebrowser-specific features."""
|
||||||
|
|
||||||
def __init__(self, tabdata, parent=None):
|
def __init__(self, tabdata, win_id, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self._win_id = win_id
|
||||||
self.setPage(WebEnginePage(tabdata, parent=self))
|
self.setPage(WebEnginePage(tabdata, parent=self))
|
||||||
|
|
||||||
|
def createWindow(self, wintype):
|
||||||
|
"""Called by Qt when a page wants to create a new window.
|
||||||
|
|
||||||
|
This function is called from the createWindow() method of the
|
||||||
|
associated QWebEnginePage, each time the page wants to create a new
|
||||||
|
window of the given type. This might be the result, for example, of a
|
||||||
|
JavaScript request to open a document in a new window.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
wintype: This enum describes the types of window that can be
|
||||||
|
created by the createWindow() function.
|
||||||
|
|
||||||
|
QWebEnginePage::WebBrowserWindow:
|
||||||
|
A complete web browser window.
|
||||||
|
QWebEnginePage::WebBrowserTab:
|
||||||
|
A web browser tab.
|
||||||
|
QWebEnginePage::WebDialog:
|
||||||
|
A window without decoration.
|
||||||
|
QWebEnginePage::WebBrowserBackgroundTab:
|
||||||
|
A web browser tab without hiding the current visible
|
||||||
|
WebEngineView. (Added in Qt 5.7)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
The new QWebEngineView object.
|
||||||
|
"""
|
||||||
|
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-54419
|
||||||
|
vercheck = qtutils.version_check
|
||||||
|
qtbug_54419_fixed = ((vercheck('5.6.2') and not vercheck('5.7.0')) or
|
||||||
|
qtutils.version_check('5.7.1') or
|
||||||
|
os.environ.get('QUTE_QTBUG54419_PATCHED', ''))
|
||||||
|
if not qtbug_54419_fixed:
|
||||||
|
message.error(self._win_id, "Qt 5.6.2/5.7.1 or newer is required "
|
||||||
|
"to open new tabs via JS!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
debug_type = debug.qenum_key(QWebEnginePage, wintype)
|
||||||
|
log.webview.debug("createWindow with type {}".format(debug_type))
|
||||||
|
background = False
|
||||||
|
if wintype in [QWebEnginePage.WebBrowserWindow,
|
||||||
|
QWebEnginePage.WebDialog]:
|
||||||
|
log.webview.warning("{} requested, but we don't support "
|
||||||
|
"that!".format(debug_type))
|
||||||
|
elif wintype == QWebEnginePage.WebBrowserTab:
|
||||||
|
pass
|
||||||
|
elif (hasattr(QWebEnginePage, 'WebBrowserBackgroundTab') and
|
||||||
|
wintype == QWebEnginePage.WebBrowserBackgroundTab):
|
||||||
|
background = True
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid wintype {}".format(debug_type))
|
||||||
|
|
||||||
|
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||||
|
window=self._win_id)
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
return tabbed_browser.tabopen(background=background)._widget
|
||||||
|
|
||||||
|
|
||||||
class WebEnginePage(QWebEnginePage):
|
class WebEnginePage(QWebEnginePage):
|
||||||
|
|
||||||
@ -74,11 +131,6 @@ class WebEnginePage(QWebEnginePage):
|
|||||||
logger = level_to_logger[level]
|
logger = level_to_logger[level]
|
||||||
logger(logstring)
|
logger(logstring)
|
||||||
|
|
||||||
def createWindow(self, _typ):
|
|
||||||
"""Handle new windows via JS."""
|
|
||||||
log.stub()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def acceptNavigationRequest(self,
|
def acceptNavigationRequest(self,
|
||||||
url: QUrl,
|
url: QUrl,
|
||||||
typ: QWebEnginePage.NavigationType,
|
typ: QWebEnginePage.NavigationType,
|
||||||
|
@ -118,7 +118,7 @@ MAPPINGS = {
|
|||||||
Attribute(QWebSettings.AutoLoadImages),
|
Attribute(QWebSettings.AutoLoadImages),
|
||||||
'allow-javascript':
|
'allow-javascript':
|
||||||
Attribute(QWebSettings.JavascriptEnabled),
|
Attribute(QWebSettings.JavascriptEnabled),
|
||||||
'javascript-can-open-windows':
|
'javascript-can-open-windows-automatically':
|
||||||
Attribute(QWebSettings.JavascriptCanOpenWindows),
|
Attribute(QWebSettings.JavascriptCanOpenWindows),
|
||||||
'javascript-can-close-windows':
|
'javascript-can-close-windows':
|
||||||
Attribute(QWebSettings.JavascriptCanCloseWindows),
|
Attribute(QWebSettings.JavascriptCanCloseWindows),
|
||||||
|
@ -29,7 +29,7 @@ from PyQt5.QtWebKitWidgets import QWebView, QWebPage, QWebFrame
|
|||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.keyinput import modeman
|
from qutebrowser.keyinput import modeman
|
||||||
from qutebrowser.utils import log, usertypes, utils, qtutils, objreg
|
from qutebrowser.utils import log, usertypes, utils, qtutils, objreg, debug
|
||||||
from qutebrowser.browser.webkit import webpage, webkitelem
|
from qutebrowser.browser.webkit import webpage, webkitelem
|
||||||
|
|
||||||
|
|
||||||
@ -218,6 +218,8 @@ class WebView(QWebView):
|
|||||||
Return:
|
Return:
|
||||||
The new QWebView object.
|
The new QWebView object.
|
||||||
"""
|
"""
|
||||||
|
debug_type = debug.qenum_key(QWebPage, wintype)
|
||||||
|
log.webview.debug("createWindow with type {}".format(debug_type))
|
||||||
if wintype == QWebPage.WebModalDialog:
|
if wintype == QWebPage.WebModalDialog:
|
||||||
log.webview.warning("WebModalDialog requested, but we don't "
|
log.webview.warning("WebModalDialog requested, but we don't "
|
||||||
"support that!")
|
"support that!")
|
||||||
|
@ -385,6 +385,8 @@ class ConfigManager(QObject):
|
|||||||
('completion', 'history-length'): 'cmd-history-max-items',
|
('completion', 'history-length'): 'cmd-history-max-items',
|
||||||
('colors', 'downloads.fg'): 'downloads.fg.start',
|
('colors', 'downloads.fg'): 'downloads.fg.start',
|
||||||
('ui', 'show-keyhints'): 'keyhint-blacklist',
|
('ui', 'show-keyhints'): 'keyhint-blacklist',
|
||||||
|
('content', 'javascript-can-open-windows'):
|
||||||
|
'javascript-can-open-windows-automatically',
|
||||||
}
|
}
|
||||||
DELETED_OPTIONS = [
|
DELETED_OPTIONS = [
|
||||||
('colors', 'tab.separator'),
|
('colors', 'tab.separator'),
|
||||||
|
@ -808,9 +808,10 @@ def data(readonly=False):
|
|||||||
SettingValue(typ.BoolAsk(), 'ask'),
|
SettingValue(typ.BoolAsk(), 'ask'),
|
||||||
"Allow websites to show notifications."),
|
"Allow websites to show notifications."),
|
||||||
|
|
||||||
('javascript-can-open-windows',
|
('javascript-can-open-windows-automatically',
|
||||||
SettingValue(typ.Bool(), 'false'),
|
SettingValue(typ.Bool(), 'false'),
|
||||||
"Whether JavaScript programs can open new windows."),
|
"Whether JavaScript programs can open new windows without user "
|
||||||
|
"interaction."),
|
||||||
|
|
||||||
('javascript-can-close-windows',
|
('javascript-can-close-windows',
|
||||||
SettingValue(typ.Bool(), 'false',
|
SettingValue(typ.Bool(), 'false',
|
||||||
|
@ -99,7 +99,7 @@ def get_fatal_crash_dialog(debug, data):
|
|||||||
def _get_environment_vars():
|
def _get_environment_vars():
|
||||||
"""Gather environment variables for the crash info."""
|
"""Gather environment variables for the crash info."""
|
||||||
masks = ('DESKTOP_SESSION', 'DE', 'QT_*', 'PYTHON*', 'LC_*', 'LANG',
|
masks = ('DESKTOP_SESSION', 'DE', 'QT_*', 'PYTHON*', 'LC_*', 'LANG',
|
||||||
'XDG_*')
|
'XDG_*', 'QUTE_*')
|
||||||
info = []
|
info = []
|
||||||
for key, value in os.environ.items():
|
for key, value in os.environ.items():
|
||||||
for m in masks:
|
for m in masks:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [[ $DOCKER ]]; then
|
if [[ $DOCKER ]]; then
|
||||||
docker run --privileged -v $PWD:/outside qutebrowser/travis:$DOCKER
|
docker run --privileged -v $PWD:/outside -e QUTE_BDD_WEBENGINE=$QUTE_BDD_WEBENGINE qutebrowser/travis:$DOCKER
|
||||||
else
|
else
|
||||||
args=()
|
args=()
|
||||||
[[ $TESTENV == docs ]] && args=('--no-authors')
|
[[ $TESTENV == docs ]] && args=('--no-authors')
|
||||||
|
@ -21,11 +21,9 @@
|
|||||||
|
|
||||||
"""The qutebrowser test suite conftest file."""
|
"""The qutebrowser test suite conftest file."""
|
||||||
|
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import operator
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import hypothesis
|
import hypothesis
|
||||||
@ -37,10 +35,6 @@ from helpers.logfail import fail_on_logging
|
|||||||
from helpers.messagemock import message_mock
|
from helpers.messagemock import message_mock
|
||||||
from helpers.fixtures import * # pylint: disable=wildcard-import
|
from helpers.fixtures import * # pylint: disable=wildcard-import
|
||||||
|
|
||||||
from PyQt5.QtCore import PYQT_VERSION
|
|
||||||
|
|
||||||
from qutebrowser.utils import qtutils
|
|
||||||
|
|
||||||
|
|
||||||
# Set hypothesis settings
|
# Set hypothesis settings
|
||||||
hypothesis.settings.register_profile('default',
|
hypothesis.settings.register_profile('default',
|
||||||
@ -78,7 +72,7 @@ def _apply_platform_markers(item):
|
|||||||
item.add_marker(skipif_marker)
|
item.add_marker(skipif_marker)
|
||||||
|
|
||||||
|
|
||||||
def pytest_collection_modifyitems(items):
|
def pytest_collection_modifyitems(config, items):
|
||||||
"""Handle custom markers.
|
"""Handle custom markers.
|
||||||
|
|
||||||
pytest hook called after collection has been performed.
|
pytest hook called after collection has been performed.
|
||||||
@ -101,7 +95,12 @@ def pytest_collection_modifyitems(items):
|
|||||||
Reference:
|
Reference:
|
||||||
http://pytest.org/latest/plugins.html
|
http://pytest.org/latest/plugins.html
|
||||||
"""
|
"""
|
||||||
|
remaining_items = []
|
||||||
|
deselected_items = []
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
|
deselected = False
|
||||||
|
|
||||||
if 'qapp' in getattr(item, 'fixturenames', ()):
|
if 'qapp' in getattr(item, 'fixturenames', ()):
|
||||||
item.add_marker('gui')
|
item.add_marker('gui')
|
||||||
|
|
||||||
@ -110,9 +109,13 @@ def pytest_collection_modifyitems(items):
|
|||||||
item.module.__file__,
|
item.module.__file__,
|
||||||
os.path.commonprefix([__file__, item.module.__file__]))
|
os.path.commonprefix([__file__, item.module.__file__]))
|
||||||
|
|
||||||
module_root_dir = os.path.split(module_path)[0]
|
module_root_dir = module_path.split(os.sep)[0]
|
||||||
|
assert module_root_dir in ['end2end', 'unit', 'helpers',
|
||||||
|
'test_conftest.py']
|
||||||
if module_root_dir == 'end2end':
|
if module_root_dir == 'end2end':
|
||||||
item.add_marker(pytest.mark.end2end)
|
item.add_marker(pytest.mark.end2end)
|
||||||
|
elif os.environ.get('QUTE_BDD_WEBENGINE', ''):
|
||||||
|
deselected = True
|
||||||
|
|
||||||
_apply_platform_markers(item)
|
_apply_platform_markers(item)
|
||||||
if item.get_marker('xfail_norun'):
|
if item.get_marker('xfail_norun'):
|
||||||
@ -120,6 +123,14 @@ def pytest_collection_modifyitems(items):
|
|||||||
if item.get_marker('flaky_once'):
|
if item.get_marker('flaky_once'):
|
||||||
item.add_marker(pytest.mark.flaky(reruns=1))
|
item.add_marker(pytest.mark.flaky(reruns=1))
|
||||||
|
|
||||||
|
if deselected:
|
||||||
|
deselected_items.append(item)
|
||||||
|
else:
|
||||||
|
remaining_items.append(item)
|
||||||
|
|
||||||
|
config.hook.pytest_deselected(items=deselected_items)
|
||||||
|
items[:] = remaining_items
|
||||||
|
|
||||||
|
|
||||||
def pytest_ignore_collect(path):
|
def pytest_ignore_collect(path):
|
||||||
"""Ignore BDD tests if we're unable to run them."""
|
"""Ignore BDD tests if we're unable to run them."""
|
||||||
@ -144,6 +155,17 @@ def pytest_addoption(parser):
|
|||||||
help='Use QtWebEngine for BDD tests')
|
help='Use QtWebEngine for BDD tests')
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
webengine_arg = config.getoption('--qute-bdd-webengine')
|
||||||
|
webengine_env = os.environ.get('QUTE_BDD_WEBENGINE', '')
|
||||||
|
config.webengine = bool(webengine_arg or webengine_env)
|
||||||
|
# Fail early if QtWebEngine is not available
|
||||||
|
# pylint: disable=no-name-in-module,unused-variable,useless-suppression
|
||||||
|
if config.webengine:
|
||||||
|
import PyQt5.QtWebEngineWidgets
|
||||||
|
# pylint: enable=no-name-in-module,unused-variable,useless-suppression
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session', autouse=True)
|
@pytest.fixture(scope='session', autouse=True)
|
||||||
def check_display(request):
|
def check_display(request):
|
||||||
if (not request.config.getoption('--no-xvfb') and
|
if (not request.config.getoption('--no-xvfb') and
|
||||||
@ -182,71 +204,3 @@ def pytest_sessionfinish(exitstatus):
|
|||||||
status_file = os.path.join(cache_dir, 'pytest_status')
|
status_file = os.path.join(cache_dir, 'pytest_status')
|
||||||
with open(status_file, 'w', encoding='ascii') as f:
|
with open(status_file, 'w', encoding='ascii') as f:
|
||||||
f.write(str(exitstatus))
|
f.write(str(exitstatus))
|
||||||
|
|
||||||
|
|
||||||
if not getattr(sys, 'frozen', False):
|
|
||||||
def _get_version_tag(tag):
|
|
||||||
"""Handle tags like pyqt>=5.3.1 for BDD tests.
|
|
||||||
|
|
||||||
This transforms e.g. pyqt>=5.3.1 into an appropriate @pytest.mark.skip
|
|
||||||
marker, and falls back to pytest-bdd's implementation for all other
|
|
||||||
casesinto an appropriate @pytest.mark.skip marker, and falls back to
|
|
||||||
"""
|
|
||||||
version_re = re.compile(r"""
|
|
||||||
(?P<package>qt|pyqt)
|
|
||||||
(?P<operator>==|>|>=|<|<=|!=)
|
|
||||||
(?P<version>\d+\.\d+\.\d+)
|
|
||||||
""", re.VERBOSE)
|
|
||||||
|
|
||||||
match = version_re.match(tag)
|
|
||||||
if not match:
|
|
||||||
return None
|
|
||||||
|
|
||||||
operators = {
|
|
||||||
'==': operator.eq,
|
|
||||||
'>': operator.gt,
|
|
||||||
'<': operator.lt,
|
|
||||||
'>=': operator.ge,
|
|
||||||
'<=': operator.le,
|
|
||||||
'!=': operator.ne,
|
|
||||||
}
|
|
||||||
|
|
||||||
package = match.group('package')
|
|
||||||
op = operators[match.group('operator')]
|
|
||||||
version = match.group('version')
|
|
||||||
|
|
||||||
if package == 'qt':
|
|
||||||
return pytest.mark.skipif(qtutils.version_check(version, op),
|
|
||||||
reason='Needs ' + tag)
|
|
||||||
elif package == 'pyqt':
|
|
||||||
major, minor, patch = [int(e) for e in version.split('.')]
|
|
||||||
hex_version = (major << 16) | (minor << 8) | patch
|
|
||||||
return pytest.mark.skipif(not op(PYQT_VERSION, hex_version),
|
|
||||||
reason='Needs ' + tag)
|
|
||||||
else:
|
|
||||||
raise ValueError("Invalid package {!r}".format(package))
|
|
||||||
|
|
||||||
def _get_qtwebengine_tag(tag):
|
|
||||||
"""Handle a @qtwebengine_* tag."""
|
|
||||||
pytest_marks = {
|
|
||||||
'qtwebengine_todo': pytest.mark.qtwebengine_todo,
|
|
||||||
'qtwebengine_skip': pytest.mark.qtwebengine_skip,
|
|
||||||
}
|
|
||||||
if not any(tag.startswith(t + ':') for t in pytest_marks):
|
|
||||||
return None
|
|
||||||
name, desc = tag.split(':', maxsplit=1)
|
|
||||||
return pytest_marks[name](desc)
|
|
||||||
|
|
||||||
def pytest_bdd_apply_tag(tag, function):
|
|
||||||
"""Handle custom tags for BDD tests.
|
|
||||||
|
|
||||||
This tries various functions, and if none knows how to handle this tag,
|
|
||||||
it returns None so it falls back to pytest-bdd's implementation.
|
|
||||||
"""
|
|
||||||
funcs = [_get_version_tag, _get_qtwebengine_tag]
|
|
||||||
for func in funcs:
|
|
||||||
mark = func(tag)
|
|
||||||
if mark is not None:
|
|
||||||
mark(function)
|
|
||||||
return True
|
|
||||||
return None
|
|
||||||
|
@ -21,11 +21,16 @@
|
|||||||
|
|
||||||
"""Things needed for end2end testing."""
|
"""Things needed for end2end testing."""
|
||||||
|
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
import pstats
|
import pstats
|
||||||
import os.path
|
import os.path
|
||||||
|
import operator
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from PyQt5.QtCore import PYQT_VERSION
|
||||||
|
|
||||||
pytest.register_assert_rewrite('end2end.fixtures')
|
pytest.register_assert_rewrite('end2end.fixtures')
|
||||||
|
|
||||||
@ -33,6 +38,7 @@ from end2end.fixtures.webserver import httpbin, httpbin_after_test, ssl_server
|
|||||||
from end2end.fixtures.quteprocess import (quteproc_process, quteproc,
|
from end2end.fixtures.quteprocess import (quteproc_process, quteproc,
|
||||||
quteproc_new)
|
quteproc_new)
|
||||||
from end2end.fixtures.testprocess import pytest_runtest_makereport
|
from end2end.fixtures.testprocess import pytest_runtest_makereport
|
||||||
|
from qutebrowser.utils import qtutils
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
@ -51,3 +57,104 @@ def pytest_unconfigure(config):
|
|||||||
for fn in os.listdir('prof'):
|
for fn in os.listdir('prof'):
|
||||||
stats.add(os.path.join('prof', fn))
|
stats.add(os.path.join('prof', fn))
|
||||||
stats.dump_stats(os.path.join('prof', 'combined.pstats'))
|
stats.dump_stats(os.path.join('prof', 'combined.pstats'))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_version_tag(tag):
|
||||||
|
"""Handle tags like pyqt>=5.3.1 for BDD tests.
|
||||||
|
|
||||||
|
This transforms e.g. pyqt>=5.3.1 into an appropriate @pytest.mark.skip
|
||||||
|
marker, and falls back to pytest-bdd's implementation for all other
|
||||||
|
casesinto an appropriate @pytest.mark.skip marker, and falls back to
|
||||||
|
"""
|
||||||
|
version_re = re.compile(r"""
|
||||||
|
(?P<package>qt|pyqt)
|
||||||
|
(?P<operator>==|>|>=|<|<=|!=)
|
||||||
|
(?P<version>\d+\.\d+\.\d+)
|
||||||
|
""", re.VERBOSE)
|
||||||
|
|
||||||
|
match = version_re.match(tag)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
|
operators = {
|
||||||
|
'==': operator.eq,
|
||||||
|
'>': operator.gt,
|
||||||
|
'<': operator.lt,
|
||||||
|
'>=': operator.ge,
|
||||||
|
'<=': operator.le,
|
||||||
|
'!=': operator.ne,
|
||||||
|
}
|
||||||
|
|
||||||
|
package = match.group('package')
|
||||||
|
op = operators[match.group('operator')]
|
||||||
|
version = match.group('version')
|
||||||
|
|
||||||
|
if package == 'qt':
|
||||||
|
return pytest.mark.skipif(qtutils.version_check(version, op),
|
||||||
|
reason='Needs ' + tag)
|
||||||
|
elif package == 'pyqt':
|
||||||
|
major, minor, patch = [int(e) for e in version.split('.')]
|
||||||
|
hex_version = (major << 16) | (minor << 8) | patch
|
||||||
|
return pytest.mark.skipif(not op(PYQT_VERSION, hex_version),
|
||||||
|
reason='Needs ' + tag)
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid package {!r}".format(package))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_backend_tag(tag):
|
||||||
|
"""Handle a @qtwebengine_*/@qtwebkit_skip tag."""
|
||||||
|
pytest_marks = {
|
||||||
|
'qtwebengine_todo': pytest.mark.qtwebengine_todo,
|
||||||
|
'qtwebengine_skip': pytest.mark.qtwebengine_skip,
|
||||||
|
'qtwebkit_skip': pytest.mark.qtwebkit_skip
|
||||||
|
}
|
||||||
|
if not any(tag.startswith(t + ':') for t in pytest_marks):
|
||||||
|
return None
|
||||||
|
name, desc = tag.split(':', maxsplit=1)
|
||||||
|
return pytest_marks[name](desc)
|
||||||
|
|
||||||
|
|
||||||
|
if not getattr(sys, 'frozen', False):
|
||||||
|
def pytest_bdd_apply_tag(tag, function):
|
||||||
|
"""Handle custom tags for BDD tests.
|
||||||
|
|
||||||
|
This tries various functions, and if none knows how to handle this tag,
|
||||||
|
it returns None so it falls back to pytest-bdd's implementation.
|
||||||
|
"""
|
||||||
|
funcs = [_get_version_tag, _get_backend_tag]
|
||||||
|
for func in funcs:
|
||||||
|
mark = func(tag)
|
||||||
|
if mark is not None:
|
||||||
|
mark(function)
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_collection_modifyitems(config, items):
|
||||||
|
"""Apply @qtwebengine_* markers; skip unittests with QUTE_BDD_WEBENGINE."""
|
||||||
|
vercheck = qtutils.version_check
|
||||||
|
qtbug_54419_fixed = ((vercheck('5.6.2') and not vercheck('5.7.0')) or
|
||||||
|
qtutils.version_check('5.7.1') or
|
||||||
|
os.environ.get('QUTE_QTBUG54419_PATCHED', ''))
|
||||||
|
|
||||||
|
markers = [
|
||||||
|
('qtwebengine_createWindow', 'Skipped because of QTBUG-54419',
|
||||||
|
pytest.mark.skipif, not qtbug_54419_fixed and config.webengine),
|
||||||
|
('qtwebengine_todo', 'QtWebEngine TODO', pytest.mark.xfail,
|
||||||
|
config.webengine),
|
||||||
|
('qtwebengine_skip', 'Skipped with QtWebEngine', pytest.mark.skipif,
|
||||||
|
config.webengine),
|
||||||
|
('qtwebkit_skip', 'Skipped with QtWebKit', pytest.mark.skipif,
|
||||||
|
not config.webengine),
|
||||||
|
]
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
for name, prefix, pytest_mark, condition in markers:
|
||||||
|
marker = item.get_marker(name)
|
||||||
|
if marker and condition:
|
||||||
|
if marker.args:
|
||||||
|
text = '{}: {}'.format(prefix, marker.args[0])
|
||||||
|
else:
|
||||||
|
text = prefix
|
||||||
|
item.add_marker(pytest_mark(condition, reason=text,
|
||||||
|
**marker.kwargs))
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<button onclick="openWin()" id="open-button">Open "myWindow"</button>
|
|
||||||
<button onclick="closeWin()" id="close-button">Close "myWindow"</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var myWindow;
|
|
||||||
|
|
||||||
function openWin() {
|
|
||||||
myWindow = window.open("", "myWindow", "width=200, height=100");
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeWin() {
|
|
||||||
myWindow.close();
|
|
||||||
myWindow.close();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
44
tests/end2end/data/javascript/window_open.html
Normal file
44
tests/end2end/data/javascript/window_open.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var my_window;
|
||||||
|
|
||||||
|
function open_modal() {
|
||||||
|
if (window.showModalDialog) {
|
||||||
|
window.showModalDialog();
|
||||||
|
} else {
|
||||||
|
window.open('about:blank', 'window', 'modal');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function open_normal() {
|
||||||
|
my_window = window.open('about:blank', 'my_window');
|
||||||
|
}
|
||||||
|
|
||||||
|
function open_invalid() {
|
||||||
|
window.open('', 'my_window');
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
my_window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function close_twice() {
|
||||||
|
my_window.close();
|
||||||
|
my_window.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button onclick="open_normal()" id="open-normal">normal</button>
|
||||||
|
<button onclick="open_modal()" id="open-modal">modal</button>
|
||||||
|
<button onclick="open_invalid()" id="open-invalid">invalid/no URL</button>
|
||||||
|
<button onclick="close()" id="close-normal">close</button>
|
||||||
|
<button onclick="close_twice()" id="close-twice">close twice (issue 906)</button>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -88,7 +88,6 @@ Feature: Going back and forward.
|
|||||||
- url: http://localhost:*/data/backforward/2.txt
|
- url: http://localhost:*/data/backforward/2.txt
|
||||||
- url: http://localhost:*/data/backforward/3.txt
|
- url: http://localhost:*/data/backforward/3.txt
|
||||||
|
|
||||||
@qtwebengine_skip: Causes 'Ignoring invalid URL being added to history' sometimes?
|
|
||||||
Scenario: Going back too much with count.
|
Scenario: Going back too much with count.
|
||||||
Given I open data/backforward/1.txt
|
Given I open data/backforward/1.txt
|
||||||
When I open data/backforward/2.txt
|
When I open data/backforward/2.txt
|
||||||
@ -138,7 +137,6 @@ Feature: Going back and forward.
|
|||||||
When I run :forward
|
When I run :forward
|
||||||
Then the error "At end of history." should be shown
|
Then the error "At end of history." should be shown
|
||||||
|
|
||||||
@qtwebengine_skip: Causes 'Ignoring invalid URL being added to history' sometimes?
|
|
||||||
Scenario: Going forward too much with count.
|
Scenario: Going forward too much with count.
|
||||||
Given I open data/backforward/1.txt
|
Given I open data/backforward/1.txt
|
||||||
When I open data/backforward/2.txt
|
When I open data/backforward/2.txt
|
||||||
|
@ -34,27 +34,6 @@ from qutebrowser.utils import log
|
|||||||
from helpers import utils
|
from helpers import utils
|
||||||
|
|
||||||
|
|
||||||
def pytest_collection_modifyitems(config, items):
|
|
||||||
"""Apply @qtwebengine_* markers."""
|
|
||||||
webengine = config.getoption('--qute-bdd-webengine')
|
|
||||||
|
|
||||||
markers = {
|
|
||||||
'qtwebengine_todo': ('QtWebEngine TODO', pytest.mark.xfail),
|
|
||||||
'qtwebengine_skip': ('Skipped with QtWebEngine', pytest.mark.skipif),
|
|
||||||
}
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
for name, (prefix, pytest_mark) in markers.items():
|
|
||||||
marker = item.get_marker(name)
|
|
||||||
if marker:
|
|
||||||
if marker.args:
|
|
||||||
text = '{}: {}'.format(prefix, marker.args[0])
|
|
||||||
else:
|
|
||||||
text = prefix
|
|
||||||
item.add_marker(pytest_mark(webengine, reason=text,
|
|
||||||
**marker.kwargs))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
"""Add a BDD section to the test output."""
|
"""Add a BDD section to the test output."""
|
||||||
@ -429,7 +408,7 @@ def compare_session(request, quteproc, expected):
|
|||||||
partial_compare is used, which means only the keys/values listed will be
|
partial_compare is used, which means only the keys/values listed will be
|
||||||
compared.
|
compared.
|
||||||
"""
|
"""
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
||||||
quteproc.compare_session(expected)
|
quteproc.compare_session(expected)
|
||||||
|
|
||||||
@ -494,7 +473,7 @@ def check_open_tabs(quteproc, request, tabs):
|
|||||||
|
|
||||||
It expects a list of URLs, with an optional "(active)" suffix.
|
It expects a list of URLs, with an optional "(active)" suffix.
|
||||||
"""
|
"""
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
||||||
session = quteproc.get_session()
|
session = quteproc.get_session()
|
||||||
active_suffix = ' (active)'
|
active_suffix = ' (active)'
|
||||||
@ -551,7 +530,7 @@ def _get_scroll_values(quteproc):
|
|||||||
@bdd.then(bdd.parsers.re(r"the page should be scrolled "
|
@bdd.then(bdd.parsers.re(r"the page should be scrolled "
|
||||||
r"(?P<direction>horizontally|vertically)"))
|
r"(?P<direction>horizontally|vertically)"))
|
||||||
def check_scrolled(request, quteproc, direction):
|
def check_scrolled(request, quteproc, direction):
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
||||||
x, y = _get_scroll_values(quteproc)
|
x, y = _get_scroll_values(quteproc)
|
||||||
if direction == 'horizontally':
|
if direction == 'horizontally':
|
||||||
@ -564,7 +543,7 @@ def check_scrolled(request, quteproc, direction):
|
|||||||
|
|
||||||
@bdd.then("the page should not be scrolled")
|
@bdd.then("the page should not be scrolled")
|
||||||
def check_not_scrolled(request, quteproc):
|
def check_not_scrolled(request, quteproc):
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
||||||
x, y = _get_scroll_values(quteproc)
|
x, y = _get_scroll_values(quteproc)
|
||||||
assert x == 0
|
assert x == 0
|
||||||
|
@ -9,6 +9,7 @@ Feature: Using hints
|
|||||||
And I hint with args "links normal" and follow xyz
|
And I hint with args "links normal" and follow xyz
|
||||||
Then the error "No hint xyz!" should be shown
|
Then the error "No hint xyz!" should be shown
|
||||||
|
|
||||||
|
@qtwebengine_skip: Flaky because scrolling happens async
|
||||||
Scenario: Following a link after scrolling down
|
Scenario: Following a link after scrolling down
|
||||||
When I open data/scroll/simple.html
|
When I open data/scroll/simple.html
|
||||||
And I run :hint links normal
|
And I run :hint links normal
|
||||||
@ -19,7 +20,7 @@ Feature: Using hints
|
|||||||
|
|
||||||
### Opening in current or new tab
|
### Opening in current or new tab
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: Following a hint and force to open in current tab.
|
Scenario: Following a hint and force to open in current tab.
|
||||||
When I open data/hints/link_blank.html
|
When I open data/hints/link_blank.html
|
||||||
And I hint with args "links current" and follow a
|
And I hint with args "links current" and follow a
|
||||||
@ -27,7 +28,7 @@ Feature: Using hints
|
|||||||
Then the following tabs should be open:
|
Then the following tabs should be open:
|
||||||
- data/hello.txt (active)
|
- data/hello.txt (active)
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: Following a hint and allow to open in new tab.
|
Scenario: Following a hint and allow to open in new tab.
|
||||||
When I open data/hints/link_blank.html
|
When I open data/hints/link_blank.html
|
||||||
And I hint with args "links normal" and follow a
|
And I hint with args "links normal" and follow a
|
||||||
@ -36,7 +37,7 @@ Feature: Using hints
|
|||||||
- data/hints/link_blank.html
|
- data/hints/link_blank.html
|
||||||
- data/hello.txt (active)
|
- data/hello.txt (active)
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: Following a hint to link with sub-element and force to open in current tab.
|
Scenario: Following a hint to link with sub-element and force to open in current tab.
|
||||||
When I open data/hints/link_span.html
|
When I open data/hints/link_span.html
|
||||||
And I run :tab-close
|
And I run :tab-close
|
||||||
@ -154,13 +155,13 @@ Feature: Using hints
|
|||||||
And I hint wht args "links normal" and follow a
|
And I hint wht args "links normal" and follow a
|
||||||
Then "navigation request: url http://localhost:*/data/hello2.txt, type NavigationTypeLinkClicked, *" should be logged
|
Then "navigation request: url http://localhost:*/data/hello2.txt, type NavigationTypeLinkClicked, *" should be logged
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: Opening a link inside a specific iframe
|
Scenario: Opening a link inside a specific iframe
|
||||||
When I open data/hints/iframe_target.html
|
When I open data/hints/iframe_target.html
|
||||||
And I hint with args "links normal" and follow a
|
And I hint with args "links normal" and follow a
|
||||||
Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged
|
Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: Opening a link with specific target frame in a new tab
|
Scenario: Opening a link with specific target frame in a new tab
|
||||||
When I open data/hints/iframe_target.html
|
When I open data/hints/iframe_target.html
|
||||||
And I hint with args "links tab" and follow a
|
And I hint with args "links tab" and follow a
|
||||||
@ -172,7 +173,7 @@ Feature: Using hints
|
|||||||
### hints -> auto-follow-timeout
|
### hints -> auto-follow-timeout
|
||||||
|
|
||||||
Scenario: Ignoring key presses after auto-following hints
|
Scenario: Ignoring key presses after auto-following hints
|
||||||
When I set hints -> auto-follow-timeout to 200
|
When I set hints -> auto-follow-timeout to 500
|
||||||
And I set hints -> mode to number
|
And I set hints -> mode to number
|
||||||
And I run :bind --force , message-error "This should not happen"
|
And I run :bind --force , message-error "This should not happen"
|
||||||
And I open data/hints/html/simple.html
|
And I open data/hints/html/simple.html
|
||||||
|
@ -48,6 +48,12 @@ Feature: Page history
|
|||||||
Then the history file should contain:
|
Then the history file should contain:
|
||||||
http://localhost:(port)/status/404 Error loading page: http://localhost:(port)/status/404
|
http://localhost:(port)/status/404 Error loading page: http://localhost:(port)/status/404
|
||||||
|
|
||||||
|
@qtwebengine_createWindow
|
||||||
|
Scenario: History with invalid URL
|
||||||
|
When I open data/javascript/window_open.html
|
||||||
|
And I run :click-element id open-invalid
|
||||||
|
Then "Changing title for idx 1 to 'about:blank'" should be logged
|
||||||
|
|
||||||
Scenario: Clearing history
|
Scenario: Clearing history
|
||||||
When I open data/title.html
|
When I open data/title.html
|
||||||
And I run :history-clear
|
And I run :history-clear
|
||||||
|
@ -7,14 +7,67 @@ Feature: Javascript stuff
|
|||||||
And I open data/javascript/consolelog.html
|
And I open data/javascript/consolelog.html
|
||||||
Then the javascript message "console.log works!" should be logged
|
Then the javascript message "console.log works!" should be logged
|
||||||
|
|
||||||
|
# Causes segfaults...
|
||||||
|
@qtwebengine_createWindow
|
||||||
|
Scenario: Opening/Closing a window via JS
|
||||||
|
When I open data/javascript/window_open.html
|
||||||
|
And I run :tab-only
|
||||||
|
And I run :click-element id open-normal
|
||||||
|
And I wait for "Changing title for idx 1 to 'about:blank'" in the log
|
||||||
|
And I run :tab-focus 1
|
||||||
|
And I run :click-element id close-normal
|
||||||
|
Then "Focus object changed: *" should be logged
|
||||||
|
|
||||||
|
# Causes segfaults...
|
||||||
|
@qtwebengine_createWindow
|
||||||
|
Scenario: Opening/closing a modal window via JS
|
||||||
|
When I open data/javascript/window_open.html
|
||||||
|
And I run :tab-only
|
||||||
|
And I run :click-element id open-modal
|
||||||
|
And I wait for "Changing title for idx 1 to 'about:blank'" in the log
|
||||||
|
And I run :tab-focus 1
|
||||||
|
And I run :click-element id close-normal
|
||||||
|
Then "Focus object changed: *" should be logged
|
||||||
|
# WebModalDialog with QtWebKit, WebDialog with QtWebEngine
|
||||||
|
And "Web*Dialog requested, but we don't support that!" should be logged
|
||||||
|
|
||||||
# https://github.com/The-Compiler/qutebrowser/issues/906
|
# https://github.com/The-Compiler/qutebrowser/issues/906
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_skip
|
||||||
Scenario: Closing a JS window twice (issue 906)
|
Scenario: Closing a JS window twice (issue 906) - qtwebkit
|
||||||
When I open about:blank
|
When I open about:blank
|
||||||
And I open data/javascript/issue906.html in a new tab
|
And I run :tab-only
|
||||||
And I run :click-element id open-button
|
When I open data/javascript/window_open.html in a new tab
|
||||||
|
And I run :click-element id open-normal
|
||||||
And I wait for "Changing title for idx 2 to 'about:blank'" in the log
|
And I wait for "Changing title for idx 2 to 'about:blank'" in the log
|
||||||
And I run :tab-focus 2
|
And I run :tab-focus 2
|
||||||
And I run :click-element id close-button
|
And I run :click-element id close-twice
|
||||||
Then "Requested to close * which does not exist!" should be logged
|
Then "Requested to close * which does not exist!" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_createWindow @qtwebkit_skip
|
||||||
|
Scenario: Closing a JS window twice (issue 906) - qtwebengine
|
||||||
|
When I open about:blank
|
||||||
|
And I run :tab-only
|
||||||
|
And I open data/javascript/window_open.html in a new tab
|
||||||
|
And I run :click-element id open-normal
|
||||||
|
And I wait for "Changing title for idx 2 to 'about:blank'" in the log
|
||||||
|
And I run :tab-focus 2
|
||||||
|
And I run :click-element id close-twice
|
||||||
|
And I wait for "Focus object changed: *" in the log
|
||||||
|
Then no crash should happen
|
||||||
|
|
||||||
|
@qtwebengine_createWindow
|
||||||
|
Scenario: Opening window without user interaction with javascript-can-open-windows-automatically set to true
|
||||||
|
When I open data/hello.txt
|
||||||
|
And I set content -> javascript-can-open-windows-automatically to true
|
||||||
|
And I run :tab-only
|
||||||
|
And I run :jseval if (window.open('about:blank')) { console.log('window opened'); } else { console.log('error while opening window'); }
|
||||||
|
Then the javascript message "window opened" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_createWindow
|
||||||
|
Scenario: Opening window without user interaction with javascript-can-open-windows-automatically set to false
|
||||||
|
When I open data/hello.txt
|
||||||
|
And I set content -> javascript-can-open-windows-automatically to false
|
||||||
|
And I run :tab-only
|
||||||
|
And I run :jseval if (window.open('about:blank')) { console.log('window opened'); } else { console.log('error while opening window'); }
|
||||||
|
Then the javascript message "error while opening window" should be logged
|
||||||
|
@ -551,7 +551,7 @@ Feature: Various utility commands.
|
|||||||
Then the page should not be scrolled
|
Then the page should not be scrolled
|
||||||
And the error "prompt-accept: This command is only allowed in prompt/yesno mode." should be shown
|
And the error "prompt-accept: This command is only allowed in prompt/yesno mode." should be shown
|
||||||
|
|
||||||
@qtwebengine_todo: createWindow is not implemented yet
|
@qtwebengine_createWindow
|
||||||
Scenario: :repeat-command with mode-switching command
|
Scenario: :repeat-command with mode-switching command
|
||||||
Given I open data/hints/link_blank.html
|
Given I open data/hints/link_blank.html
|
||||||
And I run :tab-only
|
And I run :tab-only
|
||||||
@ -620,6 +620,7 @@ Feature: Various utility commands.
|
|||||||
- data/click_element.html
|
- data/click_element.html
|
||||||
- data/hello.txt (active)
|
- data/hello.txt (active)
|
||||||
|
|
||||||
|
@qtwebengine_skip: Flaky because scrolling happens async
|
||||||
Scenario: Clicking an element which is out of view
|
Scenario: Clicking an element which is out of view
|
||||||
When I open data/scroll/simple.html
|
When I open data/scroll/simple.html
|
||||||
And I run :scroll-page 0 1
|
And I run :scroll-page 0 1
|
||||||
|
@ -24,7 +24,7 @@ bdd.scenarios('marks.feature')
|
|||||||
|
|
||||||
@bdd.then(bdd.parsers.parse("the page should be scrolled to {x} {y}"))
|
@bdd.then(bdd.parsers.parse("the page should be scrolled to {x} {y}"))
|
||||||
def check_y(request, quteproc, x, y):
|
def check_y(request, quteproc, x, y):
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
pytest.xfail(reason="QtWebEngine TODO: Sessions are not implemented")
|
||||||
data = quteproc.get_session()
|
data = quteproc.get_session()
|
||||||
pos = data['windows'][0]['tabs'][0]['history'][-1]['scroll-pos']
|
pos = data['windows'][0]['tabs'][0]['history'][-1]['scroll-pos']
|
||||||
|
@ -157,7 +157,6 @@ class QuteProc(testprocess.Process):
|
|||||||
|
|
||||||
def __init__(self, request, *, parent=None):
|
def __init__(self, request, *, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._webengine = request.config.getoption('--qute-bdd-webengine')
|
|
||||||
self._ipc_socket = None
|
self._ipc_socket = None
|
||||||
self.basedir = None
|
self.basedir = None
|
||||||
self._focus_ready = False
|
self._focus_ready = False
|
||||||
@ -261,7 +260,7 @@ class QuteProc(testprocess.Process):
|
|||||||
return executable, args
|
return executable, args
|
||||||
|
|
||||||
def _default_args(self):
|
def _default_args(self):
|
||||||
backend = 'webengine' if self._webengine else 'webkit'
|
backend = 'webengine' if self.request.config.webengine else 'webkit'
|
||||||
return ['--debug', '--no-err-windows', '--temp-basedir',
|
return ['--debug', '--no-err-windows', '--temp-basedir',
|
||||||
'--json-logging', '--backend', backend, 'about:blank']
|
'--json-logging', '--backend', backend, 'about:blank']
|
||||||
|
|
||||||
@ -338,7 +337,7 @@ class QuteProc(testprocess.Process):
|
|||||||
('general', 'auto-save-interval', '0'),
|
('general', 'auto-save-interval', '0'),
|
||||||
('general', 'new-instance-open-target.window', 'last-opened')
|
('general', 'new-instance-open-target.window', 'last-opened')
|
||||||
]
|
]
|
||||||
if not self._webengine:
|
if not self.request.config.webengine:
|
||||||
settings.append(('network', 'ssl-strict', 'false'))
|
settings.append(('network', 'ssl-strict', 'false'))
|
||||||
|
|
||||||
for sect, opt, value in settings:
|
for sect, opt, value in settings:
|
||||||
|
@ -234,7 +234,7 @@ class Process(QObject):
|
|||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
# _start ensures it actually started, but it might quit shortly
|
# _start ensures it actually started, but it might quit shortly
|
||||||
# afterwards
|
# afterwards
|
||||||
raise ProcessExited()
|
raise ProcessExited('\n' + _render_log(self.captured_log))
|
||||||
|
|
||||||
if blocker.signal_triggered:
|
if blocker.signal_triggered:
|
||||||
self._after_start()
|
self._after_start()
|
||||||
|
@ -85,21 +85,20 @@ def _parse_file(test_name):
|
|||||||
@pytest.mark.parametrize('find_implementation', ['javascript', 'python'])
|
@pytest.mark.parametrize('find_implementation', ['javascript', 'python'])
|
||||||
def test_hints(test_name, zoom_text_only, zoom_level, find_implementation,
|
def test_hints(test_name, zoom_text_only, zoom_level, find_implementation,
|
||||||
quteproc, request):
|
quteproc, request):
|
||||||
webengine = bool(request.config.getoption('--qute-bdd-webengine'))
|
if zoom_text_only and request.config.webengine:
|
||||||
if zoom_text_only and webengine:
|
|
||||||
pytest.skip("QtWebEngine doesn't have zoom-text-only")
|
pytest.skip("QtWebEngine doesn't have zoom-text-only")
|
||||||
if find_implementation == 'python' and webengine:
|
if find_implementation == 'python' and request.config.webengine:
|
||||||
pytest.skip("QtWebEngine doesn't have a python find implementation")
|
pytest.skip("QtWebEngine doesn't have a python find implementation")
|
||||||
|
|
||||||
parsed = _parse_file(test_name)
|
parsed = _parse_file(test_name)
|
||||||
if parsed.qtwebengine_todo is not None and webengine:
|
if parsed.qtwebengine_todo is not None and request.config.webengine:
|
||||||
pytest.xfail("QtWebEngine TODO: {}".format(parsed.qtwebengine_todo))
|
pytest.xfail("QtWebEngine TODO: {}".format(parsed.qtwebengine_todo))
|
||||||
|
|
||||||
url_path = 'data/hints/html/{}'.format(test_name)
|
url_path = 'data/hints/html/{}'.format(test_name)
|
||||||
quteproc.open_path(url_path)
|
quteproc.open_path(url_path)
|
||||||
|
|
||||||
# setup
|
# setup
|
||||||
if not webengine:
|
if not request.config.webengine:
|
||||||
quteproc.set_setting('ui', 'zoom-text-only', str(zoom_text_only))
|
quteproc.set_setting('ui', 'zoom-text-only', str(zoom_text_only))
|
||||||
quteproc.set_setting('hints', 'find-implementation',
|
quteproc.set_setting('hints', 'find-implementation',
|
||||||
find_implementation)
|
find_implementation)
|
||||||
@ -111,7 +110,7 @@ def test_hints(test_name, zoom_text_only, zoom_level, find_implementation,
|
|||||||
quteproc.wait_for_load_finished('data/' + parsed.target)
|
quteproc.wait_for_load_finished('data/' + parsed.target)
|
||||||
# reset
|
# reset
|
||||||
quteproc.send_cmd(':zoom 100')
|
quteproc.send_cmd(':zoom 100')
|
||||||
if not webengine:
|
if not request.config.webengine:
|
||||||
quteproc.set_setting('ui', 'zoom-text-only', 'false')
|
quteproc.set_setting('ui', 'zoom-text-only', 'false')
|
||||||
quteproc.set_setting('hints', 'find-implementation', 'javascript')
|
quteproc.set_setting('hints', 'find-implementation', 'javascript')
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ def test_insert_mode(file_name, elem_id, source, input_text, auto_insert,
|
|||||||
if source == 'keypress':
|
if source == 'keypress':
|
||||||
quteproc.press_keys(input_text)
|
quteproc.press_keys(input_text)
|
||||||
elif source == 'clipboard':
|
elif source == 'clipboard':
|
||||||
if request.config.getoption('--qute-bdd-webengine'):
|
if request.config.webengine:
|
||||||
pytest.xfail(reason="QtWebEngine TODO: :insert-text is not "
|
pytest.xfail(reason="QtWebEngine TODO: :insert-text is not "
|
||||||
"implemented")
|
"implemented")
|
||||||
quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(input_text))
|
quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(input_text))
|
||||||
|
@ -76,6 +76,7 @@ def test_parse_fatal_stacktrace(text, typ, func):
|
|||||||
"QT_IM_MODULE = fcitx"
|
"QT_IM_MODULE = fcitx"
|
||||||
),
|
),
|
||||||
({'LANGUAGE': 'foo', 'LANG': 'en_US.UTF-8'}, "LANG = en_US.UTF-8"),
|
({'LANGUAGE': 'foo', 'LANG': 'en_US.UTF-8'}, "LANG = en_US.UTF-8"),
|
||||||
|
({'FOO': 'bar', 'QUTE_BLAH': '1'}, "QUTE_BLAH = 1"),
|
||||||
], ids=lambda e: e[1])
|
], ids=lambda e: e[1])
|
||||||
def test_get_environment_vars(monkeypatch, env, expected):
|
def test_get_environment_vars(monkeypatch, env, expected):
|
||||||
"""Test for crashdialog._get_environment_vars."""
|
"""Test for crashdialog._get_environment_vars."""
|
||||||
|
2
tox.ini
2
tox.ini
@ -13,7 +13,7 @@ skipsdist = true
|
|||||||
setenv =
|
setenv =
|
||||||
QT_QPA_PLATFORM_PLUGIN_PATH={envdir}/Lib/site-packages/PyQt5/plugins/platforms
|
QT_QPA_PLATFORM_PLUGIN_PATH={envdir}/Lib/site-packages/PyQt5/plugins/platforms
|
||||||
PYTEST_QT_API=pyqt5
|
PYTEST_QT_API=pyqt5
|
||||||
passenv = PYTHON DISPLAY XAUTHORITY HOME USERNAME USER CI TRAVIS XDG_*
|
passenv = PYTHON DISPLAY XAUTHORITY HOME USERNAME USER CI TRAVIS XDG_* QUTE_*
|
||||||
deps =
|
deps =
|
||||||
-r{toxinidir}/misc/requirements/requirements-pip.txt
|
-r{toxinidir}/misc/requirements/requirements-pip.txt
|
||||||
-r{toxinidir}/requirements.txt
|
-r{toxinidir}/requirements.txt
|
||||||
|
Loading…
Reference in New Issue
Block a user