Skip to content

Commit 8a445bf

Browse files
committed
test use_effect + remove Ref.set method
1 parent 663f4a4 commit 8a445bf

File tree

7 files changed

+140
-23
lines changed

7 files changed

+140
-23
lines changed

idom/core/hooks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,10 @@ def use_memo(
236236
if memo.empty():
237237
# we need to initialize on the first run
238238
changed = True
239-
memo.args = args
239+
memo.args = () if args is None else args
240240
elif (
241241
args is None
242-
or len(memo.args) != args
242+
or len(memo.args) != len(args)
243243
or any(current is not new for current, new in zip(memo.args, args))
244244
):
245245
memo.args = args

idom/utils.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ class Ref(Generic[_Current]):
2525
def __init__(self, initial_value: _Current) -> None:
2626
self.current = initial_value
2727

28-
def set(self, value: _Current) -> None:
29-
self.current = value
30-
return None
31-
3228
def __eq__(self, other: Any) -> bool:
3329
return isinstance(other, Ref) and (other.current == self.current)
3430

tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,11 @@ class ServerSavesLastError(server_type):
221221
"""A per-client-state server that updates the ``last_server_error`` fixture"""
222222

223223
async def _run_renderer(self, *args, **kwargs):
224-
self._config["last_server_error"].set(None)
224+
self._config["last_server_error"].current = None
225225
try:
226226
await super()._run_renderer(*args, **kwargs)
227227
except Exception as e:
228-
self._config["last_server_error"].set(e)
228+
self._config["last_server_error"].current = e
229229

230230
return ServerSavesLastError
231231

@@ -261,7 +261,7 @@ def last_server_error():
261261

262262
@pytest.fixture(autouse=True)
263263
def _clean_last_server_error(last_server_error) -> Iterator[None]:
264-
last_server_error.set(default_error)
264+
last_server_error.current = default_error
265265
yield
266266

267267

tests/test_core/test_hooks.py

Lines changed: 132 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def test_simple_input_with_use_state(driver, display):
231231
@idom.element
232232
async def Input(message=None):
233233
message, set_message = idom.hooks.use_state(message)
234-
message_ref.set(message)
234+
message_ref.current = message
235235

236236
async def on_change(event):
237237
if event["value"] == "this is a test":
@@ -251,21 +251,143 @@ async def on_change(event):
251251
assert message_ref.current == "this is a test"
252252

253253

254-
def test_use_effect_callback_occurs_after_full_layout_update_is_complete():
255-
# TODO: right now it runs after the element is rendered, not the full layout update
256-
assert False
254+
async def test_use_effect_callback_occurs_after_full_render_is_complete():
255+
effect_triggered = idom.Ref(False)
256+
effect_triggers_after_final_render = idom.Ref(None)
257257

258+
@idom.element
259+
async def OuterElement():
260+
return idom.html.div(
261+
ElementWithEffect(),
262+
CheckNoEffectYet(),
263+
)
258264

259-
def test_use_effect_cleanup_occurs_on_will_render():
260-
assert False
265+
@idom.element
266+
async def ElementWithEffect():
267+
@idom.hooks.use_effect
268+
def effect():
269+
effect_triggered.current = True
261270

271+
return idom.html.div()
262272

263-
def test_use_effect_cleanup_occurs_on_will_unmount():
264-
assert False
273+
@idom.element
274+
async def CheckNoEffectYet():
275+
effect_triggers_after_final_render.current = not effect_triggered.current
276+
return idom.html.div()
265277

278+
async with idom.Layout(OuterElement()) as layout:
279+
await layout.render()
266280

267-
def test_use_effect_memoization():
268-
assert False
281+
assert effect_triggered.current
282+
assert effect_triggers_after_final_render.current is not None
283+
assert effect_triggers_after_final_render.current
284+
285+
286+
async def test_use_effect_cleanup_occurs_on_will_render():
287+
element_hook = idom.Ref(None)
288+
cleanup_triggered = idom.Ref(False)
289+
cleanup_triggered_before_next_render = idom.Ref(False)
290+
291+
@idom.element
292+
async def ElementWithEffect():
293+
element_hook.current = idom.hooks.current_hook()
294+
if cleanup_triggered.current:
295+
cleanup_triggered_before_next_render.current = True
296+
297+
@idom.hooks.use_effect
298+
def effect():
299+
def cleanup():
300+
cleanup_triggered.current = True
301+
302+
return cleanup
303+
304+
return idom.html.div()
305+
306+
async with idom.Layout(ElementWithEffect()) as layout:
307+
await layout.render()
308+
309+
assert not cleanup_triggered.current
310+
311+
element_hook.current.schedule_render()
312+
await layout.render()
313+
314+
assert cleanup_triggered.current
315+
assert cleanup_triggered_before_next_render.current
316+
317+
318+
async def test_use_effect_cleanup_occurs_on_will_unmount():
319+
outer_element_hook = idom.Ref(None)
320+
cleanup_triggered = idom.Ref(False)
321+
cleanup_triggered_before_next_render = idom.Ref(False)
322+
323+
@idom.element
324+
async def OuterElement():
325+
outer_element_hook.current = idom.hooks.current_hook()
326+
if cleanup_triggered.current:
327+
cleanup_triggered_before_next_render.current = True
328+
return ElementWithEffect()
329+
330+
@idom.element
331+
async def ElementWithEffect():
332+
@idom.hooks.use_effect
333+
def effect():
334+
def cleanup():
335+
cleanup_triggered.current = True
336+
337+
return cleanup
338+
339+
return idom.html.div()
340+
341+
async with idom.Layout(OuterElement()) as layout:
342+
await layout.render()
343+
344+
assert not cleanup_triggered.current
345+
346+
outer_element_hook.current.schedule_render()
347+
await layout.render()
348+
349+
assert cleanup_triggered.current
350+
assert cleanup_triggered_before_next_render.current
351+
352+
353+
async def test_use_effect_memoization():
354+
element_hook = idom.Ref(None)
355+
set_state_callback = idom.Ref(None)
356+
effect_run_count = idom.Ref(0)
357+
358+
first_value = 1
359+
second_value = 2
360+
361+
@idom.element
362+
async def ElementWithMemoizedEffect():
363+
element_hook.current = idom.hooks.current_hook()
364+
state, set_state_callback.current = idom.hooks.use_state(first_value)
365+
366+
@idom.hooks.use_effect(args=[state])
367+
def effect():
368+
effect_run_count.current += 1
369+
370+
return idom.html.div()
371+
372+
async with idom.Layout(ElementWithMemoizedEffect()) as layout:
373+
await layout.render()
374+
375+
assert effect_run_count.current == 1
376+
377+
element_hook.current.schedule_render()
378+
await layout.render()
379+
380+
assert effect_run_count.current == 1
381+
382+
set_state_callback.current(second_value)
383+
await layout.render()
384+
385+
assert effect_run_count.current == 2
386+
387+
element_hook.current.schedule_render()
388+
await layout.render()
389+
390+
assert effect_run_count.current == 2
269391

270392

271393
def test_use_reducer():

tests/test_core/test_layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ async def test_simple_layout():
6161
@idom.element
6262
async def SimpleElement(tag):
6363
tag, set_tag = idom.hooks.use_state(tag)
64-
set_state_hook.set(set_tag)
64+
set_state_hook.current = set_tag
6565
return idom.vdom(tag)
6666

6767
element = SimpleElement("div")

tests/test_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
def test_basic_ref_behavior():
88
r = idom.Ref(None)
9-
r.set("new_1")
109
assert r.current == "new_1"
1110
r.current = "new_2"
1211
assert r.current == "new_2"

tests/test_widgets/test_jupyter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_cross_origin_jupyter_display(server, driver, driver_wait, mount, server
3939
async def SimpleButton():
4040
@idom.event
4141
async def on_click(event):
42-
clicked.set(True)
42+
clicked.current = True
4343

4444
return idom.html.button(
4545
{"id": "simple-button", "onClick": on_click}, "click me cross origin"
@@ -88,7 +88,7 @@ def test_same_origin_jupyter_display(driver, driver_wait, mount, server_url):
8888
async def SimpleButton():
8989
@idom.event
9090
async def on_click(event):
91-
clicked.set(True)
91+
clicked.current = True
9292

9393
return idom.html.button(
9494
{"id": "simple-button", "onClick": on_click}, "click me same origin"

0 commit comments

Comments
 (0)