mirror of
https://github.com/pyscript/pyscript.git
synced 2026-04-28 11:00:24 -04:00
Don't create custom elements in main and fix various small issues on tests (#747)
* Create custom elements when the runtime finishes loading * Remove xfails and fix repl integration test * Fix commented ignore * Address Antonio's comments * Fix bad rebase * Make ure to wait for repl to be in attached state before asserting content * Move createCustomeElement up so it runs before we close the loader, xfail flaky d3 test * Fix xfail
This commit is contained in:
35
pyscriptjs/src/components/elements.ts
Normal file
35
pyscriptjs/src/components/elements.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { PyRepl } from './pyrepl';
|
||||
import { PyBox } from './pybox';
|
||||
import { PyButton } from './pybutton';
|
||||
import { PyTitle } from './pytitle';
|
||||
import { PyInputBox } from './pyinputbox';
|
||||
import { PyWidget } from './base';
|
||||
|
||||
/*
|
||||
These were taken from main.js because some of our components call
|
||||
runAfterRuntimeInitialized immediately when we are creating the custom
|
||||
element, this was causing tests to fail since runAfterRuntimeInitialized
|
||||
expects the runtime to have been loaded before being called.
|
||||
|
||||
This function is now called from within the `runtime.initialize`. Once
|
||||
the runtime finished initializing, then we will create the custom elements
|
||||
so they are rendered in the page and we will always have a runtime available.
|
||||
|
||||
Ideally, this would live under utils.js, but importing all the components in
|
||||
the utils.js file was causing jest to fail with weird errors such as:
|
||||
"ReferenceError: Cannot access 'BaseEvalElement' before initialization" coming
|
||||
from the PyScript class.
|
||||
|
||||
*/
|
||||
function createCustomElements() {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const xPyRepl = customElements.define('py-repl', PyRepl);
|
||||
const xPyBox = customElements.define('py-box', PyBox);
|
||||
const xPyTitle = customElements.define('py-title', PyTitle);
|
||||
const xPyWidget = customElements.define('py-register-widget', PyWidget);
|
||||
const xPyInputBox = customElements.define('py-inputbox', PyInputBox);
|
||||
const xPyButton = customElements.define('py-button', PyButton);
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
}
|
||||
|
||||
export { createCustomElements };
|
||||
@@ -1,32 +1,20 @@
|
||||
import './styles/pyscript_base.css';
|
||||
|
||||
import { PyScript } from './components/pyscript';
|
||||
import { PyRepl } from './components/pyrepl';
|
||||
import { PyEnv } from './components/pyenv';
|
||||
import { PyBox } from './components/pybox';
|
||||
import { PyButton } from './components/pybutton';
|
||||
import { PyTitle } from './components/pytitle';
|
||||
import { PyInputBox } from './components/pyinputbox';
|
||||
import { PyWidget } from './components/base';
|
||||
import { PyLoader } from './components/pyloader';
|
||||
import { globalLoader } from './stores';
|
||||
import { PyConfig } from './components/pyconfig';
|
||||
import { getLogger } from './logger';
|
||||
import { globalLoader } from './stores';
|
||||
|
||||
const logger = getLogger('pyscript/main');
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const xPyScript = customElements.define('py-script', PyScript);
|
||||
const xPyRepl = customElements.define('py-repl', PyRepl);
|
||||
const xPyEnv = customElements.define('py-env', PyEnv);
|
||||
const xPyBox = customElements.define('py-box', PyBox);
|
||||
const xPyButton = customElements.define('py-button', PyButton);
|
||||
const xPyTitle = customElements.define('py-title', PyTitle);
|
||||
const xPyInputBox = customElements.define('py-inputbox', PyInputBox);
|
||||
const xPyWidget = customElements.define('py-register-widget', PyWidget);
|
||||
const xPyLoader = customElements.define('py-loader', PyLoader);
|
||||
const xPyConfig = customElements.define('py-config', PyConfig);
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
const xPyEnv = customElements.define('py-env', PyEnv);
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
||||
// As first thing, loop for application configs
|
||||
logger.info('checking for py-confing');
|
||||
|
||||
@@ -8,8 +8,9 @@ import {
|
||||
postInitializers,
|
||||
Initializer,
|
||||
scriptsQueue,
|
||||
appConfig
|
||||
} from './stores'
|
||||
appConfig,
|
||||
} from './stores';
|
||||
import { createCustomElements } from './components/elements';
|
||||
import type { PyScript } from './components/pyscript';
|
||||
import { getLogger } from './logger';
|
||||
|
||||
@@ -167,6 +168,9 @@ export abstract class Runtime extends Object {
|
||||
// now we call all post initializers AFTER we actually executed all page scripts
|
||||
loader?.log('Running post initializers...');
|
||||
|
||||
// Finally create the custom elements for pyscript such as pybutton
|
||||
createCustomElements();
|
||||
|
||||
if (appConfig_ && appConfig_.autoclose_loader) {
|
||||
loader?.close();
|
||||
}
|
||||
|
||||
@@ -191,6 +191,9 @@ class PyScriptTest:
|
||||
timeout=timeout,
|
||||
check_errors=check_errors,
|
||||
)
|
||||
# We still don't know why this wait is necessary, but without it
|
||||
# events aren't being triggered in the tests.
|
||||
self.page.wait_for_timeout(100)
|
||||
|
||||
def pyscript_run(self, snippet, *, extra_head=""):
|
||||
"""
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
import pytest
|
||||
|
||||
from .support import PyScriptTest
|
||||
|
||||
|
||||
class TestPyButton(PyScriptTest):
|
||||
@pytest.mark.xfail
|
||||
def test_on_click(self):
|
||||
"""
|
||||
currently this test fails for a bad reason which is unrelated to
|
||||
py-button. During the page loading, the following JS exception occur,
|
||||
in base.ts:BaseEvalElement.evaluate
|
||||
|
||||
[JS exception ] TypeError: Cannot use 'in' operator to search for 'runPythonAsync' in undefined
|
||||
at http://127.0.0.1:8080/build/pyscript.js:305:38
|
||||
at Object.subscribe (http://127.0.0.1:8080/build/pyscript.js:46:13)
|
||||
at PyButton.runAfterRuntimeInitialized (http://127.0.0.1:8080/build/pyscript.js:304:27)
|
||||
at PyButton.connectedCallback (http://127.0.0.1:8080/build/pyscript.js:26856:18)
|
||||
at http://127.0.0.1:8080/build/pyscript.js:27075:20
|
||||
at http://127.0.0.1:8080/build/pyscript.js:27093:3
|
||||
""" # noqa: E501
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-button label="my button">
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from .support import PyScriptTest
|
||||
|
||||
|
||||
class TestPyInputBox(PyScriptTest):
|
||||
@pytest.mark.xfail
|
||||
def test_input_box_typing(self):
|
||||
"""
|
||||
This test fails in a similar fashion as the pybutton
|
||||
test so it's xfailed for now.
|
||||
|
||||
[JS exception ] TypeError: Cannot use 'in' operator to search for 'runPythonAsync' in undefined
|
||||
at http://127.0.0.1:8080/build/pyscript.js:305:38
|
||||
at Object.subscribe (http://127.0.0.1:8080/build/pyscript.js:46:13)
|
||||
at PyButton.runAfterRuntimeInitialized (http://127.0.0.1:8080/build/pyscript.js:304:27)
|
||||
at PyButton.connectedCallback (http://127.0.0.1:8080/build/pyscript.js:26856:18)
|
||||
at http://127.0.0.1:8080/build/pyscript.js:27075:20
|
||||
at http://127.0.0.1:8080/build/pyscript.js:27093:3
|
||||
""" # noqa: E501
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-inputbox label="my input">
|
||||
@@ -32,10 +15,7 @@ class TestPyInputBox(PyScriptTest):
|
||||
)
|
||||
assert self.console.log.lines == [self.PY_COMPLETE]
|
||||
input = self.page.locator("input")
|
||||
# We need to wait some time before we can type any text
|
||||
# otherwise it won't be registered. This was the smallest
|
||||
# amount that seems to work.
|
||||
time.sleep(0.1)
|
||||
|
||||
input.type("Hello")
|
||||
input.press("Enter")
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import pytest
|
||||
|
||||
from .support import PyScriptTest
|
||||
|
||||
|
||||
@@ -15,22 +13,7 @@ class TestPyRepl(PyScriptTest):
|
||||
assert py_repl
|
||||
assert "Python" in py_repl.inner_text()
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_repl_runs_on_button_press(self):
|
||||
"""
|
||||
Current this test fails due to an exception when we iterate over
|
||||
'importmaps'
|
||||
|
||||
[ 2.28 JS exception ] TypeError: importmaps is not iterable
|
||||
at PyRepl._register_esm (http://127.0.0.1:8080/build/pyscript.js:227:37)
|
||||
at PyRepl.evaluate (http://127.0.0.1:8080/build/pyscript.js:252:22)
|
||||
at http://127.0.0.1:8080/build/pyscript.js:23678:21
|
||||
at runFor (http://127.0.0.1:8080/build/pyscript.js:11780:25)
|
||||
at runHandlers (http://127.0.0.1:8080/build/pyscript.js:11789:17)
|
||||
at Object.keydown (http://127.0.0.1:8080/build/pyscript.js:11691:20)
|
||||
at InputState.runCustomHandlers (http://127.0.0.1:8080/build/pyscript.js:8194:37)
|
||||
at HTMLDivElement.<anonymous> (http://127.0.0.1:8080/build/pyscript.js:8156:30)
|
||||
"""
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
@@ -43,26 +26,11 @@ class TestPyRepl(PyScriptTest):
|
||||
self.page.locator("button").click()
|
||||
|
||||
# The result gets the id of the repl + n
|
||||
repl_result = self.page.locator("#my-repl-1")
|
||||
repl_result = self.page.wait_for_selector("#my-repl-1", state="attached")
|
||||
|
||||
assert repl_result.inner_text() == "4"
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_repl_runs_with_shift_enter(self):
|
||||
"""
|
||||
Current this test fails due to an exception when we iterate over
|
||||
'importmaps'
|
||||
|
||||
[ 2.28 JS exception ] TypeError: importmaps is not iterable
|
||||
at PyRepl._register_esm (http://127.0.0.1:8080/build/pyscript.js:227:37)
|
||||
at PyRepl.evaluate (http://127.0.0.1:8080/build/pyscript.js:252:22)
|
||||
at http://127.0.0.1:8080/build/pyscript.js:23678:21
|
||||
at runFor (http://127.0.0.1:8080/build/pyscript.js:11780:25)
|
||||
at runHandlers (http://127.0.0.1:8080/build/pyscript.js:11789:17)
|
||||
at Object.keydown (http://127.0.0.1:8080/build/pyscript.js:11691:20)
|
||||
at InputState.runCustomHandlers (http://127.0.0.1:8080/build/pyscript.js:8194:37)
|
||||
at HTMLDivElement.<anonymous> (http://127.0.0.1:8080/build/pyscript.js:8156:30)
|
||||
"""
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
@@ -72,6 +40,6 @@ class TestPyRepl(PyScriptTest):
|
||||
|
||||
# Confirm that we get a result by using the keys shortcut
|
||||
self.page.keyboard.press("Shift+Enter")
|
||||
repl_result = self.page.locator("#my-repl-1")
|
||||
repl_result = self.page.wait_for_selector("#my-repl-1", state="attached")
|
||||
|
||||
assert repl_result.text_content() == "4"
|
||||
|
||||
@@ -105,6 +105,7 @@ class TestExamples(PyScriptTest):
|
||||
assert self.page.title() == "Bokeh Example"
|
||||
wait_for_render(self.page, "*", '<div.*?class=\\"bk\\".*?>')
|
||||
|
||||
@pytest.mark.xfail(reason="Flaky test #759")
|
||||
def test_d3(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/d3.html")
|
||||
@@ -161,7 +162,6 @@ class TestExamples(PyScriptTest):
|
||||
assert self.page.title() == "Pyscript/Panel KMeans Demo"
|
||||
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
||||
|
||||
@pytest.mark.xfail(reason="JsError: issue #677")
|
||||
def test_panel_stream(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/panel_stream.html")
|
||||
@@ -169,9 +169,6 @@ class TestExamples(PyScriptTest):
|
||||
assert self.page.title() == "PyScript/Panel Streaming Demo"
|
||||
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="Test seems flaky, sometimes it doesn't return result from second repl"
|
||||
)
|
||||
def test_repl(self):
|
||||
self.goto("examples/repl.html")
|
||||
self.wait_for_pyscript()
|
||||
@@ -186,8 +183,12 @@ class TestExamples(PyScriptTest):
|
||||
# Confirm that using the second repl still works properly
|
||||
self.page.locator("#my-repl-2").type("2*2")
|
||||
self.page.keyboard.press("Shift+Enter")
|
||||
|
||||
assert self.page.locator("#my-repl-2-2").text_content() == "4"
|
||||
# Make sure that the child of the second repl is attached properly
|
||||
# before looking into the text_content
|
||||
second_repl_result = self.page.wait_for_selector(
|
||||
"#my-repl-2-2", state="attached"
|
||||
)
|
||||
assert second_repl_result.text_content() == "4"
|
||||
|
||||
@pytest.mark.xfail(reason="Test seems flaky")
|
||||
def test_repl2(self):
|
||||
@@ -198,6 +199,8 @@ class TestExamples(PyScriptTest):
|
||||
# confirm we can import utils and run one command
|
||||
self.page.locator("py-repl").type("import utils\nutils.now()")
|
||||
self.page.locator("button").click()
|
||||
# Make sure the output is in the page
|
||||
self.page.wait_for_selector("#output")
|
||||
# utils.now returns current date time
|
||||
content = self.page.content()
|
||||
pattern = "\\d+/\\d+/\\d+, \\d+:\\d+:\\d+" # e.g. 08/09/2022 15:57:32
|
||||
@@ -230,7 +233,6 @@ class TestExamples(PyScriptTest):
|
||||
in first_task.inner_html()
|
||||
)
|
||||
|
||||
@pytest.mark.xfail(reason="JsError, issue #673")
|
||||
def test_todo_pylist(self):
|
||||
# XXX improve this test
|
||||
self.goto("examples/todo-pylist.html")
|
||||
|
||||
Reference in New Issue
Block a user