Fix #1834 - Throw an error if more than a terminal exists (#1837)

This commit is contained in:
Andrea Giammarchi
2023-11-03 15:19:30 +01:00
committed by GitHub
parent c8ec29a3d8
commit aef028be6e
4 changed files with 71 additions and 12 deletions

View File

@@ -1,27 +1,35 @@
// PyScript py-terminal plugin
import { TYPES, hooks } from "../core.js";
import { notify } from "./error.js";
const SELECTOR = [...TYPES.keys()]
.map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`)
.join(",");
// show the error on main and
// stops the module from keep executing
const notifyAndThrow = (message) => {
notify(message);
throw new Error(message);
};
const pyTerminal = async () => {
const terminals = document.querySelectorAll(SELECTOR);
// no results will look further for runtime nodes
if (!terminals.length) return;
// we currently support only one terminal as in "classic"
if (terminals.length > 1)
console.warn("Unable to satisfy multiple terminals");
// if we arrived this far, let's drop the MutationObserver
// as we only support one terminal per page (right now).
mo.disconnect();
// we currently support only one terminal as in "classic"
if (terminals.length > 1) notifyAndThrow("You can use at most 1 terminal.");
const [element] = terminals;
// hopefully to be removed in the near future!
if (element.matches('script[type="mpy"],mpy-script'))
throw new Error("Unsupported terminal");
notifyAndThrow("Unsupported terminal.");
// import styles lazily
document.head.append(

View File

@@ -118,6 +118,20 @@ def only_main(fn):
return decorated
def only_worker(fn):
"""
Decorator to mark a test which make sense only in the worker thread
"""
@functools.wraps(fn)
def decorated(self, *args):
if self.execution_thread != "worker":
return
return fn(self, *args)
return decorated
def filter_inner_text(text, exclude=None):
return "\n".join(filter_page_content(text.splitlines(), exclude=exclude))

View File

@@ -80,7 +80,7 @@ class TestBasic(PyScriptTest):
'"Cross-Origin-Opener-Policy":"same-origin"}. '
"The problem may be that one or both of these are missing."
)
alert_banner = self.page.wait_for_selector(".alert-banner")
alert_banner = self.page.wait_for_selector(".py-error")
assert expected_alert_banner_msg in alert_banner.inner_text()
def test_print(self):

View File

@@ -1,12 +1,45 @@
import time
import pytest
from playwright.sync_api import expect
from .support import PyScriptTest, skip_worker
from .support import PageErrors, PyScriptTest, only_worker, skip_worker
class TestPyTerminal(PyScriptTest):
@skip_worker("FIXME: the auto worker dance removes terminal")
def test_multiple_terminals(self):
"""
Multiple terminals are not currently supported
"""
self.pyscript_run(
"""
<script type="py" terminal></script>
<script type="py" terminal></script>
""",
wait_for_pyscript=False,
check_js_errors=False,
)
assert self.assert_banner_message("You can use at most 1 terminal")
with pytest.raises(PageErrors, match="You can use at most 1 terminal"):
self.check_js_errors()
@only_worker
def test_py_terminal_input(self):
"""
Only worker py-terminal accepts an input
"""
self.pyscript_run(
"""
<script type="py" terminal></script>
""",
wait_for_pyscript=False,
)
self.page.get_by_text(">>> ", exact=True).wait_for()
self.page.keyboard.type("'the answer is ' + str(6 * 7)")
self.page.keyboard.press("Enter")
self.page.get_by_text("the answer is 42").wait_for()
def test_py_terminal(self):
"""
1. <py-terminal> should redirect stdout and stderr to the DOM
@@ -21,8 +54,10 @@ class TestPyTerminal(PyScriptTest):
print('this goes to stderr', file=sys.stderr)
print('this goes to stdout')
</script>
"""
""",
wait_for_pyscript=False,
)
self.page.get_by_text("hello world").wait_for()
term = self.page.locator("py-terminal")
term_lines = term.inner_text().splitlines()
assert term_lines[0:3] == [
@@ -31,7 +66,9 @@ class TestPyTerminal(PyScriptTest):
"this goes to stdout",
]
@skip_worker("FIXME: the auto worker dance removes terminal")
@skip_worker(
"Workers don't have events + two different workers don't share the same I/O"
)
def test_button_action(self):
self.pyscript_run(
"""
@@ -50,7 +87,6 @@ class TestPyTerminal(PyScriptTest):
last_line.wait_for()
assert term.inner_text().rstrip() == "hello world"
@skip_worker("FIXME: the auto worker dance removes terminal")
def test_xterm_function(self):
"""Test a few basic behaviors of the xtermjs terminal.
@@ -69,7 +105,8 @@ class TestPyTerminal(PyScriptTest):
print("\x1b[3mItalic\x1b[23m")
print("done")
</script>
"""
""",
wait_for_pyscript=False,
)
# Wait for "done" to actually appear in the xterm; may be delayed,