Merge remote-tracking branch 'origin/pr/3333'

This commit is contained in:
Florian Bruhin 2017-12-02 14:47:24 +01:00
commit 003ec31848
8 changed files with 68 additions and 2 deletions

View File

@ -22,6 +22,7 @@
import enum import enum
import itertools import itertools
import sip
import attr import attr
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
@ -864,3 +865,6 @@ class AbstractTab(QWidget):
except (AttributeError, RuntimeError) as exc: except (AttributeError, RuntimeError) as exc:
url = '<{}>'.format(exc.__class__.__name__) url = '<{}>'.format(exc.__class__.__name__)
return utils.get_repr(self, tab_id=self.tab_id, url=url) return utils.get_repr(self, tab_id=self.tab_id, url=url)
def is_deleted(self):
return sip.isdeleted(self._widget)

View File

@ -1644,6 +1644,8 @@ class CommandDispatcher:
""" """
try: try:
elem.set_value(text) elem.set_value(text)
except webelem.OrphanedError as e:
message.warning('Edited element vanished')
except webelem.Error as e: except webelem.Error as e:
raise cmdexc.CommandError(str(e)) raise cmdexc.CommandError(str(e))

View File

@ -60,6 +60,13 @@ class Error(Exception):
pass pass
class OrphanedError(Exception):
"""Raised when a webelement's parent has vanished."""
pass
class AbstractWebElement(collections.abc.MutableMapping): class AbstractWebElement(collections.abc.MutableMapping):
"""A wrapper around QtWebKit/QtWebEngine web element. """A wrapper around QtWebKit/QtWebEngine web element.

View File

@ -100,6 +100,8 @@ class WebEngineElement(webelem.AbstractWebElement):
def _js_call(self, name, *args, callback=None): def _js_call(self, name, *args, callback=None):
"""Wrapper to run stuff from webelem.js.""" """Wrapper to run stuff from webelem.js."""
if self._tab.is_deleted():
raise webelem.OrphanedError("Tab containing element vanished")
js_code = javascript.assemble('webelem', name, self._id, *args) js_code = javascript.assemble('webelem', name, self._id, *args)
self._tab.run_js_async(js_code, callback=callback) self._tab.run_js_async(js_code, callback=callback)

View File

@ -118,6 +118,8 @@ class WebKitElement(webelem.AbstractWebElement):
def set_value(self, value): def set_value(self, value):
self._check_vanished() self._check_vanished()
if self._tab.is_deleted():
raise webelem.OrphanedError("Tab containing element vanished")
if self.is_content_editable(): if self.is_content_editable():
log.webelem.debug("Filling {!r} via set_text.".format(self)) log.webelem.debug("Filling {!r} via set_text.".format(self))
self._elem.setPlainText(value) self._elem.setPlainText(value)

View File

@ -115,6 +115,19 @@ Feature: Opening external editors
And I run :click-element id qute-button And I run :click-element id qute-button
Then the javascript message "text: foobar" should be logged Then the javascript message "text: foobar" should be logged
# Could not get signals working on Windows
@posix
Scenario: Spawning an editor and closing the tab
When I set up a fake editor that waits
And I open data/editor.html
And I run :click-element id qute-textarea
And I wait for "Entering mode KeyMode.insert (reason: clicking input)" in the log
And I run :open-editor
And I set tabs.last_close to blank
And I run :tab-close
And I kill the waiting editor
Then the warning "Edited element vanished" should be shown
@qtwebengine_todo: Caret mode is not implemented yet @qtwebengine_todo: Caret mode is not implemented yet
Scenario: Spawning an editor in caret mode Scenario: Spawning an editor in caret mode
When I set up a fake editor returning "foobar" When I set up a fake editor returning "foobar"

View File

@ -20,6 +20,8 @@
import sys import sys
import json import json
import textwrap import textwrap
import os
import signal
import pytest_bdd as bdd import pytest_bdd as bdd
bdd.scenarios('editor.feature') bdd.scenarios('editor.feature')
@ -64,3 +66,35 @@ def set_up_editor(quteproc, server, tmpdir, text):
def set_up_editor_empty(quteproc, server, tmpdir): def set_up_editor_empty(quteproc, server, tmpdir):
"""Set up editor.command to a small python script inserting empty text.""" """Set up editor.command to a small python script inserting empty text."""
set_up_editor(quteproc, server, tmpdir, "") set_up_editor(quteproc, server, tmpdir, "")
@bdd.when(bdd.parsers.parse('I set up a fake editor that waits'))
def set_up_editor_wait(quteproc, server, tmpdir):
"""Set up editor.command to a small python script inserting a text."""
pidfile = tmpdir / 'editor_pid'
script = tmpdir / 'script.py'
script.write(textwrap.dedent("""
import os
import sys
import time
import signal
with open(r'{pidfile}', 'w') as f:
f.write(str(os.getpid()))
signal.signal(signal.SIGUSR1, lambda s, f: sys.exit(0))
time.sleep(100)
""".format(pidfile=pidfile)))
editor = json.dumps([sys.executable, str(script), '{}'])
quteproc.set_setting('editor.command', editor)
@bdd.when(bdd.parsers.parse('I kill the waiting editor'))
def kill_editor_wait(quteproc, server, tmpdir):
"""Kill the waiting editor."""
pidfile = tmpdir / 'editor_pid'
pid = int(pidfile.read())
# windows has no SIGUSR1, but we don't run this on windows anyways
# for posix, there IS a member so we need to ignore useless-suppression
# pylint: disable=no-member,useless-suppression
os.kill(pid, signal.SIGUSR1)

View File

@ -29,7 +29,7 @@ import pytest
from PyQt5.QtCore import QRect, QPoint, QUrl from PyQt5.QtCore import QRect, QPoint, QUrl
QWebElement = pytest.importorskip('PyQt5.QtWebKit').QWebElement QWebElement = pytest.importorskip('PyQt5.QtWebKit').QWebElement
from qutebrowser.browser import webelem from qutebrowser.browser import webelem, browsertab
from qutebrowser.browser.webkit import webkitelem from qutebrowser.browser.webkit import webkitelem
from qutebrowser.misc import objects from qutebrowser.misc import objects
from qutebrowser.utils import usertypes from qutebrowser.utils import usertypes
@ -127,7 +127,9 @@ def get_webelem(geometry=None, frame=None, *, null=False, style=None,
return style_dict[name] return style_dict[name]
elem.styleProperty.side_effect = _style_property elem.styleProperty.side_effect = _style_property
wrapped = webkitelem.WebKitElement(elem, tab=None) tab = mock.Mock(autospec=browsertab.AbstractTab)
tab.is_deleted.return_value = False
wrapped = webkitelem.WebKitElement(elem, tab=tab)
return wrapped return wrapped