webengine: Initial support for authentication and javascript prompts
This commit is contained in:
parent
6d72bce4b6
commit
65625a9dea
@ -19,7 +19,15 @@
|
|||||||
|
|
||||||
"""Various utilities shared between webpage/webview subclasses."""
|
"""Various utilities shared between webpage/webview subclasses."""
|
||||||
|
|
||||||
|
import html
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
|
from qutebrowser.utils import usertypes, message, log
|
||||||
|
|
||||||
|
|
||||||
|
class CallSuper(Exception):
|
||||||
|
|
||||||
|
"""Raised when the caller should call the superclass instead."""
|
||||||
|
|
||||||
|
|
||||||
def custom_headers():
|
def custom_headers():
|
||||||
@ -39,3 +47,66 @@ def custom_headers():
|
|||||||
headers[b'Accept-Language'] = accept_language.encode('ascii')
|
headers[b'Accept-Language'] = accept_language.encode('ascii')
|
||||||
|
|
||||||
return sorted(headers.items())
|
return sorted(headers.items())
|
||||||
|
|
||||||
|
|
||||||
|
def authentication_required(url, authenticator, abort_on):
|
||||||
|
"""Ask a prompt for an authentication question."""
|
||||||
|
msg = '<b>{}</b> says:<br/>{}'.format(
|
||||||
|
html.escape(url.toDisplayString()),
|
||||||
|
html.escape(authenticator.realm()))
|
||||||
|
answer = message.ask(title="Authentication required", text=msg,
|
||||||
|
mode=usertypes.PromptMode.user_pwd,
|
||||||
|
abort_on=abort_on)
|
||||||
|
if answer is not None:
|
||||||
|
authenticator.setUser(answer.user)
|
||||||
|
authenticator.setPassword(answer.password)
|
||||||
|
|
||||||
|
|
||||||
|
def javascript_confirm(url, js_msg, abort_on):
|
||||||
|
"""Display a javascript confirm prompt."""
|
||||||
|
log.js.debug("confirm: {}".format(js_msg))
|
||||||
|
if config.get('ui', 'modal-js-dialog'):
|
||||||
|
raise CallSuper
|
||||||
|
|
||||||
|
msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
|
||||||
|
html.escape(js_msg))
|
||||||
|
ans = message.ask('Javascript confirm', msg,
|
||||||
|
mode=usertypes.PromptMode.yesno,
|
||||||
|
abort_on=abort_on)
|
||||||
|
return bool(ans)
|
||||||
|
|
||||||
|
|
||||||
|
def javascript_prompt(url, js_msg, default, abort_on):
|
||||||
|
"""Display a javascript prompt."""
|
||||||
|
log.js.debug("prompt: {}".format(js_msg))
|
||||||
|
if config.get('ui', 'modal-js-dialog'):
|
||||||
|
raise CallSuper
|
||||||
|
if config.get('content', 'ignore-javascript-prompt'):
|
||||||
|
return (False, "")
|
||||||
|
|
||||||
|
msg = '<b>{}</b> asks:<br/>{}'.format(html.escape(url.toDisplayString()),
|
||||||
|
html.escape(js_msg))
|
||||||
|
answer = message.ask('Javascript prompt', msg,
|
||||||
|
mode=usertypes.PromptMode.text,
|
||||||
|
default=default,
|
||||||
|
abort_on=abort_on)
|
||||||
|
|
||||||
|
if answer is None:
|
||||||
|
return (False, "")
|
||||||
|
else:
|
||||||
|
return (True, answer)
|
||||||
|
|
||||||
|
|
||||||
|
def javascript_alert(url, js_msg, abort_on):
|
||||||
|
"""Display a javascript alert."""
|
||||||
|
log.js.debug("alert: {}".format(js_msg))
|
||||||
|
if config.get('ui', 'modal-js-dialog'):
|
||||||
|
raise CallSuper
|
||||||
|
|
||||||
|
if config.get('content', 'ignore-javascript-alert'):
|
||||||
|
return
|
||||||
|
|
||||||
|
msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
|
||||||
|
html.escape(js_msg))
|
||||||
|
message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert,
|
||||||
|
abort_on=abort_on)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
"""Wrapper over a QWebEngineView."""
|
"""Wrapper over a QWebEngineView."""
|
||||||
|
|
||||||
|
import html
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint, QUrl, QTimer
|
from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint, QUrl, QTimer
|
||||||
@ -32,12 +33,12 @@ from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineScript,
|
|||||||
QWebEngineProfile)
|
QWebEngineProfile)
|
||||||
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
||||||
|
|
||||||
from qutebrowser.browser import browsertab, mouse
|
from qutebrowser.browser import browsertab, mouse, shared
|
||||||
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
||||||
interceptor, webenginequtescheme,
|
interceptor, webenginequtescheme,
|
||||||
webenginedownloads)
|
webenginedownloads)
|
||||||
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
||||||
objreg)
|
objreg, message)
|
||||||
|
|
||||||
|
|
||||||
_qute_scheme_handler = None
|
_qute_scheme_handler = None
|
||||||
@ -538,7 +539,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
self._widget.page().runJavaScript(code, callback)
|
self._widget.page().runJavaScript(code, callback)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
log.stub()
|
self._widget.shutdown()
|
||||||
|
|
||||||
def reload(self, *, force=False):
|
def reload(self, *, force=False):
|
||||||
if force:
|
if force:
|
||||||
@ -590,6 +591,13 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
|
|
||||||
self.add_history_item.emit(url, requested_url, title)
|
self.add_history_item.emit(url, requested_url, title)
|
||||||
|
|
||||||
|
@pyqtSlot(QUrl, 'QAuthenticator*')
|
||||||
|
def _on_authentication_required(self, url, authenticator):
|
||||||
|
# FIXME:qtwebengine support .netrc
|
||||||
|
shared.authentication_required(url, authenticator,
|
||||||
|
abort_on=[self.shutting_down,
|
||||||
|
self.load_started])
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
view = self._widget
|
view = self._widget
|
||||||
page = view.page()
|
page = view.page()
|
||||||
@ -603,6 +611,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
page.loadFinished.connect(self._on_load_finished)
|
page.loadFinished.connect(self._on_load_finished)
|
||||||
page.certificate_error.connect(self._on_ssl_errors)
|
page.certificate_error.connect(self._on_ssl_errors)
|
||||||
page.link_clicked.connect(self._on_link_clicked)
|
page.link_clicked.connect(self._on_link_clicked)
|
||||||
|
page.authenticationRequired.connect(self._on_authentication_required)
|
||||||
try:
|
try:
|
||||||
view.iconChanged.connect(self.icon_changed)
|
view.iconChanged.connect(self.icon_changed)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -26,6 +26,7 @@ from PyQt5.QtCore import pyqtSignal, QUrl
|
|||||||
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
|
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.browser import shared
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import log, debug, usertypes, objreg, qtutils
|
from qutebrowser.utils import log, debug, usertypes, objreg, qtutils
|
||||||
|
|
||||||
@ -39,6 +40,9 @@ class WebEngineView(QWebEngineView):
|
|||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
self.setPage(WebEnginePage(tabdata, parent=self))
|
self.setPage(WebEnginePage(tabdata, parent=self))
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.page().shutdown()
|
||||||
|
|
||||||
def createWindow(self, wintype):
|
def createWindow(self, wintype):
|
||||||
"""Called by Qt when a page wants to create a new window.
|
"""Called by Qt when a page wants to create a new window.
|
||||||
|
|
||||||
@ -99,22 +103,65 @@ class WebEnginePage(QWebEnginePage):
|
|||||||
|
|
||||||
"""Custom QWebEnginePage subclass with qutebrowser-specific features.
|
"""Custom QWebEnginePage subclass with qutebrowser-specific features.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
_is_shutting_down: Whether the page is currently shutting down.
|
||||||
|
|
||||||
Signals:
|
Signals:
|
||||||
certificate_error: FIXME:qtwebengine
|
certificate_error: FIXME:qtwebengine
|
||||||
link_clicked: Emitted when a link was clicked on a page.
|
link_clicked: Emitted when a link was clicked on a page.
|
||||||
|
shutting_down: Emitted when the page is shutting down.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
certificate_error = pyqtSignal()
|
certificate_error = pyqtSignal()
|
||||||
link_clicked = pyqtSignal(QUrl)
|
link_clicked = pyqtSignal(QUrl)
|
||||||
|
shutting_down = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, tabdata, parent=None):
|
def __init__(self, tabdata, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._tabdata = tabdata
|
self._tabdata = tabdata
|
||||||
|
self._is_shutting_down = False
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self._is_shutting_down = True
|
||||||
|
self.shutting_down.emit()
|
||||||
|
|
||||||
def certificateError(self, error):
|
def certificateError(self, error):
|
||||||
self.certificate_error.emit()
|
self.certificate_error.emit()
|
||||||
return super().certificateError(error)
|
return super().certificateError(error)
|
||||||
|
|
||||||
|
def javaScriptConfirm(self, url, js_msg):
|
||||||
|
if self._is_shutting_down:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return shared.javascript_confirm(url, js_msg,
|
||||||
|
abort_on=[self.loadStarted,
|
||||||
|
self.shutting_down])
|
||||||
|
except shared.CallSuper:
|
||||||
|
return super().javaScriptConfirm(url, js_msg)
|
||||||
|
|
||||||
|
# Can't override javaScriptPrompt currently
|
||||||
|
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-November/038293.html
|
||||||
|
# def javaScriptPrompt(self, url, js_msg, default, result):
|
||||||
|
# if self._is_shutting_down:
|
||||||
|
# return (False, "")
|
||||||
|
# try:
|
||||||
|
# return shared.javascript_prompt(url, js_msg, default,
|
||||||
|
# abort_on=[self.loadStarted,
|
||||||
|
# self.shutting_down])
|
||||||
|
# except shared.CallSuper:
|
||||||
|
# return super().javaScriptPrompt(url, js_msg, default)
|
||||||
|
|
||||||
|
def javaScriptAlert(self, url, js_msg):
|
||||||
|
"""Override javaScriptAlert to use the statusbar."""
|
||||||
|
if self._is_shutting_down:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
shared.javascript_alert(url, js_msg,
|
||||||
|
abort_on=[self.loadStarted,
|
||||||
|
self.shutting_down])
|
||||||
|
except shared.CallSuper:
|
||||||
|
super().javaScriptAlert(url, js_msg)
|
||||||
|
|
||||||
def javaScriptConsoleMessage(self, level, msg, line, source):
|
def javaScriptConsoleMessage(self, level, msg, line, source):
|
||||||
"""Log javascript messages to qutebrowser's log."""
|
"""Log javascript messages to qutebrowser's log."""
|
||||||
# FIXME:qtwebengine maybe unify this in the tab api somehow?
|
# FIXME:qtwebengine maybe unify this in the tab api somehow?
|
||||||
|
@ -343,19 +343,18 @@ class NetworkManager(QNetworkAccessManager):
|
|||||||
except netrc.NetrcParseError:
|
except netrc.NetrcParseError:
|
||||||
log.misc.exception("Error when parsing the netrc file")
|
log.misc.exception("Error when parsing the netrc file")
|
||||||
|
|
||||||
if user is None:
|
|
||||||
# netrc check failed
|
|
||||||
msg = '<b>{}</b> says:<br/>{}'.format(
|
|
||||||
html.escape(reply.url().toDisplayString()),
|
|
||||||
html.escape(authenticator.realm()))
|
|
||||||
answer = self._ask("Authentication required",
|
|
||||||
text=msg, mode=usertypes.PromptMode.user_pwd,
|
|
||||||
owner=reply)
|
|
||||||
if answer is not None:
|
|
||||||
user, password = answer.user, answer.password
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
authenticator.setUser(user)
|
authenticator.setUser(user)
|
||||||
authenticator.setPassword(password)
|
authenticator.setPassword(password)
|
||||||
|
else:
|
||||||
|
abort_on = [self.shutting_down, reply.destroyed]
|
||||||
|
if self._tab_id is not None:
|
||||||
|
tab = objreg.get('tab', scope='tab', window=self._win_id,
|
||||||
|
tab=self._tab_id)
|
||||||
|
abort_on.append(tab.load_started)
|
||||||
|
|
||||||
|
shared.authentication_required(reply.url(), authenticator,
|
||||||
|
abort_on=abort_on)
|
||||||
|
|
||||||
@pyqtSlot('QNetworkProxy', 'QAuthenticator*')
|
@pyqtSlot('QNetworkProxy', 'QAuthenticator*')
|
||||||
def on_proxy_authentication_required(self, proxy, authenticator):
|
def on_proxy_authentication_required(self, proxy, authenticator):
|
||||||
|
@ -30,7 +30,7 @@ from PyQt5.QtPrintSupport import QPrintDialog
|
|||||||
from PyQt5.QtWebKitWidgets import QWebPage, QWebFrame
|
from PyQt5.QtWebKitWidgets import QWebPage, QWebFrame
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.browser import pdfjs
|
from qutebrowser.browser import pdfjs, shared
|
||||||
from qutebrowser.browser.webkit import http
|
from qutebrowser.browser.webkit import http
|
||||||
from qutebrowser.browser.webkit.network import networkmanager
|
from qutebrowser.browser.webkit.network import networkmanager
|
||||||
from qutebrowser.utils import (message, usertypes, log, jinja, qtutils, utils,
|
from qutebrowser.utils import (message, usertypes, log, jinja, qtutils, utils,
|
||||||
@ -94,23 +94,16 @@ class BrowserPage(QWebPage):
|
|||||||
# of a bug in PyQt.
|
# of a bug in PyQt.
|
||||||
# See http://www.riverbankcomputing.com/pipermail/pyqt/2014-June/034385.html
|
# See http://www.riverbankcomputing.com/pipermail/pyqt/2014-June/034385.html
|
||||||
|
|
||||||
def javaScriptPrompt(self, _frame, js_msg, default):
|
def javaScriptPrompt(self, frame, js_msg, default):
|
||||||
"""Override javaScriptPrompt to use the statusbar."""
|
"""Override javaScriptPrompt to use the statusbar."""
|
||||||
if (self._is_shutting_down or
|
if self._is_shutting_down:
|
||||||
config.get('content', 'ignore-javascript-prompt')):
|
|
||||||
return (False, "")
|
return (False, "")
|
||||||
msg = '<b>{}</b> asks:<br/>{}'.format(
|
try:
|
||||||
html.escape(self.mainFrame().url().toDisplayString()),
|
return shared.javascript_prompt(frame.url(), js_msg, default,
|
||||||
html.escape(js_msg))
|
abort_on=[self.loadStarted,
|
||||||
answer = message.ask('Javascript prompt', msg,
|
self.shutting_down])
|
||||||
mode=usertypes.PromptMode.text,
|
except shared.CallSuper:
|
||||||
default=default,
|
return super().javaScriptPrompt(frame, js_msg, default)
|
||||||
abort_on=[self.loadStarted,
|
|
||||||
self.shutting_down])
|
|
||||||
if answer is None:
|
|
||||||
return (False, "")
|
|
||||||
else:
|
|
||||||
return (True, answer)
|
|
||||||
|
|
||||||
def _handle_errorpage(self, info, errpage):
|
def _handle_errorpage(self, info, errpage):
|
||||||
"""Display an error page if needed.
|
"""Display an error page if needed.
|
||||||
@ -442,36 +435,25 @@ class BrowserPage(QWebPage):
|
|||||||
|
|
||||||
def javaScriptAlert(self, frame, js_msg):
|
def javaScriptAlert(self, frame, js_msg):
|
||||||
"""Override javaScriptAlert to use the statusbar."""
|
"""Override javaScriptAlert to use the statusbar."""
|
||||||
log.js.debug("alert: {}".format(js_msg))
|
if self._is_shutting_down:
|
||||||
if config.get('ui', 'modal-js-dialog'):
|
|
||||||
return super().javaScriptAlert(frame, js_msg)
|
|
||||||
|
|
||||||
if (self._is_shutting_down or
|
|
||||||
config.get('content', 'ignore-javascript-alert')):
|
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
msg = 'From <b>{}</b>:<br/>{}'.format(
|
shared.javascript_alert(frame.url(), js_msg,
|
||||||
html.escape(self.mainFrame().url().toDisplayString()),
|
abort_on=[self.loadStarted,
|
||||||
html.escape(js_msg))
|
self.shutting_down])
|
||||||
message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert,
|
except shared.CallSuper:
|
||||||
abort_on=[self.loadStarted, self.shutting_down])
|
super().javaScriptAlert(frame, js_msg)
|
||||||
|
|
||||||
def javaScriptConfirm(self, frame, js_msg):
|
def javaScriptConfirm(self, frame, js_msg):
|
||||||
"""Override javaScriptConfirm to use the statusbar."""
|
"""Override javaScriptConfirm to use the statusbar."""
|
||||||
log.js.debug("confirm: {}".format(js_msg))
|
|
||||||
if config.get('ui', 'modal-js-dialog'):
|
|
||||||
return super().javaScriptConfirm(frame, js_msg)
|
|
||||||
|
|
||||||
if self._is_shutting_down:
|
if self._is_shutting_down:
|
||||||
return False
|
return False
|
||||||
|
try:
|
||||||
msg = 'From <b>{}</b>:<br/>{}'.format(
|
return shared.javascript_confirm(frame.url(), js_msg,
|
||||||
html.escape(self.mainFrame().url().toDisplayString()),
|
abort_on=[self.loadStarted,
|
||||||
html.escape(js_msg))
|
self.shutting_down])
|
||||||
ans = message.ask('Javascript confirm', msg,
|
except shared.CallSuper:
|
||||||
mode=usertypes.PromptMode.yesno,
|
return super().javaScriptConfirm(frame, js_msg)
|
||||||
abort_on=[self.loadStarted, self.shutting_down])
|
|
||||||
return bool(ans)
|
|
||||||
|
|
||||||
def javaScriptConsoleMessage(self, msg, line, source):
|
def javaScriptConsoleMessage(self, msg, line, source):
|
||||||
"""Override javaScriptConsoleMessage to use debug log."""
|
"""Override javaScriptConsoleMessage to use debug log."""
|
||||||
|
@ -40,7 +40,7 @@ Feature: Prompts
|
|||||||
And I run :leave-mode
|
And I run :leave-mode
|
||||||
Then the javascript message "confirm reply: false" should be logged
|
Then the javascript message "confirm reply: false" should be logged
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Javascript prompt
|
Scenario: Javascript prompt
|
||||||
When I open data/prompt/jsprompt.html
|
When I open data/prompt/jsprompt.html
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
@ -49,7 +49,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
Then the javascript message "Prompt reply: prompt test" should be logged
|
Then the javascript message "Prompt reply: prompt test" should be logged
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Javascript prompt with default
|
Scenario: Javascript prompt with default
|
||||||
When I open data/prompt/jsprompt.html
|
When I open data/prompt/jsprompt.html
|
||||||
And I run :click-element id button-default
|
And I run :click-element id button-default
|
||||||
@ -57,7 +57,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
Then the javascript message "Prompt reply: default" should be logged
|
Then the javascript message "Prompt reply: default" should be logged
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Rejected javascript prompt
|
Scenario: Rejected javascript prompt
|
||||||
When I open data/prompt/jsprompt.html
|
When I open data/prompt/jsprompt.html
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
@ -68,6 +68,7 @@ Feature: Prompts
|
|||||||
|
|
||||||
# Multiple prompts
|
# Multiple prompts
|
||||||
|
|
||||||
|
@qtwebengine_skip: QtWebEngine refuses to load anything with a JS question
|
||||||
Scenario: Blocking question interrupted by blocking one
|
Scenario: Blocking question interrupted by blocking one
|
||||||
When I set content -> ignore-javascript-alert to false
|
When I set content -> ignore-javascript-alert to false
|
||||||
And I open data/prompt/jsalert.html
|
And I open data/prompt/jsalert.html
|
||||||
@ -83,6 +84,7 @@ Feature: Prompts
|
|||||||
Then the javascript message "confirm reply: true" should be logged
|
Then the javascript message "confirm reply: true" should be logged
|
||||||
And the javascript message "Alert done" should be logged
|
And the javascript message "Alert done" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_skip: QtWebEngine refuses to load anything with a JS question
|
||||||
Scenario: Blocking question interrupted by async one
|
Scenario: Blocking question interrupted by async one
|
||||||
When I set content -> ignore-javascript-alert to false
|
When I set content -> ignore-javascript-alert to false
|
||||||
And I set content -> notifications to ask
|
And I set content -> notifications to ask
|
||||||
@ -99,6 +101,7 @@ Feature: Prompts
|
|||||||
Then the javascript message "Alert done" should be logged
|
Then the javascript message "Alert done" should be logged
|
||||||
And the javascript message "notification permission granted" should be logged
|
And the javascript message "notification permission granted" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Async question interrupted by async one
|
Scenario: Async question interrupted by async one
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
@ -113,6 +116,7 @@ Feature: Prompts
|
|||||||
Then the javascript message "notification permission granted" should be logged
|
Then the javascript message "notification permission granted" should be logged
|
||||||
And "Added quickmark test for *" should be logged
|
And "Added quickmark test for *" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Async question interrupted by blocking one
|
Scenario: Async question interrupted by blocking one
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I set content -> ignore-javascript-alert to false
|
And I set content -> ignore-javascript-alert to false
|
||||||
@ -131,7 +135,7 @@ Feature: Prompts
|
|||||||
|
|
||||||
# Shift-Insert with prompt (issue 1299)
|
# Shift-Insert with prompt (issue 1299)
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Pasting via shift-insert in prompt mode
|
Scenario: Pasting via shift-insert in prompt mode
|
||||||
When selection is supported
|
When selection is supported
|
||||||
And I put "insert test" into the primary selection
|
And I put "insert test" into the primary selection
|
||||||
@ -142,7 +146,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
Then the javascript message "Prompt reply: insert test" should be logged
|
Then the javascript message "Prompt reply: insert test" should be logged
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Pasting via shift-insert without it being supported
|
Scenario: Pasting via shift-insert without it being supported
|
||||||
When selection is not supported
|
When selection is not supported
|
||||||
And I put "insert test" into the primary selection
|
And I put "insert test" into the primary selection
|
||||||
@ -153,7 +157,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
Then the javascript message "Prompt reply: " should be logged
|
Then the javascript message "Prompt reply: " should be logged
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Using content -> ignore-javascript-prompt
|
Scenario: Using content -> ignore-javascript-prompt
|
||||||
When I set content -> ignore-javascript-prompt to true
|
When I set content -> ignore-javascript-prompt to true
|
||||||
And I open data/prompt/jsprompt.html
|
And I open data/prompt/jsprompt.html
|
||||||
@ -162,6 +166,7 @@ Feature: Prompts
|
|||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
|
|
||||||
|
@qtwebengine_todo: SSL errors are not implemented yet
|
||||||
Scenario: SSL error with ssl-strict = false
|
Scenario: SSL error with ssl-strict = false
|
||||||
When I run :debug-clear-ssl-errors
|
When I run :debug-clear-ssl-errors
|
||||||
And I set network -> ssl-strict to false
|
And I set network -> ssl-strict to false
|
||||||
@ -170,6 +175,7 @@ Feature: Prompts
|
|||||||
Then the error "SSL error: *" should be shown
|
Then the error "SSL error: *" should be shown
|
||||||
And the page should contain the plaintext "Hello World via SSL!"
|
And the page should contain the plaintext "Hello World via SSL!"
|
||||||
|
|
||||||
|
@qtwebengine_todo: SSL errors are not implemented yet
|
||||||
Scenario: SSL error with ssl-strict = true
|
Scenario: SSL error with ssl-strict = true
|
||||||
When I run :debug-clear-ssl-errors
|
When I run :debug-clear-ssl-errors
|
||||||
And I set network -> ssl-strict to true
|
And I set network -> ssl-strict to true
|
||||||
@ -177,6 +183,7 @@ Feature: Prompts
|
|||||||
Then "Error while loading *: SSL handshake failed" should be logged
|
Then "Error while loading *: SSL handshake failed" should be logged
|
||||||
And the page should contain the plaintext "Unable to load page"
|
And the page should contain the plaintext "Unable to load page"
|
||||||
|
|
||||||
|
@qtwebengine_todo: SSL errors are not implemented yet
|
||||||
Scenario: SSL error with ssl-strict = ask -> yes
|
Scenario: SSL error with ssl-strict = ask -> yes
|
||||||
When I run :debug-clear-ssl-errors
|
When I run :debug-clear-ssl-errors
|
||||||
And I set network -> ssl-strict to ask
|
And I set network -> ssl-strict to ask
|
||||||
@ -186,6 +193,7 @@ Feature: Prompts
|
|||||||
And I wait until the SSL page finished loading
|
And I wait until the SSL page finished loading
|
||||||
Then the page should contain the plaintext "Hello World via SSL!"
|
Then the page should contain the plaintext "Hello World via SSL!"
|
||||||
|
|
||||||
|
@qtwebengine_todo: SSL errors are not implemented yet
|
||||||
Scenario: SSL error with ssl-strict = ask -> no
|
Scenario: SSL error with ssl-strict = ask -> no
|
||||||
When I run :debug-clear-ssl-errors
|
When I run :debug-clear-ssl-errors
|
||||||
And I set network -> ssl-strict to ask
|
And I set network -> ssl-strict to ask
|
||||||
@ -197,20 +205,21 @@ Feature: Prompts
|
|||||||
|
|
||||||
# Geolocation
|
# Geolocation
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Always rejecting geolocation
|
Scenario: Always rejecting geolocation
|
||||||
When I set content -> geolocation to false
|
When I set content -> geolocation to false
|
||||||
And I open data/prompt/geolocation.html in a new tab
|
And I open data/prompt/geolocation.html in a new tab
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
Then the javascript message "geolocation permission denied" should be logged
|
Then the javascript message "geolocation permission denied" should be logged
|
||||||
|
|
||||||
@ci @not_osx
|
@ci @not_osx @qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Always accepting geolocation
|
Scenario: Always accepting geolocation
|
||||||
When I set content -> geolocation to true
|
When I set content -> geolocation to true
|
||||||
And I open data/prompt/geolocation.html in a new tab
|
And I open data/prompt/geolocation.html in a new tab
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
Then the javascript message "geolocation permission denied" should not be logged
|
Then the javascript message "geolocation permission denied" should not be logged
|
||||||
|
|
||||||
@ci @not_osx
|
@ci @not_osx @qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: geolocation with ask -> true
|
Scenario: geolocation with ask -> true
|
||||||
When I set content -> geolocation to ask
|
When I set content -> geolocation to ask
|
||||||
And I open data/prompt/geolocation.html in a new tab
|
And I open data/prompt/geolocation.html in a new tab
|
||||||
@ -219,6 +228,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept yes
|
And I run :prompt-accept yes
|
||||||
Then the javascript message "geolocation permission denied" should not be logged
|
Then the javascript message "geolocation permission denied" should not be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: geolocation with ask -> false
|
Scenario: geolocation with ask -> false
|
||||||
When I set content -> geolocation to ask
|
When I set content -> geolocation to ask
|
||||||
And I open data/prompt/geolocation.html in a new tab
|
And I open data/prompt/geolocation.html in a new tab
|
||||||
@ -227,6 +237,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept no
|
And I run :prompt-accept no
|
||||||
Then the javascript message "geolocation permission denied" should be logged
|
Then the javascript message "geolocation permission denied" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: geolocation with ask -> abort
|
Scenario: geolocation with ask -> abort
|
||||||
When I set content -> geolocation to ask
|
When I set content -> geolocation to ask
|
||||||
And I open data/prompt/geolocation.html in a new tab
|
And I open data/prompt/geolocation.html in a new tab
|
||||||
@ -237,18 +248,21 @@ Feature: Prompts
|
|||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Always rejecting notifications
|
Scenario: Always rejecting notifications
|
||||||
When I set content -> notifications to false
|
When I set content -> notifications to false
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
Then the javascript message "notification permission denied" should be logged
|
Then the javascript message "notification permission denied" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: Always accepting notifications
|
Scenario: Always accepting notifications
|
||||||
When I set content -> notifications to true
|
When I set content -> notifications to true
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
Then the javascript message "notification permission granted" should be logged
|
Then the javascript message "notification permission granted" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: notifications with ask -> false
|
Scenario: notifications with ask -> false
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
@ -257,6 +271,7 @@ Feature: Prompts
|
|||||||
And I run :prompt-accept no
|
And I run :prompt-accept no
|
||||||
Then the javascript message "notification permission denied" should be logged
|
Then the javascript message "notification permission denied" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: notifications with ask -> true
|
Scenario: notifications with ask -> true
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
@ -275,6 +290,7 @@ Feature: Prompts
|
|||||||
And I run :leave-mode
|
And I run :leave-mode
|
||||||
Then the javascript message "notification permission aborted" should be logged
|
Then the javascript message "notification permission aborted" should be logged
|
||||||
|
|
||||||
|
@qtwebengine_todo: Permissions are not implemented yet
|
||||||
Scenario: answering notification after closing tab
|
Scenario: answering notification after closing tab
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I open data/prompt/notifications.html in a new tab
|
And I open data/prompt/notifications.html in a new tab
|
||||||
@ -287,55 +303,55 @@ Feature: Prompts
|
|||||||
# Page authentication
|
# Page authentication
|
||||||
|
|
||||||
Scenario: Successful webpage authentification
|
Scenario: Successful webpage authentification
|
||||||
When I open basic-auth/user/password without waiting
|
When I open basic-auth/user1/password1 without waiting
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
And I press the keys "user"
|
And I press the keys "user1"
|
||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
And I press the keys "password"
|
And I press the keys "password1"
|
||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
And I wait until basic-auth/user/password is loaded
|
And I wait until basic-auth/user1/password1 is loaded
|
||||||
Then the json on the page should be:
|
Then the json on the page should be:
|
||||||
{
|
{
|
||||||
"authenticated": true,
|
"authenticated": true,
|
||||||
"user": "user"
|
"user": "user1"
|
||||||
}
|
}
|
||||||
|
|
||||||
Scenario: Authentication with :prompt-accept value
|
Scenario: Authentication with :prompt-accept value
|
||||||
When I open about:blank in a new tab
|
When I open about:blank in a new tab
|
||||||
And I open basic-auth/user/password without waiting
|
And I open basic-auth/user2/password2 without waiting
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
And I run :prompt-accept user:password
|
And I run :prompt-accept user2:password2
|
||||||
And I wait until basic-auth/user/password is loaded
|
And I wait until basic-auth/user2/password2 is loaded
|
||||||
Then the json on the page should be:
|
Then the json on the page should be:
|
||||||
{
|
{
|
||||||
"authenticated": true,
|
"authenticated": true,
|
||||||
"user": "user"
|
"user": "user2"
|
||||||
}
|
}
|
||||||
|
|
||||||
Scenario: Authentication with invalid :prompt-accept value
|
Scenario: Authentication with invalid :prompt-accept value
|
||||||
When I open about:blank in a new tab
|
When I open about:blank in a new tab
|
||||||
And I open basic-auth/user/password without waiting
|
And I open basic-auth/user3/password3 without waiting
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
And I run :prompt-accept foo
|
And I run :prompt-accept foo
|
||||||
And I run :prompt-accept user:password
|
And I run :prompt-accept user3:password3
|
||||||
Then the error "Value needs to be in the format username:password, but foo was given" should be shown
|
Then the error "Value needs to be in the format username:password, but foo was given" should be shown
|
||||||
|
|
||||||
Scenario: Tabbing between username and password
|
Scenario: Tabbing between username and password
|
||||||
When I open about:blank in a new tab
|
When I open about:blank in a new tab
|
||||||
And I open basic-auth/user/password without waiting
|
And I open basic-auth/user4/password4 without waiting
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
And I press the keys "us"
|
And I press the keys "us"
|
||||||
And I run :prompt-item-focus next
|
And I run :prompt-item-focus next
|
||||||
And I press the keys "password"
|
And I press the keys "password4"
|
||||||
And I run :prompt-item-focus prev
|
And I run :prompt-item-focus prev
|
||||||
And I press the keys "er"
|
And I press the keys "er4"
|
||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
And I run :prompt-accept
|
And I run :prompt-accept
|
||||||
And I wait until basic-auth/user/password is loaded
|
And I wait until basic-auth/user4/password4 is loaded
|
||||||
Then the json on the page should be:
|
Then the json on the page should be:
|
||||||
{
|
{
|
||||||
"authenticated": true,
|
"authenticated": true,
|
||||||
"user": "user"
|
"user": "user4"
|
||||||
}
|
}
|
||||||
|
|
||||||
# :prompt-accept with value argument
|
# :prompt-accept with value argument
|
||||||
@ -350,7 +366,7 @@ Feature: Prompts
|
|||||||
Then the javascript message "Alert done" should be logged
|
Then the javascript message "Alert done" should be logged
|
||||||
And the error "No value is permitted with alert prompts!" should be shown
|
And the error "No value is permitted with alert prompts!" should be shown
|
||||||
|
|
||||||
@pyqt>=5.3.1
|
@pyqt>=5.3.1 @qtwebengine_skip
|
||||||
Scenario: Javascript prompt with value
|
Scenario: Javascript prompt with value
|
||||||
When I set content -> ignore-javascript-prompt to false
|
When I set content -> ignore-javascript-prompt to false
|
||||||
And I open data/prompt/jsprompt.html
|
And I open data/prompt/jsprompt.html
|
||||||
@ -396,6 +412,7 @@ Feature: Prompts
|
|||||||
|
|
||||||
# Other
|
# Other
|
||||||
|
|
||||||
|
@qtwebengine_skip
|
||||||
Scenario: Shutting down with a question
|
Scenario: Shutting down with a question
|
||||||
When I open data/prompt/jsconfirm.html
|
When I open data/prompt/jsconfirm.html
|
||||||
And I run :click-element id button
|
And I run :click-element id button
|
||||||
@ -429,32 +446,34 @@ Feature: Prompts
|
|||||||
Then "Added quickmark prompt-in-command-mode for *" should be logged
|
Then "Added quickmark prompt-in-command-mode for *" should be logged
|
||||||
|
|
||||||
# https://github.com/The-Compiler/qutebrowser/issues/1093
|
# https://github.com/The-Compiler/qutebrowser/issues/1093
|
||||||
|
@qtwebengine_skip: QtWebEngine doesn't open the second page/prompt
|
||||||
Scenario: Keyboard focus with multiple auth prompts
|
Scenario: Keyboard focus with multiple auth prompts
|
||||||
When I open basic-auth/user1/password1 without waiting
|
When I open basic-auth/user5/password5 without waiting
|
||||||
And I open basic-auth/user2/password2 in a new tab without waiting
|
And I open basic-auth/user6/password6 in a new tab without waiting
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
And I wait for a prompt
|
And I wait for a prompt
|
||||||
# Second prompt (showed first)
|
# Second prompt (showed first)
|
||||||
And I press the keys "user2"
|
And I press the keys "user6"
|
||||||
And I press the key "<Enter>"
|
And I press the key "<Enter>"
|
||||||
And I press the keys "password2"
|
And I press the keys "password6"
|
||||||
And I press the key "<Enter>"
|
And I press the key "<Enter>"
|
||||||
And I wait until basic-auth/user2/password2 is loaded
|
And I wait until basic-auth/user6/password6 is loaded
|
||||||
# First prompt
|
# First prompt
|
||||||
And I press the keys "user1"
|
And I press the keys "user5"
|
||||||
And I press the key "<Enter>"
|
And I press the key "<Enter>"
|
||||||
And I press the keys "password1"
|
And I press the keys "password5"
|
||||||
And I press the key "<Enter>"
|
And I press the key "<Enter>"
|
||||||
And I wait until basic-auth/user1/password1 is loaded
|
And I wait until basic-auth/user5/password5 is loaded
|
||||||
# We're on the second page
|
# We're on the second page
|
||||||
Then the json on the page should be:
|
Then the json on the page should be:
|
||||||
{
|
{
|
||||||
"authenticated": true,
|
"authenticated": true,
|
||||||
"user": "user2"
|
"user": "user6"
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://github.com/The-Compiler/qutebrowser/issues/1249#issuecomment-175205531
|
# https://github.com/The-Compiler/qutebrowser/issues/1249#issuecomment-175205531
|
||||||
# https://github.com/The-Compiler/qutebrowser/pull/2054#issuecomment-258285544
|
# https://github.com/The-Compiler/qutebrowser/pull/2054#issuecomment-258285544
|
||||||
|
@qtwebengine_todo: SSL errors are not implemented yet
|
||||||
Scenario: Interrupting SSL prompt during a notification prompt
|
Scenario: Interrupting SSL prompt during a notification prompt
|
||||||
When I set content -> notifications to ask
|
When I set content -> notifications to ask
|
||||||
And I set network -> ssl-strict to ask
|
And I set network -> ssl-strict to ask
|
||||||
|
@ -22,9 +22,6 @@ import pytest_bdd as bdd
|
|||||||
bdd.scenarios('prompts.feature')
|
bdd.scenarios('prompts.feature')
|
||||||
|
|
||||||
|
|
||||||
pytestmark = pytest.mark.qtwebengine_todo("Prompts are not implemented")
|
|
||||||
|
|
||||||
|
|
||||||
@bdd.when("I load an SSL page")
|
@bdd.when("I load an SSL page")
|
||||||
def load_ssl_page(quteproc, ssl_server):
|
def load_ssl_page(quteproc, ssl_server):
|
||||||
# We don't wait here as we can get an SSL question.
|
# We don't wait here as we can get an SSL question.
|
||||||
|
@ -81,7 +81,7 @@ class Request(testprocess.Line):
|
|||||||
http.client.FOUND]
|
http.client.FOUND]
|
||||||
path_to_statuses['/absolute-redirect/{}'.format(i)] = [
|
path_to_statuses['/absolute-redirect/{}'.format(i)] = [
|
||||||
http.client.FOUND]
|
http.client.FOUND]
|
||||||
for suffix in ['', '1', '2']:
|
for suffix in ['', '1', '2', '3', '4', '5', '6']:
|
||||||
key = '/basic-auth/user{}/password{}'.format(suffix, suffix)
|
key = '/basic-auth/user{}/password{}'.format(suffix, suffix)
|
||||||
path_to_statuses[key] = [http.client.UNAUTHORIZED, http.client.OK]
|
path_to_statuses[key] = [http.client.UNAUTHORIZED, http.client.OK]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user