def test_run_in_executor(driver, display): parent_thread = idom.Var(None) count_thread = idom.Var(None) @idom.element async def Main(self): parent_thread.set(current_thread()) return CounterOnClick() @idom.element(run_in_executor=True) async def CounterOnClick(self, count=0): count_thread.set(current_thread()) @idom.event async def increment(event): self.update(count + 1) return idom.html.div( idom.html.button({ "onClick": increment, "id": "button" }, "click to increment"), idom.html.p({"id": f"count-{count}"}, f"count: {count}"), ) display(Main) button = driver.find_element_by_id("button") driver.find_element_by_id("count-0") button.click() driver.find_element_by_id("count-1") assert parent_thread.get() != count_thread.get()
async def DragDropBoxes(self): last_owner = idom.Var(None) last_hover = idom.Var(None) h1 = Holder("filled", last_owner, last_hover) h2 = Holder("empty", last_owner, last_hover) h3 = Holder("empty", last_owner, last_hover) last_owner.set(h1) style = idom.html.style([ """ .holder { height: 150px; width: 150px; margin: 20px; display: inline-block; } .holder-filled { border: solid 10px black; background-color: black; } .holder-hover { border: dotted 5px black; } .holder-empty { border: solid 5px black; background-color: white; } """ ]) return idom.html.div([style, h1, h2, h3])
def __init__(self, grid_size, block_size): self.snake = [] self.grid = Grid(grid_size, block_size) self.new_direction = idom.Var(Directions.ArrowRight) self.old_direction = idom.Var(Directions.ArrowRight) self.food = idom.Var(None) self.won = idom.Var(False) self.lost = idom.Var(False)
def test_spinner_display_terminal(capsys): done = Event() display_count = idom.Var(0) class MySpinner(Spinner): def _display_terminal(self, frame, text): if display_count.value < 3 or frame in ( self.success_frame, self.failure_frame, None, ): super()._display_terminal(frame, text) display_count.value += 1 else: done.set() spinner = MySpinner( "my spinner", frames=[". ", ".. ", "..."], success_frame="success", failure_frame="failure", rate=0, ) with spinner: done.wait() captured = capsys.readouterr() expected = ". my spinner\x1b[K\r.. my spinner\x1b[K\r... my spinner\x1b[K\rsuccess my spinner\x1b[K\r\n" assert captured.out == expected
def test_simple_click_event(driver, display): clicked = idom.Var(False) @idom.element async def Button(self): async def on_click(event): clicked.set(True) self.update() if not clicked.get(): return idom.html.button({ "onClick": on_click, "id": "click" }, ["Click Me!"]) else: return idom.html.p({"id": "complete"}, ["Complete"]) display(Button) button = driver.find_element_by_id("click") button.click() driver.find_element_by_id("complete") # we care what happens in the final delete when there's no value assert clicked.get()
def test_cross_origin_jupyter_display(server, driver, driver_wait, mount, server_url): clicked = idom.Var(False) # we use flask here just because its easier to set up in a thread flask_host = "127.0.0.1" flask_port = find_available_port(flask_host) flask_server_url = f"http://{flask_host}:{flask_port}/" @idom.element async def SimpleButton(self): @idom.event async def on_click(event): clicked.set(True) return idom.html.button({ "id": "simple-button", "onClick": on_click }, "click me cross origin") def run(): """Runs flask using the JuptyerDisplay client""" flask_app = flask.Flask(__name__) @flask_app.route("/") def widget(): widget = JupyterDisplay(server_url) return widget._repr_html_() @flask_app.route("/shutdown") def shutdown(): stop = flask.request.environ.get("werkzeug.server.shutdown") stop() flask_app.run(host=flask_host, port=flask_port, debug=False) thread = Thread(target=run, daemon=True) thread.start() time.sleep(1) # wait for server to start mount(SimpleButton) # switch to flask widget view driver.get(flask_server_url) client_button = driver.find_element_by_id("simple-button") client_button.click() driver_wait.until(lambda d: clicked.get()) driver.get(f"{flask_server_url}/shutdown")
def test_spinner_display_notebook(mocker): done = Event() display_count = idom.Var(0) class MySpinner(Spinner): def _display_notebook(self, frame, text): if display_count.value < 3 or frame in ( self.success_frame, self.failure_frame, None, ): super()._display_notebook(frame, text) display_count.value += 1 else: done.set() @staticmethod def _running_in_notebook(): return True displays = [] class Handle: def update(self, value): displays.append(value._repr_html_()) mocker.patch("IPython.display.display", side_effect=lambda *a, **kw: Handle()) spinner = MySpinner( "my spinner", frames=[". ", ".. ", "..."], success_frame="success", failure_frame="failure", rate=0, ) with spinner: done.wait() assert displays == [ "<pre><code>. my spinner<code></pre>", "<pre><code>.. my spinner<code></pre>", "<pre><code>... my spinner<code></pre>", "<pre><code>success my spinner<code></pre>", ]
async def ButtonSwapsDivs(self): count = idom.Var(0) @idom.event async def on_click(event): count.value += 1 mount(idom.html.div, {"id": f"hotswap-{count.value}"}, count.value) incr = idom.html.button({ "onClick": on_click, "id": "incr-button" }, "incr") mount, make_hostswap = idom.widgets.hotswap(shared=True) mount(idom.html.div, {"id": f"hotswap-{count.value}"}, count.value) hotswap_view = make_hostswap() return idom.html.div(incr, hotswap_view)
def test_same_origin_jupyter_display(driver, driver_wait, mount, server_url): clicked = idom.Var(False) @idom.element async def SimpleButton(self): @idom.event async def on_click(event): clicked.set(True) return idom.html.button({ "id": "simple-button", "onClick": on_click }, "click me same origin") mount(SimpleButton) driver.get(f"{server_url}/__test_jupyter_widget_client__") client_button = driver.find_element_by_id("simple-button") client_button.click() driver_wait.until(lambda d: clicked.get())
def test_simple_input(driver, display): message = idom.Var(None) @idom.element async def Input(self): async def on_change(event): if event["value"] == "this is a test": message.set(event["value"]) self.update() if message.get() is None: return idom.html.input({"id": "input", "onChange": on_change}) else: return idom.html.p({"id": "complete"}, ["Complete"]) display(Input) button = driver.find_element_by_id("input") button.send_keys("this is a test") driver.find_element_by_id("complete") assert message.get() == "this is a test"
def test_var_set(): v = idom.Var() old_1 = v.set("new_1") assert old_1 is idom.Var.empty old_2 = v.set("new_2") assert old_2 == "new_1"
def display_id() -> idom.Var[int]: return idom.Var(0)
def test_var_equivalence(): r1 = idom.Var([1, 2, 3]) r2 = idom.Var([1, 2, 3]) assert r1 == r2
def test_var_get(): v = idom.Var(None) assert v.get() is None v.set(1) assert v.get() == 1
def test_var_set(): v = idom.Var(None) old_1 = v.set("new_1") assert old_1 is None old_2 = v.set("new_2") assert old_2 == "new_1"
def last_server_error(): """A ``Var`` containing the last server error. This must be populated by ``server_type``""" return idom.Var(default_error)
def test_var_get(): v = idom.Var() assert v.get() is idom.Var.empty v.set(1) assert v.get() == 1
import time import pytest from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import Options import idom # Default is an error because we want to know whether we are setting the last # error while testing. A refactor could miss the code path that catches serve # errors. default_error = NotImplementedError() last_server_error = idom.Var(default_error) class ServerWithErrorCatch(idom.server.sanic.PerClientState): async def _stream(self, request, socket): last_server_error.set(None) try: await super()._stream(request, socket) except Exception as e: last_server_error.set(e) def pytest_addoption(parser): parser.addoption( "--headless", action="store_true", help="Whether to run browser tests in headless mode.",