Merge remote-tracking branch 'origin/pr/3333'
This commit is contained in:
commit
003ec31848
@ -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)
|
||||||
|
@ -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))
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user