mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 10:17:23 -05:00
* Revise display module. TODO: more comprehensive tests. Especially around mimebundles. * Markdown corrections in example code in display.py docstrings. * Minor adjustments and a much more comprehensive test-suite for the display module. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Updated docstring in __init__.py. * Remove unused imports and black-ify the source. * Refactor, docs and tests for the Event class in events.py. * Refactored, simplified and documented @when decorator. * Extensive test suite for @when decorator. * Documentation and minor refactoring of the fetch.py module. TODO: Check tests. * Refactored and more comprehensive tests for the fetch module. * Add/clarify Event related interactions. Thanks @Neon22 for the suggestion. * Refactor, document ffi.py module. * More complete passing tests for ffi.py. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add docstrings to flatted.py. Since this is actually an external(ish) module, tests for it should be in the external repository from which this code is derived. * Minor docstring cleanup in ffi.py. * Added docstrings and clarifications to fs.py. * Add very limited test suite for fs.py. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Rename magic_js.py to context.py, add comprehensive docstrings, and rename certain internal things for readability and comprehension. * Fix dict check in ffi.py. * Rename test_js_modules to test_context. * Fix test configuration aftert rename. * Docs and refactor of media.py. * Comprehensive tests for media.py. * Refactor and docstrings for storage.py * Appease the ruff gods. * Further storage.py changes and a more complete test suite for storage. * Refactor and docstrings for the util.py module. Fixed a problem with is_awaitable not handling async bound methods. * More comprehensive test suite for util.py. Updated to latest upytest. * A major refactoring, documenting and simplification of the web.py module substantially reducing it in size and complexity with only a few minor (edge) behavioural changes. Softly breaking changes include: - An element's classes are just a set. - An element's styles are just a dict. - Explicitly use `update_all` with ElementCollections (simpler and greater flexibility). - Extract a child element by id with `my_container["#an-id"]` * Updates and additions for a more comprehensive test suite for the web.py module. All code paths are exercised and checked. * Black tidy-ups in test suite. * Refactor and documentation for websocket.py module. * Tests for websocket.py. Disabled due to playwright flakiness, but they all pass in a local browser. * Refactor and documentation of workers.py module. * Added tests for workers.py module. Updated related test suite to account for the new named worker in the test HTML. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Refactor away remaining "is not None" not caught before. * Remove check-docstring-first because it interferes with the auto-generated documentation (where triple quoted strings are used to document module attributes). * Careful Markdown changes so the docstrings render properly in the PyScript docs. * Typo correction. * More typo corrections and clarifications. * Add clarification about SVG handling to _render_image docstring. * Add DOM event options to the @when decorator (with new tests to exercise this functionality). * Fixes default value for options if no options passed into @when. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
280 lines
7.4 KiB
Python
280 lines
7.4 KiB
Python
"""
|
|
Exercise the pyscript.Websocket class.
|
|
"""
|
|
|
|
import asyncio
|
|
import upytest
|
|
|
|
from pyscript import WebSocket
|
|
|
|
|
|
# Websocket tests are disabled by default because they don't reliably work in
|
|
# playwright based tests. Feel free to set this to False to enable them when
|
|
# running tests locally in an actual browser (they all pass there).
|
|
SKIP_WEBSOCKET_TESTS = True
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_with_attributes():
|
|
"""
|
|
Event handlers assigned via object attributes.
|
|
|
|
The Websocket class should be able to connect to a websocket server and
|
|
send and receive messages.
|
|
|
|
Use of echo.websocket.org means:
|
|
|
|
1) When connecting it responds with a "Request served by" message.
|
|
2) When sending a message it echos it back.
|
|
"""
|
|
connected_flag = False
|
|
closed_flag = False
|
|
messages = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def on_open(event):
|
|
nonlocal connected_flag
|
|
connected_flag = True
|
|
ws.send("Hello, world!") # A message to echo.
|
|
|
|
def on_message(event):
|
|
messages.append(event.data)
|
|
if len(messages) == 2: # We're done.
|
|
ws.close()
|
|
|
|
def on_close(event):
|
|
nonlocal closed_flag
|
|
closed_flag = True
|
|
ready_to_test.set() # Finished!
|
|
|
|
ws = WebSocket(url="wss://echo.websocket.org")
|
|
ws.onopen = on_open
|
|
ws.onmessage = on_message
|
|
ws.onclose = on_close
|
|
# Wait for everything to be finished.
|
|
await ready_to_test.wait()
|
|
assert connected_flag is True
|
|
assert len(messages) == 2
|
|
assert "request served by" in messages[0].lower()
|
|
assert messages[1] == "Hello, world!"
|
|
assert closed_flag is True
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_with_init():
|
|
"""
|
|
Event handlers assigned via __init__ arguments.
|
|
|
|
The Websocket class should be able to connect to a websocket server and
|
|
send and receive messages.
|
|
|
|
Use of echo.websocket.org means:
|
|
|
|
1) When connecting it responds with a "Request served by" message.
|
|
2) When sending a message it echos it back.
|
|
"""
|
|
connected_flag = False
|
|
closed_flag = False
|
|
messages = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def on_open(event):
|
|
nonlocal connected_flag
|
|
connected_flag = True
|
|
ws.send("Hello, world!") # A message to echo.
|
|
|
|
def on_message(event):
|
|
messages.append(event.data)
|
|
if len(messages) == 2: # We're done.
|
|
ws.close()
|
|
|
|
def on_close(event):
|
|
nonlocal closed_flag
|
|
closed_flag = True
|
|
ready_to_test.set() # Finished!
|
|
|
|
ws = WebSocket(
|
|
url="wss://echo.websocket.org",
|
|
onopen=on_open,
|
|
onmessage=on_message,
|
|
onclose=on_close,
|
|
)
|
|
# Wait for everything to be finished.
|
|
await ready_to_test.wait()
|
|
assert connected_flag is True
|
|
assert len(messages) == 2
|
|
assert "request served by" in messages[0].lower()
|
|
assert messages[1] == "Hello, world!"
|
|
assert closed_flag is True
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_async_handlers():
|
|
"""
|
|
Async event handlers should work correctly.
|
|
"""
|
|
messages = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
async def on_open(event):
|
|
await asyncio.sleep(0)
|
|
ws.send("async test")
|
|
|
|
async def on_message(event):
|
|
await asyncio.sleep(0)
|
|
messages.append(event.data)
|
|
if len(messages) == 2:
|
|
ws.close()
|
|
|
|
async def on_close(event):
|
|
await asyncio.sleep(0)
|
|
ready_to_test.set()
|
|
|
|
ws = WebSocket(
|
|
url="wss://echo.websocket.org",
|
|
onopen=on_open,
|
|
onmessage=on_message,
|
|
onclose=on_close,
|
|
)
|
|
|
|
await ready_to_test.wait()
|
|
assert len(messages) == 2
|
|
assert messages[1] == "async test"
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_binary_data_conversion():
|
|
"""
|
|
WebSocket should convert binary data to memoryview for Python.
|
|
"""
|
|
messages = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def on_open(event):
|
|
# Send binary data as bytearray.
|
|
binary_data = bytearray([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
ws.send(binary_data)
|
|
|
|
def on_message(event):
|
|
messages.append(event.data)
|
|
if len(messages) == 2:
|
|
ws.close()
|
|
|
|
def on_close(event):
|
|
ready_to_test.set()
|
|
|
|
ws = WebSocket(
|
|
url="wss://echo.websocket.org",
|
|
onopen=on_open,
|
|
onmessage=on_message,
|
|
onclose=on_close,
|
|
)
|
|
|
|
await ready_to_test.wait()
|
|
assert len(messages) == 2
|
|
# Verify wrapper converts binary to memoryview Python type.
|
|
assert isinstance(messages[1], memoryview)
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_send_bytes_conversion():
|
|
"""
|
|
WebSocket send should convert Python bytes to JS Uint8Array.
|
|
"""
|
|
messages = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def on_open(event):
|
|
# Test that bytes are converted properly.
|
|
ws.send(bytes([0x41, 0x42, 0x43]))
|
|
|
|
def on_message(event):
|
|
messages.append(event.data)
|
|
if len(messages) == 2:
|
|
ws.close()
|
|
|
|
def on_close(event):
|
|
ready_to_test.set()
|
|
|
|
ws = WebSocket(
|
|
url="wss://echo.websocket.org",
|
|
onopen=on_open,
|
|
onmessage=on_message,
|
|
onclose=on_close,
|
|
)
|
|
|
|
await ready_to_test.wait()
|
|
assert len(messages) == 2
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_event_wrapper():
|
|
"""
|
|
WebSocketEvent wrapper should provide access to event properties.
|
|
"""
|
|
event_types = []
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def on_open(event):
|
|
event_types.append(event.type)
|
|
ws.send("test")
|
|
|
|
def on_message(event):
|
|
event_types.append(event.type)
|
|
# Verify event wrapper exposes properties.
|
|
assert hasattr(event, "data")
|
|
assert hasattr(event, "type")
|
|
if len(event_types) >= 2:
|
|
ws.close()
|
|
|
|
def on_close(event):
|
|
event_types.append(event.type)
|
|
ready_to_test.set()
|
|
|
|
ws = WebSocket(
|
|
url="wss://echo.websocket.org",
|
|
onopen=on_open,
|
|
onmessage=on_message,
|
|
onclose=on_close,
|
|
)
|
|
|
|
await ready_to_test.wait()
|
|
assert "open" in event_types
|
|
assert "message" in event_types
|
|
assert "close" in event_types
|
|
|
|
|
|
@upytest.skip("Websocket tests are disabled.", skip_when=SKIP_WEBSOCKET_TESTS)
|
|
async def test_websocket_reassign_handler():
|
|
"""
|
|
Event handlers should be replaceable after creation.
|
|
"""
|
|
first_handler_called = False
|
|
second_handler_called = False
|
|
ready_to_test = asyncio.Event()
|
|
|
|
def first_handler(event):
|
|
nonlocal first_handler_called
|
|
first_handler_called = True
|
|
|
|
def second_handler(event):
|
|
nonlocal second_handler_called
|
|
second_handler_called = True
|
|
ws.close()
|
|
|
|
def on_open(event):
|
|
# Replace the message handler before any messages arrive.
|
|
ws.onmessage = second_handler
|
|
ws.send("test")
|
|
|
|
def on_close(event):
|
|
ready_to_test.set()
|
|
|
|
ws = WebSocket(url="wss://echo.websocket.org", onopen=on_open, onclose=on_close)
|
|
ws.onmessage = first_handler
|
|
|
|
await ready_to_test.wait()
|
|
# Verify that handler replacement worked.
|
|
assert first_handler_called is False
|
|
assert second_handler_called is True
|