@pyscript/core 0.1.22 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.css +1 -1
- package/dist/core.js +2 -2
- package/dist/core.js.map +1 -1
- package/dist/error-e4fe78fd.js +2 -0
- package/dist/error-e4fe78fd.js.map +1 -0
- package/package.json +2 -2
- package/src/core.css +3 -1
- package/src/core.js +170 -161
- package/src/plugins/error.js +2 -2
- package/src/stdlib/pyscript/__init__.py +10 -1
- package/src/stdlib/pyscript/display.py +7 -0
- package/src/stdlib/pyscript/util.py +3 -4
- package/src/stdlib/pyscript.js +3 -3
- package/dist/error-87e0706c.js +0 -2
- package/dist/error-87e0706c.js.map +0 -1
- package/tests/integration/__init__.py +0 -0
- package/tests/integration/conftest.py +0 -184
- package/tests/integration/support.py +0 -1038
- package/tests/integration/test_00_support.py +0 -495
- package/tests/integration/test_01_basic.py +0 -353
- package/tests/integration/test_02_display.py +0 -452
- package/tests/integration/test_03_element.py +0 -303
- package/tests/integration/test_assets/line_plot.png +0 -0
- package/tests/integration/test_assets/tripcolor.png +0 -0
- package/tests/integration/test_async.py +0 -197
- package/tests/integration/test_event_handling.py +0 -193
- package/tests/integration/test_importmap.py +0 -66
- package/tests/integration/test_interpreter.py +0 -98
- package/tests/integration/test_plugins.py +0 -419
- package/tests/integration/test_py_config.py +0 -294
- package/tests/integration/test_py_repl.py +0 -663
- package/tests/integration/test_py_terminal.py +0 -270
- package/tests/integration/test_runtime_attributes.py +0 -64
- package/tests/integration/test_script_type.py +0 -121
- package/tests/integration/test_shadow_root.py +0 -33
- package/tests/integration/test_splashscreen.py +0 -124
- package/tests/integration/test_stdio_handling.py +0 -370
- package/tests/integration/test_style.py +0 -47
- package/tests/integration/test_warnings_and_banners.py +0 -32
- package/tests/integration/test_zz_examples.py +0 -419
- package/tests/integration/test_zzz_docs_snippets.py +0 -305
@@ -1,66 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
|
3
|
-
from .support import PyScriptTest
|
4
|
-
|
5
|
-
|
6
|
-
@pytest.mark.xfail(reason="See PR #938")
|
7
|
-
class TestImportmap(PyScriptTest):
|
8
|
-
def test_importmap(self):
|
9
|
-
src = """
|
10
|
-
export function say_hello(who) {
|
11
|
-
console.log("hello from", who);
|
12
|
-
}
|
13
|
-
"""
|
14
|
-
self.writefile("mymod.js", src)
|
15
|
-
#
|
16
|
-
self.pyscript_run(
|
17
|
-
"""
|
18
|
-
<script type="importmap">
|
19
|
-
{
|
20
|
-
"imports": {
|
21
|
-
"mymod": "/mymod.js"
|
22
|
-
}
|
23
|
-
}
|
24
|
-
</script>
|
25
|
-
|
26
|
-
<script type="module">
|
27
|
-
import { say_hello } from "mymod";
|
28
|
-
say_hello("JS");
|
29
|
-
</script>
|
30
|
-
|
31
|
-
<py-script>
|
32
|
-
import mymod
|
33
|
-
mymod.say_hello("Python")
|
34
|
-
</py-script>
|
35
|
-
"""
|
36
|
-
)
|
37
|
-
assert self.console.log.lines == [
|
38
|
-
"hello from JS",
|
39
|
-
"hello from Python",
|
40
|
-
]
|
41
|
-
|
42
|
-
def test_invalid_json(self):
|
43
|
-
self.pyscript_run(
|
44
|
-
"""
|
45
|
-
<script type="importmap">
|
46
|
-
this is not valid JSON
|
47
|
-
</script>
|
48
|
-
|
49
|
-
<py-script>
|
50
|
-
print("hello world")
|
51
|
-
</py-script>
|
52
|
-
""",
|
53
|
-
wait_for_pyscript=False,
|
54
|
-
)
|
55
|
-
# this error is raised by the browser itself, when *it* tries to parse
|
56
|
-
# the import map
|
57
|
-
self.check_js_errors("Failed to parse import map")
|
58
|
-
|
59
|
-
self.wait_for_pyscript()
|
60
|
-
assert self.console.log.lines == [
|
61
|
-
"hello world",
|
62
|
-
]
|
63
|
-
# this warning is shown by pyscript, when *we* try to parse the import
|
64
|
-
# map
|
65
|
-
banner = self.page.locator(".py-warning")
|
66
|
-
assert "Failed to parse import map" in banner.inner_text()
|
@@ -1,98 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
|
3
|
-
from .support import PyScriptTest
|
4
|
-
|
5
|
-
pytest.skip(
|
6
|
-
reason="FIXME: pyscript API changed doesn't expose pyscript to window anymore",
|
7
|
-
allow_module_level=True,
|
8
|
-
)
|
9
|
-
|
10
|
-
|
11
|
-
class TestInterpreterAccess(PyScriptTest):
|
12
|
-
"""Test accessing Python objects from JS via pyscript.interpreter"""
|
13
|
-
|
14
|
-
def test_interpreter_python_access(self):
|
15
|
-
self.pyscript_run(
|
16
|
-
"""
|
17
|
-
<py-script>
|
18
|
-
x = 1
|
19
|
-
def py_func():
|
20
|
-
return 2
|
21
|
-
</py-script>
|
22
|
-
"""
|
23
|
-
)
|
24
|
-
|
25
|
-
self.run_js(
|
26
|
-
"""
|
27
|
-
const x = await pyscript.interpreter.globals.get('x');
|
28
|
-
const py_func = await pyscript.interpreter.globals.get('py_func');
|
29
|
-
const py_func_res = await py_func();
|
30
|
-
console.log(`x is ${x}`);
|
31
|
-
console.log(`py_func() returns ${py_func_res}`);
|
32
|
-
"""
|
33
|
-
)
|
34
|
-
assert self.console.log.lines[-2:] == [
|
35
|
-
"x is 1",
|
36
|
-
"py_func() returns 2",
|
37
|
-
]
|
38
|
-
|
39
|
-
def test_interpreter_script_execution(self):
|
40
|
-
"""Test running Python code from js via pyscript.interpreter"""
|
41
|
-
self.pyscript_run("")
|
42
|
-
|
43
|
-
self.run_js(
|
44
|
-
"""
|
45
|
-
const interface = pyscript.interpreter._remote.interface;
|
46
|
-
await interface.runPython('print("Interpreter Ran This")');
|
47
|
-
"""
|
48
|
-
)
|
49
|
-
|
50
|
-
expected_message = "Interpreter Ran This"
|
51
|
-
assert self.console.log.lines[-1] == expected_message
|
52
|
-
|
53
|
-
py_terminal = self.page.wait_for_selector("py-terminal")
|
54
|
-
assert py_terminal.text_content() == expected_message
|
55
|
-
|
56
|
-
def test_backward_compatibility_runtime_script_execution(self):
|
57
|
-
"""Test running Python code from js via pyscript.runtime"""
|
58
|
-
self.pyscript_run("")
|
59
|
-
|
60
|
-
self.run_js(
|
61
|
-
"""
|
62
|
-
const interface = pyscript.runtime._remote.interpreter;
|
63
|
-
await interface.runPython('print("Interpreter Ran This")');
|
64
|
-
"""
|
65
|
-
)
|
66
|
-
|
67
|
-
expected_message = "Interpreter Ran This"
|
68
|
-
assert self.console.log.lines[-1] == expected_message
|
69
|
-
|
70
|
-
py_terminal = self.page.wait_for_selector("py-terminal")
|
71
|
-
assert py_terminal.text_content() == expected_message
|
72
|
-
|
73
|
-
def test_backward_compatibility_runtime_python_access(self):
|
74
|
-
"""Test accessing Python objects from JS via pyscript.runtime"""
|
75
|
-
self.pyscript_run(
|
76
|
-
"""
|
77
|
-
<py-script>
|
78
|
-
x = 1
|
79
|
-
def py_func():
|
80
|
-
return 2
|
81
|
-
</py-script>
|
82
|
-
"""
|
83
|
-
)
|
84
|
-
|
85
|
-
self.run_js(
|
86
|
-
"""
|
87
|
-
const x = await pyscript.interpreter.globals.get('x');
|
88
|
-
const py_func = await pyscript.interpreter.globals.get('py_func');
|
89
|
-
const py_func_res = await py_func();
|
90
|
-
console.log(`x is ${x}`);
|
91
|
-
console.log(`py_func() returns ${py_func_res}`);
|
92
|
-
"""
|
93
|
-
)
|
94
|
-
|
95
|
-
assert self.console.log.lines[-2:] == [
|
96
|
-
"x is 1",
|
97
|
-
"py_func() returns 2",
|
98
|
-
]
|
@@ -1,419 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
|
3
|
-
from .support import PyScriptTest, skip_worker
|
4
|
-
|
5
|
-
pytest.skip(
|
6
|
-
reason="FIX LATER: pyscript NEXT doesn't support plugins yet",
|
7
|
-
allow_module_level=True,
|
8
|
-
)
|
9
|
-
|
10
|
-
# Source code of a simple plugin that creates a Custom Element for testing purposes
|
11
|
-
CE_PLUGIN_CODE = """
|
12
|
-
from pyscript import Plugin
|
13
|
-
from js import console
|
14
|
-
|
15
|
-
plugin = Plugin('py-upper')
|
16
|
-
|
17
|
-
console.log("py_upper Plugin loaded")
|
18
|
-
|
19
|
-
@plugin.register_custom_element('py-up')
|
20
|
-
class Upper:
|
21
|
-
def __init__(self, element):
|
22
|
-
self.element = element
|
23
|
-
|
24
|
-
def connect(self):
|
25
|
-
console.log("Upper plugin connected")
|
26
|
-
return self.element.originalInnerHTML.upper()
|
27
|
-
"""
|
28
|
-
|
29
|
-
# Source of a plugin hooks into the PyScript App lifecycle events
|
30
|
-
HOOKS_PLUGIN_CODE = """
|
31
|
-
from pyscript import Plugin
|
32
|
-
from js import console
|
33
|
-
|
34
|
-
class TestLogger(Plugin):
|
35
|
-
def configure(self, config):
|
36
|
-
console.log('configure called')
|
37
|
-
|
38
|
-
def beforeLaunch(self, config):
|
39
|
-
console.log('beforeLaunch called')
|
40
|
-
|
41
|
-
def afterSetup(self, config):
|
42
|
-
console.log('afterSetup called')
|
43
|
-
|
44
|
-
def afterStartup(self, config):
|
45
|
-
console.log('afterStartup called')
|
46
|
-
|
47
|
-
def beforePyScriptExec(self, interpreter, src, pyScriptTag):
|
48
|
-
console.log(f'beforePyScriptExec called')
|
49
|
-
console.log(f'before_src:{src}')
|
50
|
-
|
51
|
-
def afterPyScriptExec(self, interpreter, src, pyScriptTag, result):
|
52
|
-
console.log(f'afterPyScriptExec called')
|
53
|
-
console.log(f'after_src:{src}')
|
54
|
-
|
55
|
-
def onUserError(self, config):
|
56
|
-
console.log('onUserError called')
|
57
|
-
|
58
|
-
|
59
|
-
plugin = TestLogger()
|
60
|
-
"""
|
61
|
-
|
62
|
-
# Source of script that defines a plugin with only beforePyScriptExec and
|
63
|
-
# afterPyScriptExec methods
|
64
|
-
PYSCRIPT_HOOKS_PLUGIN_CODE = """
|
65
|
-
from pyscript import Plugin
|
66
|
-
from js import console
|
67
|
-
|
68
|
-
class ExecTestLogger(Plugin):
|
69
|
-
|
70
|
-
async def beforePyScriptExec(self, interpreter, src, pyScriptTag):
|
71
|
-
console.log(f'beforePyScriptExec called')
|
72
|
-
console.log(f'before_src:{src}')
|
73
|
-
|
74
|
-
async def afterPyScriptExec(self, interpreter, src, pyScriptTag, result):
|
75
|
-
console.log(f'afterPyScriptExec called')
|
76
|
-
console.log(f'after_src:{src}')
|
77
|
-
console.log(f'result:{result}')
|
78
|
-
|
79
|
-
|
80
|
-
plugin = ExecTestLogger()
|
81
|
-
"""
|
82
|
-
|
83
|
-
# Source of script that defines a plugin with only beforePyScriptExec and
|
84
|
-
# afterPyScriptExec methods
|
85
|
-
PYREPL_HOOKS_PLUGIN_CODE = """
|
86
|
-
from pyscript import Plugin
|
87
|
-
from js import console
|
88
|
-
|
89
|
-
console.warn("This is in pyrepl hooks file")
|
90
|
-
|
91
|
-
class PyReplTestLogger(Plugin):
|
92
|
-
|
93
|
-
def beforePyReplExec(self, interpreter, src, outEl, pyReplTag):
|
94
|
-
console.log(f'beforePyReplExec called')
|
95
|
-
console.log(f'before_src:{src}')
|
96
|
-
|
97
|
-
def afterPyReplExec(self, interpreter, src, outEl, pyReplTag, result):
|
98
|
-
console.log(f'afterPyReplExec called')
|
99
|
-
console.log(f'after_src:{src}')
|
100
|
-
console.log(f'result:{result}')
|
101
|
-
|
102
|
-
|
103
|
-
plugin = PyReplTestLogger()
|
104
|
-
"""
|
105
|
-
|
106
|
-
# Source of a script that doesn't call define a `plugin` attribute
|
107
|
-
NO_PLUGIN_CODE = """
|
108
|
-
from pyscript import Plugin
|
109
|
-
from js import console
|
110
|
-
|
111
|
-
class TestLogger(Plugin):
|
112
|
-
pass
|
113
|
-
"""
|
114
|
-
|
115
|
-
# Source code of a simple plugin that creates a Custom Element for testing purposes
|
116
|
-
CODE_CE_PLUGIN_BAD_RETURNS = """
|
117
|
-
from pyscript import Plugin
|
118
|
-
from js import console
|
119
|
-
|
120
|
-
plugin = Plugin('py-broken')
|
121
|
-
|
122
|
-
@plugin.register_custom_element('py-up')
|
123
|
-
class Upper:
|
124
|
-
def __init__(self, element):
|
125
|
-
self.element = element
|
126
|
-
|
127
|
-
def connect(self):
|
128
|
-
# Just returning something... anything other than a string should be ignore
|
129
|
-
return Plugin
|
130
|
-
"""
|
131
|
-
HTML_TEMPLATE_WITH_TAG = """
|
132
|
-
<py-config>
|
133
|
-
plugins = [
|
134
|
-
"./{plugin_name}.py"
|
135
|
-
]
|
136
|
-
</py-config>
|
137
|
-
|
138
|
-
<{tagname}>
|
139
|
-
{html}
|
140
|
-
</{tagname}>
|
141
|
-
"""
|
142
|
-
HTML_TEMPLATE_NO_TAG = """
|
143
|
-
<py-config>
|
144
|
-
plugins = [
|
145
|
-
"./{plugin_name}.py"
|
146
|
-
]
|
147
|
-
</py-config>
|
148
|
-
"""
|
149
|
-
|
150
|
-
|
151
|
-
def prepare_test(
|
152
|
-
plugin_name, code, tagname="", html="", template=HTML_TEMPLATE_WITH_TAG
|
153
|
-
):
|
154
|
-
"""
|
155
|
-
Prepares the test by writing a new plugin file named `plugin_name`.py, with `code` as its
|
156
|
-
content and run `pyscript_run` on `template` formatted with the above inputs to create the
|
157
|
-
page HTML code.
|
158
|
-
|
159
|
-
For example:
|
160
|
-
|
161
|
-
>> @prepare_test('py-upper', CE_PLUGIN_CODE, tagname='py-up', html="Hello World")
|
162
|
-
>> def my_foo(...):
|
163
|
-
>> ...
|
164
|
-
|
165
|
-
will:
|
166
|
-
|
167
|
-
* write a new `py-upper.py` file to the FS
|
168
|
-
* the contents of `py-upper.py` is equal to CE_PLUGIN_CODE
|
169
|
-
* call self.pyscript_run with the following string:
|
170
|
-
'''
|
171
|
-
<py-config>
|
172
|
-
plugins = [
|
173
|
-
"./py-upper.py"
|
174
|
-
]
|
175
|
-
</py-config>
|
176
|
-
|
177
|
-
<py-up>
|
178
|
-
{html}
|
179
|
-
</py-up>
|
180
|
-
'''
|
181
|
-
* call `my_foo` just like a normal decorator would
|
182
|
-
|
183
|
-
"""
|
184
|
-
|
185
|
-
def dec(f):
|
186
|
-
def _inner(self, *args, **kws):
|
187
|
-
self.writefile(f"{plugin_name}.py", code)
|
188
|
-
page_html = template.format(
|
189
|
-
plugin_name=plugin_name, tagname=tagname, html=html
|
190
|
-
)
|
191
|
-
self.pyscript_run(page_html)
|
192
|
-
return f(self, *args, **kws)
|
193
|
-
|
194
|
-
return _inner
|
195
|
-
|
196
|
-
return dec
|
197
|
-
|
198
|
-
|
199
|
-
class TestPlugin(PyScriptTest):
|
200
|
-
@skip_worker("FIXME: relative paths")
|
201
|
-
@prepare_test("py-upper", CE_PLUGIN_CODE, tagname="py-up", html="Hello World")
|
202
|
-
def test_py_plugin_inline(self):
|
203
|
-
"""Test that a regular plugin that returns new HTML content from connected works"""
|
204
|
-
# GIVEN a plugin that returns the all caps version of the tag innerHTML and logs text
|
205
|
-
# during it's execution/hooks
|
206
|
-
|
207
|
-
# EXPECT the plugin logs to be present in the console logs
|
208
|
-
log_lines = self.console.log.lines
|
209
|
-
for log_line in ["py_upper Plugin loaded", "Upper plugin connected"]:
|
210
|
-
assert log_line in log_lines
|
211
|
-
|
212
|
-
# EXPECT the inner text of the Plugin CustomElement to be all caps
|
213
|
-
rendered_text = self.page.locator("py-up").inner_text()
|
214
|
-
assert rendered_text == "HELLO WORLD"
|
215
|
-
|
216
|
-
@skip_worker("FIXME: relative paths")
|
217
|
-
@prepare_test("hooks_logger", HOOKS_PLUGIN_CODE, template=HTML_TEMPLATE_NO_TAG)
|
218
|
-
def test_execution_hooks(self):
|
219
|
-
"""Test that a Plugin that hooks into the PyScript App events, gets called
|
220
|
-
for each one of them"""
|
221
|
-
# GIVEN a plugin that logs specific strings for each app execution event
|
222
|
-
hooks_available = ["afterSetup", "afterStartup"]
|
223
|
-
hooks_unavailable = [
|
224
|
-
"configure",
|
225
|
-
"beforeLaunch",
|
226
|
-
"beforePyScriptExec",
|
227
|
-
"afterPyScriptExec",
|
228
|
-
"beforePyReplExec",
|
229
|
-
"afterPyReplExec",
|
230
|
-
]
|
231
|
-
|
232
|
-
# EXPECT it to log the correct logs for the events it intercepts
|
233
|
-
log_lines = self.console.log.lines
|
234
|
-
num_calls = {
|
235
|
-
method: log_lines.count(f"{method} called") for method in hooks_available
|
236
|
-
}
|
237
|
-
expected_calls = {method: 1 for method in hooks_available}
|
238
|
-
assert num_calls == expected_calls
|
239
|
-
|
240
|
-
# EXPECT it to NOT be called (hence not log anything) the events that happen
|
241
|
-
# before it's ready, hence is not called
|
242
|
-
unavailable_called = {
|
243
|
-
method: f"{method} called" in log_lines for method in hooks_unavailable
|
244
|
-
}
|
245
|
-
assert unavailable_called == {method: False for method in hooks_unavailable}
|
246
|
-
|
247
|
-
# TODO: It'd be actually better to check that the events get called in order
|
248
|
-
|
249
|
-
@skip_worker("FIXME: relative paths")
|
250
|
-
@prepare_test(
|
251
|
-
"exec_test_logger",
|
252
|
-
PYSCRIPT_HOOKS_PLUGIN_CODE,
|
253
|
-
template=HTML_TEMPLATE_NO_TAG + "\n<py-script id='pyid'>x=2; x</py-script>",
|
254
|
-
)
|
255
|
-
def test_pyscript_exec_hooks(self):
|
256
|
-
"""Test that the beforePyScriptExec and afterPyScriptExec hooks work as intended"""
|
257
|
-
assert self.page.locator("py-script") is not None
|
258
|
-
|
259
|
-
log_lines: list[str] = self.console.log.lines
|
260
|
-
|
261
|
-
assert "beforePyScriptExec called" in log_lines
|
262
|
-
assert "afterPyScriptExec called" in log_lines
|
263
|
-
|
264
|
-
# These could be made better with a utility function that found log lines
|
265
|
-
# that match a filter function, or start with something
|
266
|
-
assert "before_src:x=2; x" in log_lines
|
267
|
-
assert "after_src:x=2; x" in log_lines
|
268
|
-
assert "result:2" in log_lines
|
269
|
-
|
270
|
-
@skip_worker("FIXME: relative paths")
|
271
|
-
@prepare_test(
|
272
|
-
"pyrepl_test_logger",
|
273
|
-
PYREPL_HOOKS_PLUGIN_CODE,
|
274
|
-
template=HTML_TEMPLATE_NO_TAG + "\n<py-repl id='pyid'>x=2; x</py-repl>",
|
275
|
-
)
|
276
|
-
def test_pyrepl_exec_hooks(self):
|
277
|
-
py_repl = self.page.locator("py-repl")
|
278
|
-
py_repl.locator("button").click()
|
279
|
-
# allow afterPyReplExec to also finish before the test finishes
|
280
|
-
self.wait_for_console("result:2")
|
281
|
-
|
282
|
-
log_lines: list[str] = self.console.log.lines
|
283
|
-
|
284
|
-
assert "beforePyReplExec called" in log_lines
|
285
|
-
assert "afterPyReplExec called" in log_lines
|
286
|
-
|
287
|
-
# These could be made better with a utility function that found log lines
|
288
|
-
# that match a filter function, or start with something
|
289
|
-
assert "before_src:x=2; x" in log_lines
|
290
|
-
assert "after_src:x=2; x" in log_lines
|
291
|
-
assert "result:2" in log_lines
|
292
|
-
|
293
|
-
@skip_worker("FIXME: relative paths")
|
294
|
-
@prepare_test("no_plugin", NO_PLUGIN_CODE)
|
295
|
-
def test_no_plugin_attribute_error(self):
|
296
|
-
"""
|
297
|
-
Test a plugin that do not add the `plugin` attribute to its module
|
298
|
-
"""
|
299
|
-
# GIVEN a Plugin NO `plugin` attribute in it's module
|
300
|
-
error_msg = (
|
301
|
-
"[pyscript/main] Cannot find plugin on Python module no_plugin! Python plugins "
|
302
|
-
'modules must contain a "plugin" attribute. For more information check the '
|
303
|
-
"plugins documentation."
|
304
|
-
)
|
305
|
-
# EXPECT an error for the missing attribute
|
306
|
-
assert error_msg in self.console.error.lines
|
307
|
-
|
308
|
-
@skip_worker("FIXME: relative paths")
|
309
|
-
def test_fetch_python_plugin(self):
|
310
|
-
"""
|
311
|
-
Test that we can fetch a plugin from a remote URL. Note we need to use
|
312
|
-
the 'raw' URL for the plugin, otherwise the request will be rejected
|
313
|
-
by cors policy.
|
314
|
-
"""
|
315
|
-
self.pyscript_run(
|
316
|
-
"""
|
317
|
-
<py-config>
|
318
|
-
plugins = [
|
319
|
-
"https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/python/hello-world.py"
|
320
|
-
]
|
321
|
-
|
322
|
-
</py-config>
|
323
|
-
<py-hello-world></py-hello-world>
|
324
|
-
"""
|
325
|
-
)
|
326
|
-
|
327
|
-
hello_element = self.page.locator("py-hello-world")
|
328
|
-
assert hello_element.inner_html() == '<div id="hello">Hello World!</div>'
|
329
|
-
|
330
|
-
def test_fetch_js_plugin(self):
|
331
|
-
self.pyscript_run(
|
332
|
-
"""
|
333
|
-
<py-config>
|
334
|
-
plugins = [
|
335
|
-
"https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world.js"
|
336
|
-
]
|
337
|
-
</py-config>
|
338
|
-
"""
|
339
|
-
)
|
340
|
-
|
341
|
-
hello_element = self.page.locator("py-hello-world")
|
342
|
-
assert hello_element.inner_html() == "<h1>Hello, world!</h1>"
|
343
|
-
|
344
|
-
def test_fetch_js_plugin_bare(self):
|
345
|
-
self.pyscript_run(
|
346
|
-
"""
|
347
|
-
<py-config>
|
348
|
-
plugins = [
|
349
|
-
"https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world-base.js"
|
350
|
-
]
|
351
|
-
</py-config>
|
352
|
-
"""
|
353
|
-
)
|
354
|
-
|
355
|
-
hello_element = self.page.locator("py-hello-world")
|
356
|
-
assert hello_element.inner_html() == "<h1>Hello, world!</h1>"
|
357
|
-
|
358
|
-
def test_fetch_plugin_no_file_extension(self):
|
359
|
-
self.pyscript_run(
|
360
|
-
"""
|
361
|
-
<py-config>
|
362
|
-
plugins = [
|
363
|
-
"https://non-existent.blah/hello-world"
|
364
|
-
]
|
365
|
-
</py-config>
|
366
|
-
""",
|
367
|
-
wait_for_pyscript=False,
|
368
|
-
)
|
369
|
-
|
370
|
-
expected_msg = (
|
371
|
-
"(PY2000): Unable to load plugin from "
|
372
|
-
"'https://non-existent.blah/hello-world'. Plugins "
|
373
|
-
"need to contain a file extension and be either a "
|
374
|
-
"python or javascript file."
|
375
|
-
)
|
376
|
-
|
377
|
-
assert self.assert_banner_message(expected_msg)
|
378
|
-
|
379
|
-
def test_fetch_js_plugin_non_existent(self):
|
380
|
-
self.pyscript_run(
|
381
|
-
"""
|
382
|
-
<py-config>
|
383
|
-
plugins = [
|
384
|
-
"http://non-existent.example.com/hello-world.js"
|
385
|
-
]
|
386
|
-
</py-config>
|
387
|
-
""",
|
388
|
-
wait_for_pyscript=False,
|
389
|
-
)
|
390
|
-
|
391
|
-
expected_msg = (
|
392
|
-
"(PY0001): Fetching from URL "
|
393
|
-
"http://non-existent.example.com/hello-world.js failed "
|
394
|
-
"with error 'Failed to fetch'. Are your filename and "
|
395
|
-
"path correct?"
|
396
|
-
)
|
397
|
-
|
398
|
-
assert self.assert_banner_message(expected_msg)
|
399
|
-
|
400
|
-
def test_fetch_js_no_export(self):
|
401
|
-
self.pyscript_run(
|
402
|
-
"""
|
403
|
-
<py-config>
|
404
|
-
plugins = [
|
405
|
-
"https://raw.githubusercontent.com/FabioRosado/pyscript-plugins/main/js/hello-world-no-export.js"
|
406
|
-
]
|
407
|
-
</py-config>
|
408
|
-
""",
|
409
|
-
wait_for_pyscript=False,
|
410
|
-
)
|
411
|
-
|
412
|
-
expected_message = (
|
413
|
-
"(PY2001): Unable to load plugin from "
|
414
|
-
"'https://raw.githubusercontent.com/FabioRosado/pyscript-plugins"
|
415
|
-
"/main/js/hello-world-no-export.js'. "
|
416
|
-
"Plugins need to contain a default export."
|
417
|
-
)
|
418
|
-
|
419
|
-
assert self.assert_banner_message(expected_message)
|