import base64
import io
import os
import re
import time
import numpy as np
import pytest
from PIL import Image
from .support import ROOT, PyScriptTest, wait_for_render
@pytest.mark.usefixtures("chdir")
class TestExamples(PyScriptTest):
"""
Each example requires the same three tests:
- Test that the initial markup loads properly (currently done by
testing the
tag's content)
- Testing that pyscript is loading properly
- Testing that the page contains appropriate content after rendering
"""
@pytest.fixture()
def chdir(self):
# make sure that the http server serves from the right directory
ROOT.join("pyscriptjs").chdir()
def test_hello_world(self):
self.goto("examples/hello_world.html")
self.wait_for_pyscript()
assert self.page.title() == "PyScript Hello World"
content = self.page.content()
pattern = "\\d+/\\d+/\\d+, \\d+:\\d+:\\d+" # e.g. 08/09/2022 15:57:32
assert re.search(pattern, content)
self.assert_no_banners()
self.check_tutor_generated_code()
def test_simple_clock(self):
self.goto("examples/simple_clock.html")
self.wait_for_pyscript()
assert self.page.title() == "Simple Clock Demo"
pattern = r"\d{2}/\d{2}/\d{4}, \d{2}:\d{2}:\d{2}"
# run for 5 seconds to be sure that we see the page with "It's
# espresso time!"
for _ in range(5):
content = self.page.inner_html("#outputDiv2")
if re.match(pattern, content) and int(content[-1]) in (0, 4, 8):
assert self.page.inner_html("#outputDiv3") == "It's espresso time!"
break
else:
time.sleep(1)
else:
raise AssertionError("Espresso time not found :(")
self.assert_no_banners()
self.check_tutor_generated_code()
def test_altair(self):
self.goto("examples/altair.html")
self.wait_for_pyscript()
assert self.page.title() == "Altair"
wait_for_render(self.page, "*", '')
save_as_png_link = self.page.locator("text=Save as PNG")
see_source_link = self.page.locator("text=View Source")
# These shouldn't be visible since we didn't click the menu
assert not save_as_png_link.is_visible()
assert not see_source_link.is_visible()
self.page.locator("summary").click()
# Let's confirm that the links are visible now after clicking the menu
assert save_as_png_link.is_visible()
assert see_source_link.is_visible()
self.assert_no_banners()
self.check_tutor_generated_code()
def test_antigravity(self):
self.goto("examples/antigravity.html")
self.wait_for_pyscript()
assert self.page.title() == "Antigravity"
# confirm that svg added to page
wait_for_render(self.page, "*", '')
# Get svg layer of flying character
char = self.page.wait_for_selector("#python")
assert char is not None
# check that character moves in negative-y direction over time
ycoord_pattern = r"translate\(-?\d*\.\d*,\s(?P-?[\d.]+)\)"
starting_y_coord = float(
re.match(ycoord_pattern, char.get_attribute("transform")).group("ycoord")
)
time.sleep(2)
later_y_coord = float(
re.match(ycoord_pattern, char.get_attribute("transform")).group("ycoord")
)
assert later_y_coord < starting_y_coord
self.check_tutor_generated_code(modules_to_check=["antigravity.py"])
def test_bokeh(self):
# XXX improve this test
self.goto("examples/bokeh.html")
self.wait_for_pyscript(timeout=90 * 1000)
assert self.page.title() == "Bokeh Example"
wait_for_render(self.page, "*", '')
self.assert_no_banners()
self.check_tutor_generated_code()
def test_bokeh_interactive(self):
# XXX improve this test
self.goto("examples/bokeh_interactive.html")
self.wait_for_pyscript(timeout=90 * 1000)
assert self.page.title() == "Bokeh Example"
wait_for_render(self.page, "*", '')
self.assert_no_banners()
self.check_tutor_generated_code()
@pytest.mark.skip("flaky, see issue 759")
def test_d3(self):
self.goto("examples/d3.html")
self.wait_for_pyscript()
assert (
self.page.title() == "d3: JavaScript & PyScript visualizations side-by-side"
)
wait_for_render(self.page, "*", "")
assert "PyScript version" in self.page.content()
pyscript_chart = self.page.wait_for_selector("#py")
# Let's simply assert that the text of the chart is as expected which
# means that the chart rendered successfully and with the right text
assert "š21\nš13\nš8\nš5\nš3\nš2\nš1\nš1" in pyscript_chart.inner_text()
self.assert_no_banners()
self.check_tutor_generated_code(modules_to_check=["d3.py"])
def test_folium(self):
self.goto("examples/folium.html")
self.wait_for_pyscript()
assert self.page.title() == "Folium"
wait_for_render(self.page, "*", "
# * #Hello world!
self.goto("examples/markdown-plugin.html")
self.wait_for_pyscript()
# ASSERT title is rendered correctly
assert self.page.title() == "PyMarkdown"
# ASSERT markdown is rendered to the corresponding HTML tag
wait_for_render(self.page, "*", "Hello world!
")
self.check_tutor_generated_code()
def test_matplotlib(self):
self.goto("examples/matplotlib.html")
self.wait_for_pyscript()
assert self.page.title() == "Matplotlib"
wait_for_render(self.page, "*", "
> img")
img_src = test.get_attribute("src").replace(
"data:image/png;charset=utf-8;base64,", ""
)
# Finally, let's get the np array from the previous data
img_data = np.asarray(Image.open(io.BytesIO(base64.b64decode(img_src))))
with Image.open(
os.path.join(os.path.dirname(__file__), "test_assets", "tripcolor.png"),
) as image:
ref_data = np.asarray(image)
# Now that we have both images data as a numpy array
# let's confirm that they are the same
deviation = np.mean(np.abs(img_data - ref_data))
assert deviation == 0.0
self.assert_no_banners()
self.check_tutor_generated_code()
def test_numpy_canvas_fractals(self):
self.goto("examples/numpy_canvas_fractals.html")
self.wait_for_pyscript()
assert (
self.page.title()
== "Visualization of Mandelbrot, Julia and Newton sets with NumPy and HTML5 canvas"
)
wait_for_render(
self.page, "*", ""
)
# Assert that we get the title and canvas for each element
mandelbrot = self.page.wait_for_selector("#mandelbrot")
assert "Mandelbrot set" in mandelbrot.inner_text()
assert "