From bcf9ca169cf7fa2602483f5ee43e7ad67bcdb470 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 02:25:39 -0700 Subject: [PATCH 01/10] feat(vite): re-export ViteConfig from vite package root --- fastapi_startkit/.coverage | Bin 0 -> 135168 bytes .../src/fastapi_startkit/vite/__init__.py | 2 ++ fastapi_startkit/tests/vite/test_vite.py | 23 ++++++++++++++++++ fastapi_startkit/uv.lock | 2 +- 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 fastapi_startkit/.coverage diff --git a/fastapi_startkit/.coverage b/fastapi_startkit/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..43962310e710cee54d1a3fd7dd67c66a7959a8cf GIT binary patch literal 135168 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 VnwQJU4%PqF)w+KheK(D?{|BYq{tEyA literal 0 HcmV?d00001 diff --git a/fastapi_startkit/src/fastapi_startkit/vite/__init__.py b/fastapi_startkit/src/fastapi_startkit/vite/__init__.py index 4447516b..dab671ad 100644 --- a/fastapi_startkit/src/fastapi_startkit/vite/__init__.py +++ b/fastapi_startkit/src/fastapi_startkit/vite/__init__.py @@ -1,10 +1,12 @@ from .vite import Vite +from .config.vite import ViteConfig from .providers.provider import ViteProvider from .template import Template, template from .exceptions import ViteException, ViteManifestNotFoundException __all__ = [ "Vite", + "ViteConfig", "ViteProvider", "Template", "template", diff --git a/fastapi_startkit/tests/vite/test_vite.py b/fastapi_startkit/tests/vite/test_vite.py index b7cb6a11..e5973984 100644 --- a/fastapi_startkit/tests/vite/test_vite.py +++ b/fastapi_startkit/tests/vite/test_vite.py @@ -298,3 +298,26 @@ def test_flush_clears_preloaded_assets(self, tmp_path): vite("resources/js/app.js") vite.flush() assert vite.preloaded_assets() == {} + + +# --------------------------------------------------------------------------- +# Package-root re-exports +# --------------------------------------------------------------------------- + + +class TestViteConfigExport: + def test_viteconfig_importable_from_package_root(self): + from fastapi_startkit.vite import ViteConfig + + assert ViteConfig is not None + + def test_viteconfig_is_same_class_as_config_module(self): + from fastapi_startkit.vite import ViteConfig + from fastapi_startkit.vite.config.vite import ViteConfig as ConfigViteConfig + + assert ViteConfig is ConfigViteConfig + + def test_viteconfig_in_package_all(self): + import fastapi_startkit.vite as vite_pkg + + assert "ViteConfig" in vite_pkg.__all__ diff --git a/fastapi_startkit/uv.lock b/fastapi_startkit/uv.lock index de9262fe..8b674dea 100644 --- a/fastapi_startkit/uv.lock +++ b/fastapi_startkit/uv.lock @@ -593,7 +593,7 @@ wheels = [ [[package]] name = "fastapi-startkit" -version = "0.44.0" +version = "0.45.0" source = { editable = "." } dependencies = [ { name = "cleo" }, From 18c95021caca6d8f46d8289a04898a0b70adb26c Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 09:42:29 -0700 Subject: [PATCH 02/10] refactor(vite-app): move templates to resources/templates and use provider default Move the example templates into resources/templates to match ViteConfig's default templates_directory, and drop the bootstrap override so the example relies on ViteProvider's auto-bound Jinja2Templates engine. --- example/vite-app/bootstrap/application.py | 4 ++-- example/vite-app/{ => resources}/templates/index.html | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename example/vite-app/{ => resources}/templates/index.html (100%) diff --git a/example/vite-app/bootstrap/application.py b/example/vite-app/bootstrap/application.py index 0fbc882a..1572a5fe 100644 --- a/example/vite-app/bootstrap/application.py +++ b/example/vite-app/bootstrap/application.py @@ -12,7 +12,7 @@ LogProvider, FastAPIProvider, # ViteProvider auto-binds a Jinja2Templates engine (with the vite() - # globals injected) at the configured templates directory. - (ViteProvider, {"templates_directory": "templates"}), + # globals injected) from resources/templates, its default directory. + ViteProvider, ], ) diff --git a/example/vite-app/templates/index.html b/example/vite-app/resources/templates/index.html similarity index 100% rename from example/vite-app/templates/index.html rename to example/vite-app/resources/templates/index.html From 6d3d7f1ed08c762cb68ed7375501d1024141c40d Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 10:27:31 -0700 Subject: [PATCH 03/10] refactor(vite-app): resolve templates via canonical app accessor Use `from fastapi_startkit.application import app` -> app().make('templates') in the example route instead of the bootstrap module, matching the framework's canonical app accessor (no top-level export). --- example/vite-app/routes/web.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/example/vite-app/routes/web.py b/example/vite-app/routes/web.py index 73b952b1..063e1854 100644 --- a/example/vite-app/routes/web.py +++ b/example/vite-app/routes/web.py @@ -1,14 +1,15 @@ -from fastapi import APIRouter +from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse -from fastapi_startkit.vite import template +from fastapi_startkit.application import app web = APIRouter() @web.get("/", response_class=HTMLResponse) -async def index(): - return template("index.html") +async def index(request: Request): + templates = app().make("templates") + return templates.TemplateResponse(request, "index.html") @web.get("/api/health") From 685ec7223bb993ed902e9a11838afcd9988c5b35 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 10:33:28 -0700 Subject: [PATCH 04/10] refactor(vite-app): move providers into app/ package Relocate providers/ to app/providers/ and update the bootstrap import, grouping application code under the app/ namespace. --- example/vite-app/app/__init__.py | 0 example/vite-app/app/providers/__init__.py | 0 example/vite-app/{ => app}/providers/fastapi_provider.py | 0 example/vite-app/bootstrap/application.py | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 example/vite-app/app/__init__.py create mode 100644 example/vite-app/app/providers/__init__.py rename example/vite-app/{ => app}/providers/fastapi_provider.py (100%) diff --git a/example/vite-app/app/__init__.py b/example/vite-app/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/example/vite-app/app/providers/__init__.py b/example/vite-app/app/providers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/example/vite-app/providers/fastapi_provider.py b/example/vite-app/app/providers/fastapi_provider.py similarity index 100% rename from example/vite-app/providers/fastapi_provider.py rename to example/vite-app/app/providers/fastapi_provider.py diff --git a/example/vite-app/bootstrap/application.py b/example/vite-app/bootstrap/application.py index 1572a5fe..7b66c145 100644 --- a/example/vite-app/bootstrap/application.py +++ b/example/vite-app/bootstrap/application.py @@ -4,7 +4,7 @@ from fastapi_startkit.logging import LogProvider from fastapi_startkit.vite import ViteProvider -from providers.fastapi_provider import FastAPIProvider +from app.providers.fastapi_provider import FastAPIProvider app: Application = Application( base_path=Path(__file__).resolve().parent.parent, From 6217d9413ddfaf2696bd41a9a90d0b6d9d8663fb Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 10:33:33 -0700 Subject: [PATCH 05/10] test(vite-app): add simple HTTP tests for web routes Add HttpTestCase-based tests covering the health endpoint and the index page render (templates resolve from resources/templates with vite globals). Wire up pytest config and dev dependencies. --- example/vite-app/pyproject.toml | 3 ++ example/vite-app/pytest.ini | 3 ++ example/vite-app/tests/__init__.py | 0 example/vite-app/tests/test_case.py | 14 ++++++ example/vite-app/tests/test_web.py | 31 ++++++++++++ example/vite-app/uv.lock | 75 +++++++++++++++++++++++++++-- 6 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 example/vite-app/pytest.ini create mode 100644 example/vite-app/tests/__init__.py create mode 100644 example/vite-app/tests/test_case.py create mode 100644 example/vite-app/tests/test_web.py diff --git a/example/vite-app/pyproject.toml b/example/vite-app/pyproject.toml index d11352a4..1ea54589 100644 --- a/example/vite-app/pyproject.toml +++ b/example/vite-app/pyproject.toml @@ -14,4 +14,7 @@ fastapi-startkit = { path = "../../fastapi_startkit", editable = true } [dependency-groups] dev = [ "dumpdie>=1.5.0", + "httpx>=0.28.1", + "pytest>=9.0.3", + "pytest-asyncio>=1.3.0", ] diff --git a/example/vite-app/pytest.ini b/example/vite-app/pytest.ini new file mode 100644 index 00000000..82bc8d15 --- /dev/null +++ b/example/vite-app/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +asyncio_mode = auto +pythonpath = . diff --git a/example/vite-app/tests/__init__.py b/example/vite-app/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/example/vite-app/tests/test_case.py b/example/vite-app/tests/test_case.py new file mode 100644 index 00000000..c3319011 --- /dev/null +++ b/example/vite-app/tests/test_case.py @@ -0,0 +1,14 @@ +from abc import ABC +from typing import TYPE_CHECKING + +from fastapi_startkit.testing import TestCase as BaseTestCase + +if TYPE_CHECKING: + from fastapi_startkit.application import Application + + +class TestCase(BaseTestCase, ABC): + def get_application(self) -> "Application": + from bootstrap.application import app + + return app diff --git a/example/vite-app/tests/test_web.py b/example/vite-app/tests/test_web.py new file mode 100644 index 00000000..f8718f7f --- /dev/null +++ b/example/vite-app/tests/test_web.py @@ -0,0 +1,31 @@ +from pathlib import Path + +from fastapi_startkit.fastapi.testing import HttpTestCase + +from tests.test_case import TestCase + + +class TestWebRoutes(TestCase, HttpTestCase): + async def test_health_endpoint_returns_ok(self): + response = await self.get("/api/health") + + response.assert_ok() + assert response.json() == {"status": "healthy"} + + async def test_index_page_renders(self): + # vite() needs a built manifest or the dev-server hot file; write the + # hot file (Vite reads public/hot relative to the cwd) so the template's + # vite('resources/js/app.ts') directive resolves in dev mode. + hot_file = Path("public") / "hot" + hot_file.parent.mkdir(parents=True, exist_ok=True) + hot_file.write_text("http://localhost:5173") + try: + response = await self.get("/") + finally: + hot_file.unlink(missing_ok=True) + + response.assert_ok() + body = response.text + assert "FastAPI StartKit" in body + assert "resources/js/app.ts" in body + assert "{{ vite" not in body diff --git a/example/vite-app/uv.lock b/example/vite-app/uv.lock index 47c56698..52df7eb7 100644 --- a/example/vite-app/uv.lock +++ b/example/vite-app/uv.lock @@ -280,7 +280,7 @@ wheels = [ [[package]] name = "fastapi-startkit" -version = "0.26.0" +version = "0.45.0" source = { editable = "../../fastapi_startkit" } dependencies = [ { name = "cleo" }, @@ -305,23 +305,26 @@ vite = [ requires-dist = [ { name = "aiomysql", marker = "extra == 'mysql'", specifier = ">=0.2.0" }, { name = "aiosqlite", marker = "extra == 'sqlite'", specifier = ">=0.22.1" }, + { name = "anthropic", marker = "extra == 'ai'", specifier = ">=0.49.0" }, { name = "asyncpg", marker = "extra == 'postgres'", specifier = ">=0.29.0" }, { name = "cleo", specifier = ">=2.1.0,<3.0.0" }, { name = "dotenv", specifier = ">=0.9.9" }, { name = "dotty-dict", specifier = ">=1.3.1" }, { name = "faker", marker = "extra == 'database'", specifier = ">=40.13.0" }, { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.124.4,<0.125.0" }, + { name = "google-generativeai", marker = "extra == 'ai'", specifier = ">=0.8.0" }, { name = "inflection", specifier = ">=0.5.1" }, { name = "itsdangerous", marker = "extra == 'fastapi'", specifier = ">=2.2.0" }, { name = "jinja2", marker = "extra == 'inertia'", specifier = ">=3.1" }, { name = "jinja2", marker = "extra == 'vite'", specifier = ">=3.1" }, { name = "markupsafe", marker = "extra == 'inertia'", specifier = ">=2.0" }, + { name = "openai", marker = "extra == 'ai'", specifier = ">=1.0.0" }, { name = "pendulum", specifier = ">=3.1.0,<4.0.0" }, { name = "pydantic", specifier = ">=2.12.5" }, { name = "requests", specifier = ">=2.32.5,<3.0.0" }, { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'database'", specifier = ">=2.0.38" }, ] -provides-extras = ["fastapi", "database", "sqlite", "postgres", "mysql", "vite", "inertia"] +provides-extras = ["fastapi", "database", "sqlite", "postgres", "mysql", "vite", "inertia", "ai"] [package.metadata.requires-dev] dev = [ @@ -329,10 +332,12 @@ dev = [ { name = "aiosqlite", specifier = ">=0.22.1" }, { name = "asyncpg", specifier = ">=0.29.0" }, { name = "dumpdie", specifier = ">=1.5.0" }, + { name = "faker", specifier = ">=40.13.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.124.4" }, { name = "itsdangerous", specifier = ">=2.2.0" }, { name = "pytest", specifier = ">=9.0.3" }, { name = "pytest-asyncio", specifier = ">=1.3.0" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, { name = "ruff", specifier = ">=0.9.0" }, { name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0.38" }, { name = "twine", specifier = ">=6.2.0" }, @@ -494,6 +499,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454, upload-time = "2020-08-22T08:16:27.816Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "itsdangerous" version = "2.2.0" @@ -599,6 +613,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + [[package]] name = "pendulum" version = "3.2.0" @@ -642,6 +665,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/fb/d65db067a67df7252f18b0cb7420dda84078b9e8bfb375215469c14a50be/pendulum-3.2.0-py3-none-any.whl", hash = "sha256:f3a9c18a89b4d9ef39c5fa6a78722aaff8d5be2597c129a3b16b9f40a561acf3", size = 114111, upload-time = "2026-01-30T11:22:22.361Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pydantic" version = "2.13.3" @@ -746,6 +778,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1161,6 +1222,9 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "dumpdie" }, + { name = "httpx" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, ] [package.metadata] @@ -1170,7 +1234,12 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "dumpdie", specifier = ">=1.5.0" }] +dev = [ + { name = "dumpdie", specifier = ">=1.5.0" }, + { name = "httpx", specifier = ">=0.28.1" }, + { name = "pytest", specifier = ">=9.0.3" }, + { name = "pytest-asyncio", specifier = ">=1.3.0" }, +] [[package]] name = "watchfiles" From 7c0fc933273ef63f8eb0ebf21f66f6cbf4c31936 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 10:34:51 -0700 Subject: [PATCH 06/10] chore: drop accidental .coverage binary and ignore coverage artifacts --- .gitignore | 4 ++++ fastapi_startkit/.coverage | Bin 135168 -> 0 bytes 2 files changed, 4 insertions(+) delete mode 100644 fastapi_startkit/.coverage diff --git a/.gitignore b/.gitignore index ee65e917..5a93aab3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ **/.env **/*.sqlite **/*.vite +**/.coverage +**/.coverage.* +**/htmlcov/ +**/coverage.xml fastapi_startkit/dist fastapi_startkit.github.io.git laravel-repo diff --git a/fastapi_startkit/.coverage b/fastapi_startkit/.coverage deleted file mode 100644 index 43962310e710cee54d1a3fd7dd67c66a7959a8cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135168 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 VnwQJU4%PqF)w+KheK(D?{|BYq{tEyA From e129d9aea877a2be992b231f6297a0f4b776e5a7 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 12:08:36 -0700 Subject: [PATCH 07/10] test(vite-app): remove hot file workaround from index page test Rely on the built manifest so the vite() directive resolves to production asset URLs, and drop the dev-server hot file setup. Assert against the built /build/assets/ output instead of the source path. Also remove the stale ViteProvider comment in bootstrap. --- example/vite-app/bootstrap/application.py | 2 -- example/vite-app/tests/test_web.py | 15 ++------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/example/vite-app/bootstrap/application.py b/example/vite-app/bootstrap/application.py index 7b66c145..4cde13a8 100644 --- a/example/vite-app/bootstrap/application.py +++ b/example/vite-app/bootstrap/application.py @@ -11,8 +11,6 @@ providers=[ LogProvider, FastAPIProvider, - # ViteProvider auto-binds a Jinja2Templates engine (with the vite() - # globals injected) from resources/templates, its default directory. ViteProvider, ], ) diff --git a/example/vite-app/tests/test_web.py b/example/vite-app/tests/test_web.py index f8718f7f..3cf46835 100644 --- a/example/vite-app/tests/test_web.py +++ b/example/vite-app/tests/test_web.py @@ -1,5 +1,3 @@ -from pathlib import Path - from fastapi_startkit.fastapi.testing import HttpTestCase from tests.test_case import TestCase @@ -13,19 +11,10 @@ async def test_health_endpoint_returns_ok(self): assert response.json() == {"status": "healthy"} async def test_index_page_renders(self): - # vite() needs a built manifest or the dev-server hot file; write the - # hot file (Vite reads public/hot relative to the cwd) so the template's - # vite('resources/js/app.ts') directive resolves in dev mode. - hot_file = Path("public") / "hot" - hot_file.parent.mkdir(parents=True, exist_ok=True) - hot_file.write_text("http://localhost:5173") - try: - response = await self.get("/") - finally: - hot_file.unlink(missing_ok=True) + response = await self.get("/") response.assert_ok() body = response.text assert "FastAPI StartKit" in body - assert "resources/js/app.ts" in body + assert "/build/assets/" in body assert "{{ vite" not in body From 161f1fc5176841a5a307e2ab20acbceb23b6ebf5 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 12:09:18 -0700 Subject: [PATCH 08/10] test(vite-app): rename test_web to test_web_routes Match the routes/web.py module and the TestWebRoutes class it covers. --- example/vite-app/tests/{test_web.py => test_web_routes.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename example/vite-app/tests/{test_web.py => test_web_routes.py} (100%) diff --git a/example/vite-app/tests/test_web.py b/example/vite-app/tests/test_web_routes.py similarity index 100% rename from example/vite-app/tests/test_web.py rename to example/vite-app/tests/test_web_routes.py From b8cc904da3bca5deeb6019e9873aa4df1ffcfc39 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 12:09:43 -0700 Subject: [PATCH 09/10] test(vite-app): drop asset and vite directive assertions Keep the index page test focused on a successful render. --- example/vite-app/tests/test_web_routes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/example/vite-app/tests/test_web_routes.py b/example/vite-app/tests/test_web_routes.py index 3cf46835..0e33a082 100644 --- a/example/vite-app/tests/test_web_routes.py +++ b/example/vite-app/tests/test_web_routes.py @@ -16,5 +16,3 @@ async def test_index_page_renders(self): response.assert_ok() body = response.text assert "FastAPI StartKit" in body - assert "/build/assets/" in body - assert "{{ vite" not in body From c2d3814e82a69e6f41e8a1a939cc41c76243ea9e Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Sat, 20 Jun 2026 12:10:58 -0700 Subject: [PATCH 10/10] test(vite-app): rename TestWebRoutes to TestHomeController --- example/vite-app/tests/test_web_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/vite-app/tests/test_web_routes.py b/example/vite-app/tests/test_web_routes.py index 0e33a082..521c7412 100644 --- a/example/vite-app/tests/test_web_routes.py +++ b/example/vite-app/tests/test_web_routes.py @@ -3,7 +3,7 @@ from tests.test_case import TestCase -class TestWebRoutes(TestCase, HttpTestCase): +class TestHomeController(TestCase, HttpTestCase): async def test_health_endpoint_returns_ok(self): response = await self.get("/api/health")