@pyscript/core 0.1.21 → 0.2.0
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.js +3 -3
- 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/config.js +1 -1
- package/src/core.js +20 -1
- package/src/exceptions.js +7 -6
- package/src/plugins/error.js +2 -2
- package/src/stdlib/pyscript/display.py +7 -0
- package/src/stdlib/pyscript.js +1 -1
- package/types/config.d.ts +2 -1
- package/types/exceptions.d.ts +6 -5
- 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,419 +0,0 @@
|
|
1
|
-
import base64
|
2
|
-
import io
|
3
|
-
import os
|
4
|
-
import re
|
5
|
-
import time
|
6
|
-
|
7
|
-
import numpy as np
|
8
|
-
import pytest
|
9
|
-
from PIL import Image
|
10
|
-
|
11
|
-
from .support import ROOT, PyScriptTest, wait_for_render, with_execution_thread
|
12
|
-
|
13
|
-
|
14
|
-
@pytest.mark.skip(
|
15
|
-
reason="SKIPPING EXAMPLES: these should be moved elsewhere and updated"
|
16
|
-
)
|
17
|
-
@with_execution_thread(None)
|
18
|
-
@pytest.mark.usefixtures("chdir")
|
19
|
-
class TestExamples(PyScriptTest):
|
20
|
-
"""
|
21
|
-
Each example requires the same three tests:
|
22
|
-
|
23
|
-
- Test that the initial markup loads properly (currently done by
|
24
|
-
testing the <title> tag's content)
|
25
|
-
- Testing that pyscript is loading properly
|
26
|
-
- Testing that the page contains appropriate content after rendering
|
27
|
-
"""
|
28
|
-
|
29
|
-
@pytest.fixture()
|
30
|
-
def chdir(self):
|
31
|
-
# make sure that the http server serves from the right directory
|
32
|
-
ROOT.join("pyscriptjs").chdir()
|
33
|
-
|
34
|
-
def test_hello_world(self):
|
35
|
-
self.goto("examples/hello_world.html")
|
36
|
-
self.wait_for_pyscript()
|
37
|
-
assert self.page.title() == "PyScript Hello World"
|
38
|
-
content = self.page.content()
|
39
|
-
pattern = "\\d+/\\d+/\\d+, \\d+:\\d+:\\d+" # e.g. 08/09/2022 15:57:32
|
40
|
-
assert re.search(pattern, content)
|
41
|
-
self.assert_no_banners()
|
42
|
-
self.check_tutor_generated_code()
|
43
|
-
|
44
|
-
def test_simple_clock(self):
|
45
|
-
self.goto("examples/simple_clock.html")
|
46
|
-
self.wait_for_pyscript()
|
47
|
-
assert self.page.title() == "Simple Clock Demo"
|
48
|
-
pattern = r"\d{2}/\d{2}/\d{4}, \d{2}:\d{2}:\d{2}"
|
49
|
-
# run for 5 seconds to be sure that we see the page with "It's
|
50
|
-
# espresso time!"
|
51
|
-
for _ in range(5):
|
52
|
-
content = self.page.inner_html("#outputDiv2")
|
53
|
-
if re.match(pattern, content) and int(content[-1]) in (0, 4, 8):
|
54
|
-
assert self.page.inner_html("#outputDiv3") == "It's espresso time!"
|
55
|
-
break
|
56
|
-
else:
|
57
|
-
time.sleep(1)
|
58
|
-
else:
|
59
|
-
raise AssertionError("Espresso time not found :(")
|
60
|
-
self.assert_no_banners()
|
61
|
-
self.check_tutor_generated_code()
|
62
|
-
|
63
|
-
def test_altair(self):
|
64
|
-
self.goto("examples/altair.html")
|
65
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
66
|
-
assert self.page.title() == "Altair"
|
67
|
-
wait_for_render(self.page, "*", '<canvas.*?class=\\"marks\\".*?>')
|
68
|
-
save_as_png_link = self.page.locator("text=Save as PNG")
|
69
|
-
see_source_link = self.page.locator("text=View Source")
|
70
|
-
# These shouldn't be visible since we didn't click the menu
|
71
|
-
assert not save_as_png_link.is_visible()
|
72
|
-
assert not see_source_link.is_visible()
|
73
|
-
|
74
|
-
self.page.locator("summary").click()
|
75
|
-
|
76
|
-
# Let's confirm that the links are visible now after clicking the menu
|
77
|
-
assert save_as_png_link.is_visible()
|
78
|
-
assert see_source_link.is_visible()
|
79
|
-
self.assert_no_banners()
|
80
|
-
self.check_tutor_generated_code()
|
81
|
-
|
82
|
-
def test_antigravity(self):
|
83
|
-
self.goto("examples/antigravity.html")
|
84
|
-
self.wait_for_pyscript()
|
85
|
-
assert self.page.title() == "Antigravity"
|
86
|
-
|
87
|
-
# confirm that svg added to page
|
88
|
-
wait_for_render(self.page, "*", '<svg.*id="svg8".*>')
|
89
|
-
|
90
|
-
# Get svg layer of flying character
|
91
|
-
char = self.page.wait_for_selector("#python")
|
92
|
-
assert char is not None
|
93
|
-
|
94
|
-
# check that character moves in negative-y direction over time
|
95
|
-
ycoord_pattern = r"translate\(-?\d*\.\d*,\s(?P<ycoord>-?[\d.]+)\)"
|
96
|
-
starting_y_coord = float(
|
97
|
-
re.match(ycoord_pattern, char.get_attribute("transform")).group("ycoord")
|
98
|
-
)
|
99
|
-
time.sleep(2)
|
100
|
-
later_y_coord = float(
|
101
|
-
re.match(ycoord_pattern, char.get_attribute("transform")).group("ycoord")
|
102
|
-
)
|
103
|
-
assert later_y_coord < starting_y_coord
|
104
|
-
self.check_tutor_generated_code(modules_to_check=["antigravity.py"])
|
105
|
-
|
106
|
-
def test_bokeh(self):
|
107
|
-
# XXX improve this test
|
108
|
-
self.goto("examples/bokeh.html")
|
109
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
110
|
-
assert self.page.title() == "Bokeh Example"
|
111
|
-
wait_for_render(self.page, "*", '<div.*?class="bk.*".*?>')
|
112
|
-
self.assert_no_banners()
|
113
|
-
self.check_tutor_generated_code()
|
114
|
-
|
115
|
-
def test_bokeh_interactive(self):
|
116
|
-
# XXX improve this test
|
117
|
-
self.goto("examples/bokeh_interactive.html")
|
118
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
119
|
-
assert self.page.title() == "Bokeh Example"
|
120
|
-
wait_for_render(self.page, "*", '<div.*?class=\\"bk\\".*?>')
|
121
|
-
self.assert_no_banners()
|
122
|
-
self.check_tutor_generated_code()
|
123
|
-
|
124
|
-
@pytest.mark.skip("flaky, see issue 759")
|
125
|
-
def test_d3(self):
|
126
|
-
self.goto("examples/d3.html")
|
127
|
-
self.wait_for_pyscript()
|
128
|
-
assert (
|
129
|
-
self.page.title() == "d3: JavaScript & PyScript visualizations side-by-side"
|
130
|
-
)
|
131
|
-
wait_for_render(self.page, "*", "<svg.*?>")
|
132
|
-
assert "PyScript version" in self.page.content()
|
133
|
-
pyscript_chart = self.page.wait_for_selector("#py")
|
134
|
-
|
135
|
-
# Let's simply assert that the text of the chart is as expected which
|
136
|
-
# means that the chart rendered successfully and with the right text
|
137
|
-
assert "🍊21\n🍇13\n🍏8\n🍌5\n🍐3\n🍋2\n🍎1\n🍉1" in pyscript_chart.inner_text()
|
138
|
-
self.assert_no_banners()
|
139
|
-
self.check_tutor_generated_code(modules_to_check=["d3.py"])
|
140
|
-
|
141
|
-
def test_folium(self):
|
142
|
-
self.goto("examples/folium.html")
|
143
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
144
|
-
assert self.page.title() == "Folium"
|
145
|
-
wait_for_render(self.page, "*", "<iframe srcdoc=")
|
146
|
-
|
147
|
-
# We need to look into the iframe first
|
148
|
-
iframe = self.page.frame_locator("iframe")
|
149
|
-
|
150
|
-
# Just checking that legend was rendered correctly
|
151
|
-
legend = iframe.locator("#legend")
|
152
|
-
assert "Unemployment Rate (%)" in legend.inner_html()
|
153
|
-
|
154
|
-
# Let's check that the zoom buttons are rendered and clickable
|
155
|
-
# Note: if element is not clickable it will timeout
|
156
|
-
zoom_in = iframe.locator("[aria-label='Zoom in']")
|
157
|
-
assert "+" in zoom_in.inner_text()
|
158
|
-
zoom_in.click()
|
159
|
-
zoom_out = iframe.locator("[aria-label='Zoom out']")
|
160
|
-
assert "−" in zoom_out.inner_text()
|
161
|
-
zoom_out.click()
|
162
|
-
self.assert_no_banners()
|
163
|
-
self.check_tutor_generated_code()
|
164
|
-
|
165
|
-
def test_markdown_plugin(self):
|
166
|
-
# Given the example page with:
|
167
|
-
# * <title>PyMarkdown</title>
|
168
|
-
# * <py-md>#Hello world!</py-md>
|
169
|
-
self.goto("examples/markdown-plugin.html")
|
170
|
-
self.wait_for_pyscript()
|
171
|
-
# ASSERT title is rendered correctly
|
172
|
-
assert self.page.title() == "PyMarkdown"
|
173
|
-
# ASSERT markdown is rendered to the corresponding HTML tag
|
174
|
-
wait_for_render(self.page, "*", "<h1>Hello world!</h1>")
|
175
|
-
self.check_tutor_generated_code()
|
176
|
-
|
177
|
-
def test_matplotlib(self):
|
178
|
-
self.goto("examples/matplotlib.html")
|
179
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
180
|
-
assert self.page.title() == "Matplotlib"
|
181
|
-
wait_for_render(self.page, "*", "<img src=['\"]data:image")
|
182
|
-
# The image is being rended using base64, lets fetch its source
|
183
|
-
# and replace everything but the actual base64 string.
|
184
|
-
# Note: The first image on the page is the logo, so we are lookin
|
185
|
-
# at the mpl-1 div which is rendered once the image is in the page
|
186
|
-
# if this test fails, confirm that the div has the right id using
|
187
|
-
# the --dev flag when running the tests
|
188
|
-
test = self.page.wait_for_selector("#mpl >> img")
|
189
|
-
img_src = test.get_attribute("src").replace(
|
190
|
-
"data:image/png;charset=utf-8;base64,", ""
|
191
|
-
)
|
192
|
-
# Finally, let's get the np array from the previous data
|
193
|
-
img_data = np.asarray(Image.open(io.BytesIO(base64.b64decode(img_src))))
|
194
|
-
with Image.open(
|
195
|
-
os.path.join(os.path.dirname(__file__), "test_assets", "tripcolor.png"),
|
196
|
-
) as image:
|
197
|
-
ref_data = np.asarray(image)
|
198
|
-
# Now that we have both images data as a numpy array
|
199
|
-
# let's confirm that they are the same
|
200
|
-
deviation = np.mean(np.abs(img_data - ref_data))
|
201
|
-
assert deviation == 0.0
|
202
|
-
self.assert_no_banners()
|
203
|
-
self.check_tutor_generated_code()
|
204
|
-
|
205
|
-
def test_numpy_canvas_fractals(self):
|
206
|
-
self.goto("examples/numpy_canvas_fractals.html")
|
207
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
208
|
-
assert (
|
209
|
-
self.page.title()
|
210
|
-
== "Visualization of Mandelbrot, Julia and Newton sets with NumPy and HTML5 canvas"
|
211
|
-
)
|
212
|
-
wait_for_render(
|
213
|
-
self.page, "*", "<div.*?id=['\"](mandelbrot|julia|newton)['\"].*?>"
|
214
|
-
)
|
215
|
-
|
216
|
-
# Assert that we get the title and canvas for each element
|
217
|
-
mandelbrot = self.page.wait_for_selector("#mandelbrot")
|
218
|
-
assert "Mandelbrot set" in mandelbrot.inner_text()
|
219
|
-
assert "<canvas" in mandelbrot.inner_html()
|
220
|
-
|
221
|
-
julia = self.page.wait_for_selector("#julia")
|
222
|
-
assert "Julia set" in julia.inner_text()
|
223
|
-
assert "<canvas" in julia.inner_html()
|
224
|
-
|
225
|
-
newton = self.page.wait_for_selector("#newton")
|
226
|
-
assert "Newton set" in newton.inner_text()
|
227
|
-
assert "<canvas" in newton.inner_html()
|
228
|
-
|
229
|
-
# Confirm that all fieldsets are rendered correctly
|
230
|
-
poly = newton.wait_for_selector("#poly")
|
231
|
-
assert poly.input_value() == "z**3 - 2*z + 2"
|
232
|
-
|
233
|
-
coef = newton.wait_for_selector("#coef")
|
234
|
-
assert coef.input_value() == "1"
|
235
|
-
|
236
|
-
# Let's now change some x/y values to confirm that they
|
237
|
-
# are editable (is it the best way to test this?)
|
238
|
-
x0 = newton.wait_for_selector("#x0")
|
239
|
-
y0 = newton.wait_for_selector("#y0")
|
240
|
-
|
241
|
-
x0.fill("50")
|
242
|
-
assert x0.input_value() == "50"
|
243
|
-
y0.fill("-25")
|
244
|
-
assert y0.input_value() == "-25"
|
245
|
-
|
246
|
-
# This was the first computation with the default values
|
247
|
-
assert self.console.log.lines[-2] == "Computing Newton set ..."
|
248
|
-
# Confirm that changing the input values, triggered a new computation
|
249
|
-
assert self.console.log.lines[-1] == "Computing Newton set ..."
|
250
|
-
self.assert_no_banners()
|
251
|
-
self.check_tutor_generated_code()
|
252
|
-
|
253
|
-
def test_panel(self):
|
254
|
-
self.goto("examples/panel.html")
|
255
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
256
|
-
assert self.page.title() == "Panel Example"
|
257
|
-
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
258
|
-
slider_title = self.page.wait_for_selector(".bk-slider-title")
|
259
|
-
assert slider_title.inner_text() == "Amplitude: 0"
|
260
|
-
|
261
|
-
slider_result = self.page.wait_for_selector(".bk-clearfix")
|
262
|
-
assert slider_result.inner_text() == "Amplitude is: 0"
|
263
|
-
|
264
|
-
amplitude_bar = self.page.wait_for_selector(".noUi-connects")
|
265
|
-
amplitude_bar.click()
|
266
|
-
|
267
|
-
# Let's confirm that slider title changed
|
268
|
-
assert slider_title.inner_text() == "Amplitude: 5"
|
269
|
-
self.assert_no_banners()
|
270
|
-
self.check_tutor_generated_code()
|
271
|
-
|
272
|
-
def test_panel_deckgl(self):
|
273
|
-
# XXX improve this test
|
274
|
-
self.goto("examples/panel_deckgl.html")
|
275
|
-
self.wait_for_pyscript(timeout=90 * 1000)
|
276
|
-
assert self.page.title() == "PyScript/Panel DeckGL Demo"
|
277
|
-
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
278
|
-
self.assert_no_banners()
|
279
|
-
self.check_tutor_generated_code()
|
280
|
-
|
281
|
-
def test_panel_kmeans(self):
|
282
|
-
# XXX improve this test>>>>>>> main
|
283
|
-
self.goto("examples/panel_kmeans.html")
|
284
|
-
self.wait_for_pyscript(timeout=120 * 1000)
|
285
|
-
assert self.page.title() == "Pyscript/Panel KMeans Demo"
|
286
|
-
wait_for_render(
|
287
|
-
self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>", timeout_seconds=60 * 2
|
288
|
-
)
|
289
|
-
self.assert_no_banners()
|
290
|
-
self.check_tutor_generated_code()
|
291
|
-
|
292
|
-
def test_panel_stream(self):
|
293
|
-
# XXX improve this test
|
294
|
-
self.goto("examples/panel_stream.html")
|
295
|
-
self.wait_for_pyscript(timeout=3 * 60 * 1000)
|
296
|
-
assert self.page.title() == "PyScript/Panel Streaming Demo"
|
297
|
-
wait_for_render(self.page, "*", "<div.*?class=['\"]bk-root['\"].*?>")
|
298
|
-
self.assert_no_banners()
|
299
|
-
self.check_tutor_generated_code()
|
300
|
-
|
301
|
-
def test_repl(self):
|
302
|
-
self.goto("examples/repl.html")
|
303
|
-
self.wait_for_pyscript()
|
304
|
-
assert self.page.title() == "REPL"
|
305
|
-
self.page.wait_for_selector("py-repl")
|
306
|
-
|
307
|
-
self.page.locator("py-repl").type("display('Hello, World!')")
|
308
|
-
self.page.wait_for_selector(".py-repl-run-button").click()
|
309
|
-
self.page.wait_for_selector("#my-repl-repl-output")
|
310
|
-
assert (
|
311
|
-
self.page.locator("#my-repl-repl-output").text_content() == "Hello, World!"
|
312
|
-
)
|
313
|
-
|
314
|
-
# Confirm that using the second repl still works properly
|
315
|
-
self.page.locator("#my-repl-1").type("display(2*2)")
|
316
|
-
self.page.keyboard.press("Shift+Enter")
|
317
|
-
my_repl_1 = self.page.wait_for_selector("#my-repl-1-repl-output")
|
318
|
-
assert my_repl_1.inner_text() == "4"
|
319
|
-
self.assert_no_banners()
|
320
|
-
self.check_tutor_generated_code(modules_to_check=["antigravity.py"])
|
321
|
-
|
322
|
-
def test_repl2(self):
|
323
|
-
self.goto("examples/repl2.html")
|
324
|
-
self.wait_for_pyscript(timeout=1.5 * 60 * 1000)
|
325
|
-
assert self.page.title() == "Custom REPL Example"
|
326
|
-
wait_for_render(self.page, "*", "<py-repl.*?>")
|
327
|
-
# confirm we can import utils and run one command
|
328
|
-
self.page.locator("py-repl").type("import utils\ndisplay(utils.now())")
|
329
|
-
self.page.wait_for_selector("py-repl .py-repl-run-button").click()
|
330
|
-
# Make sure the output is in the page
|
331
|
-
self.page.wait_for_selector("#my-repl-1")
|
332
|
-
# utils.now returns current date time
|
333
|
-
content = self.page.content()
|
334
|
-
pattern = "\\d+/\\d+/\\d+, \\d+:\\d+:\\d+" # e.g. 08/09/2022 15:57:32
|
335
|
-
assert re.search(pattern, content)
|
336
|
-
self.assert_no_banners()
|
337
|
-
self.check_tutor_generated_code(modules_to_check=["antigravity.py"])
|
338
|
-
|
339
|
-
def test_todo(self):
|
340
|
-
self.goto("examples/todo.html")
|
341
|
-
self.wait_for_pyscript()
|
342
|
-
assert self.page.title() == "Todo App"
|
343
|
-
wait_for_render(self.page, "*", "<input.*?id=['\"]new-task-content['\"].*?>")
|
344
|
-
todo_input = self.page.locator("input")
|
345
|
-
submit_task_button = self.page.locator("button")
|
346
|
-
|
347
|
-
todo_input.type("Fold laundry")
|
348
|
-
submit_task_button.click()
|
349
|
-
|
350
|
-
first_task = self.page.locator("#task-0")
|
351
|
-
assert "Fold laundry" in first_task.inner_text()
|
352
|
-
|
353
|
-
task_checkbox = first_task.locator("input")
|
354
|
-
# Confirm that the new task isn't checked
|
355
|
-
assert not task_checkbox.is_checked()
|
356
|
-
|
357
|
-
# Let's mark it as done now
|
358
|
-
task_checkbox.check()
|
359
|
-
|
360
|
-
# Basic check that the task has the line-through class
|
361
|
-
assert (
|
362
|
-
'<p class="m-0 inline line-through">Fold laundry</p>'
|
363
|
-
in first_task.inner_html()
|
364
|
-
)
|
365
|
-
self.assert_no_banners()
|
366
|
-
self.check_tutor_generated_code(modules_to_check=["./utils.py", "./todo.py"])
|
367
|
-
|
368
|
-
def test_todo_pylist(self):
|
369
|
-
self.goto("examples/todo-pylist.html")
|
370
|
-
self.wait_for_pyscript()
|
371
|
-
assert self.page.title() == "Todo App"
|
372
|
-
wait_for_render(self.page, "*", "<input.*?id=['\"]new-task-content['\"].*?>")
|
373
|
-
todo_input = self.page.locator("input")
|
374
|
-
submit_task_button = self.page.locator("button#new-task-btn")
|
375
|
-
|
376
|
-
todo_input.type("Fold laundry")
|
377
|
-
submit_task_button.click()
|
378
|
-
|
379
|
-
first_task = self.page.locator("div#myList-c-0")
|
380
|
-
assert "Fold laundry" in first_task.inner_text()
|
381
|
-
|
382
|
-
task_checkbox = first_task.locator("input")
|
383
|
-
# Confirm that the new task isn't checked
|
384
|
-
assert not task_checkbox.is_checked()
|
385
|
-
|
386
|
-
# Let's mark it as done now
|
387
|
-
task_checkbox.check()
|
388
|
-
|
389
|
-
# Basic check that the task has the line-through class
|
390
|
-
assert "line-through" in first_task.get_attribute("class")
|
391
|
-
self.assert_no_banners()
|
392
|
-
self.check_tutor_generated_code(modules_to_check=["utils.py"])
|
393
|
-
|
394
|
-
@pytest.mark.xfail(reason="To be moved to collective and updated, see issue #686")
|
395
|
-
def test_toga_freedom(self):
|
396
|
-
self.goto("examples/toga/freedom.html")
|
397
|
-
self.wait_for_pyscript()
|
398
|
-
assert self.page.title() in ["Loading...", "Freedom Units"]
|
399
|
-
wait_for_render(self.page, "*", "<(main|div).*?id=['\"]toga_\\d+['\"].*?>")
|
400
|
-
|
401
|
-
page_content = self.page.content()
|
402
|
-
|
403
|
-
assert "Fahrenheit" in page_content
|
404
|
-
assert "Celsius" in page_content
|
405
|
-
|
406
|
-
self.page.locator("#toga_f_input").fill("105")
|
407
|
-
self.page.locator("button#toga_calculate").click()
|
408
|
-
result = self.page.locator("#toga_c_input")
|
409
|
-
assert "40.555" in result.input_value()
|
410
|
-
self.assert_no_banners()
|
411
|
-
self.check_tutor_generated_code()
|
412
|
-
|
413
|
-
def test_webgl_raycaster_index(self):
|
414
|
-
# XXX improve this test
|
415
|
-
self.goto("examples/webgl/raycaster/index.html")
|
416
|
-
self.wait_for_pyscript()
|
417
|
-
assert self.page.title() == "Raycaster"
|
418
|
-
wait_for_render(self.page, "*", "<canvas.*?>")
|
419
|
-
self.assert_no_banners()
|