From 5ce4215d5a50b386926e010589adb7ec13676eeb Mon Sep 17 00:00:00 2001 From: euri10 Date: Sat, 9 Mar 2024 14:28:23 +0100 Subject: [PATCH] attempt at sse e2e --- pdm.lock | 92 ++++++++++++++++++++++++++++++++++++++-- pyproject.toml | 32 +++++++------- tests/e2e/test_sse_js.py | 81 +++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 tests/e2e/test_sse_js.py diff --git a/pdm.lock b/pdm.lock index 8c5337b7d0..7051bb183c 100644 --- a/pdm.lock +++ b/pdm.lock @@ -4,8 +4,8 @@ [metadata] groups = ["default", "standard", "jwt", "pydantic", "cli", "picologging", "dev-contrib", "piccolo", "prometheus", "dev", "mako", "test", "brotli", "cryptography", "linting", "attrs", "opentelemetry", "docs", "redis", "sqlalchemy", "full", "annotated-types", "jinja", "structlog", "minijinja"] strategy = ["cross_platform"] -lock_version = "4.4.1" -content_hash = "sha256:d15ae45eac6b6d77a630838b16d3e06192941b526fb6c53b46cf78bd7400d394" +lock_version = "4.4" +content_hash = "sha256:6b781ddc144caaccbb002e9d55c3e7966e0e18ce7234d44d5c8ef60b1c750378" [[package]] name = "accessible-pygments" @@ -2169,6 +2169,25 @@ files = [ {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] +[[package]] +name = "playwright" +version = "1.42.0" +requires_python = ">=3.8" +summary = "A high-level API to automate web browsers" +dependencies = [ + "greenlet==3.0.3", + "pyee==11.0.1", +] +files = [ + {file = "playwright-1.42.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:e2b293f077efeaa45253fde31cea4bc6b0ae8be6b5e65e8ce8b4aa3b9f0d55b6"}, + {file = "playwright-1.42.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:283887f0bdd0039c3d720e32fbc73a045c24fa800599a6ad60fb199c29580534"}, + {file = "playwright-1.42.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:4e1fc1c049a0af64626ddd50814d14a01f316bcbb4d1aa83c3416fe420add558"}, + {file = "playwright-1.42.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:313f2551a772f57c9ccca017c4dd4661f2277166f9e1d84bbf5a2e316f0f892c"}, + {file = "playwright-1.42.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2a46a24641e5d468046cde567c98fdb8d85e32df901630b14dfb288cbd1ed4f"}, + {file = "playwright-1.42.0-py3-none-win32.whl", hash = "sha256:dbf473496808d4c2c816902c1dee2aabc029648e56ce8514b643f5a1a6fc8e22"}, + {file = "playwright-1.42.0-py3-none-win_amd64.whl", hash = "sha256:e092c6cfbf797bff03fbdfc53c3e6a9e29fbcf6b82f9e43113d37494aee0561b"}, +] + [[package]] name = "pluggy" version = "1.4.0" @@ -2607,6 +2626,19 @@ files = [ {file = "pydata_sphinx_theme-0.14.4.tar.gz", hash = "sha256:f5d7a2cb7a98e35b9b49d3b02cec373ad28958c2ed5c9b1ffe6aff6c56e9de5b"}, ] +[[package]] +name = "pyee" +version = "11.0.1" +requires_python = ">=3.8" +summary = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own" +dependencies = [ + "typing-extensions", +] +files = [ + {file = "pyee-11.0.1-py3-none-any.whl", hash = "sha256:9bcc9647822234f42c228d88de63d0f9ffa881e87a87f9d36ddf5211f6ac977d"}, + {file = "pyee-11.0.1.tar.gz", hash = "sha256:a642c51e3885a33ead087286e35212783a4e9b8d6514a10a5db4e57ac57b2b29"}, +] + [[package]] name = "pygments" version = "2.17.2" @@ -2750,6 +2782,20 @@ files = [ {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, ] +[[package]] +name = "pytest-base-url" +version = "2.1.0" +requires_python = ">=3.8" +summary = "pytest plugin for URL based testing" +dependencies = [ + "pytest>=7.0.0", + "requests>=2.9", +] +files = [ + {file = "pytest_base_url-2.1.0-py3-none-any.whl", hash = "sha256:3ad15611778764d451927b2a53240c1a7a591b521ea44cebfe45849d2d2812e6"}, + {file = "pytest_base_url-2.1.0.tar.gz", hash = "sha256:02748589a54f9e63fcbe62301d6b0496da0d10231b753e950c63e03aee745d45"}, +] + [[package]] name = "pytest-cov" version = "4.1.0" @@ -2789,6 +2835,22 @@ files = [ {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, ] +[[package]] +name = "pytest-playwright" +version = "0.4.4" +requires_python = ">=3.8" +summary = "A pytest wrapper with fixtures for Playwright to automate web browsers" +dependencies = [ + "playwright>=1.18", + "pytest-base-url<3.0.0,>=1.0.0", + "pytest<9.0.0,>=6.2.4", + "python-slugify<9.0.0,>=6.0.0", +] +files = [ + {file = "pytest-playwright-0.4.4.tar.gz", hash = "sha256:5488db4cc49028491c5130af0a2bb6b1d0b222a202217f6d14491d4c9aa67ff9"}, + {file = "pytest_playwright-0.4.4-py3-none-any.whl", hash = "sha256:df306f3a60a8631a3cfde1b95a2ed5a89203a3408dfa1154de049ca7de87c90b"}, +] + [[package]] name = "pytest-rerunfailures" version = "13.0" @@ -2867,6 +2929,19 @@ files = [ {file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"}, ] +[[package]] +name = "python-slugify" +version = "8.0.4" +requires_python = ">=3.7" +summary = "A Python slugify application that also handles Unicode" +dependencies = [ + "text-unidecode>=1.3", +] +files = [ + {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, + {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, +] + [[package]] name = "pytz" version = "2024.1" @@ -3430,7 +3505,7 @@ version = "2.0.25" requires_python = ">=3.7" summary = "Database Abstraction Library" dependencies = [ - "greenlet!=0.4.17; platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\"", + "greenlet!=0.4.17; platform_machine == \"aarch64\" or (platform_machine == \"ppc64le\" or (platform_machine == \"x86_64\" or (platform_machine == \"amd64\" or (platform_machine == \"AMD64\" or (platform_machine == \"win32\" or platform_machine == \"WIN32\")))))", "typing-extensions>=4.6.0", ] files = [ @@ -3538,6 +3613,15 @@ files = [ {file = "taskgroup-0.0.0a4.tar.gz", hash = "sha256:eb08902d221e27661950f2a0320ddf3f939f579279996f81fe30779bca3a159c"}, ] +[[package]] +name = "text-unidecode" +version = "1.3" +summary = "The most basic Text::Unidecode port" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + [[package]] name = "time-machine" version = "2.13.0" @@ -3890,7 +3974,7 @@ dependencies = [ "python-dotenv>=0.13", "pyyaml>=5.1", "uvicorn==0.27.1", - "uvloop!=0.15.0,!=0.15.1,>=0.14.0; (sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\"", + "uvloop!=0.15.0,!=0.15.1,>=0.14.0; sys_platform != \"win32\" and (sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\")", "watchfiles>=0.13", "websockets>=10.4", ] diff --git a/pyproject.toml b/pyproject.toml index ee1e2920be..c70f399b46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,26 +108,28 @@ include = [ '/CHANGELOG.rst', ] + [tool.pdm] ignore_package_warnings = ["sphinx", "slotscheck"] [tool.pdm.dev-dependencies] dev = [ - "beanie>=1.21.0", - "beautifulsoup4", - "fsspec", - "greenlet", - "hypothesis", - "python-dotenv", - "starlette", - "trio", - "aiosqlite", - "asyncpg>=0.29.0", - "psycopg[pool,binary]>=3.1.10", - "psycopg2-binary", - "psutil>=5.9.8", - "hypercorn>=0.16.0", - "daphne>=4.0.0", + "beanie>=1.21.0", + "beautifulsoup4", + "fsspec", + "greenlet", + "hypothesis", + "python-dotenv", + "starlette", + "trio", + "aiosqlite", + "asyncpg>=0.29.0", + "psycopg[pool,binary]>=3.1.10", + "psycopg2-binary", + "psutil>=5.9.8", + "hypercorn>=0.16.0", + "daphne>=4.0.0", + "pytest-playwright>=0.4.4", ] dev-contrib = ["opentelemetry-sdk", "httpx-sse"] docs = [ diff --git a/tests/e2e/test_sse_js.py b/tests/e2e/test_sse_js.py new file mode 100644 index 0000000000..9666ba260b --- /dev/null +++ b/tests/e2e/test_sse_js.py @@ -0,0 +1,81 @@ +import asyncio +from contextlib import asynccontextmanager +from pathlib import Path +from typing import AsyncIterator + +from playwright.async_api import async_playwright +from uvicorn.config import Config +from uvicorn.server import Server + +from litestar import Litestar, get +from litestar.config.cors import CORSConfig +from litestar.response import ServerSentEvent, ServerSentEventMessage +from litestar.types import SSEData + + +@get("/test_sse_empty") +async def handler() -> ServerSentEvent: + async def generate() -> AsyncIterator[SSEData]: + event = ServerSentEventMessage(event="empty") + yield event + + return ServerSentEvent(generate()) + + +html = """ + + +

Server-Sent Events

+
+ + +""" + + +@asynccontextmanager +async def run_server(config: Config, sockets=None): + server = Server(config=config) + task = asyncio.create_task(server.serve(sockets=sockets)) + await asyncio.sleep(0.1) + try: + yield server + finally: + await server.shutdown() + task.cancel() + + +async def test_get_started_link(tmp_path: Path) -> None: + app = Litestar(route_handlers=[handler], cors_config=CORSConfig(allow_origins=["*"])) + index = tmp_path / "index.html" + index.write_text(html) + async with run_server(config=Config(app=app, port=8765, lifespan="off")): + async with async_playwright() as p: + browser = await p.chromium.launch() + page = await browser.new_page() + await page.goto(f"file://{index.as_posix()}") + # Click the get started link.# + output_div_content = await page.query_selector("div#output") + print(await output_div_content.inner_text()) + await browser.close()