diff --git a/django_vite/core/asset_loader.py b/django_vite/core/asset_loader.py index 397b82b..acc57f1 100644 --- a/django_vite/core/asset_loader.py +++ b/django_vite/core/asset_loader.py @@ -33,7 +33,7 @@ class DjangoViteConfig(NamedTuple): dev_server_host: str = "localhost" # Default Vite server port. - dev_server_port: int = 5173 + dev_server_port: int = 3000 # Prefix for STATIC_URL. static_url_prefix: str = "" @@ -720,11 +720,7 @@ def _apply_legacy_django_vite_settings(cls): DeprecationWarning, ) - # Keep same default dev_server_port for legacy users that are still on vite v2. - legacy_config = { - "dev_server_port": 3000, - } - + legacy_config = {} for legacy_setting in applied_legacy_settings: new_config_name = cls.LEGACY_DJANGO_VITE_SETTINGS[legacy_setting] if new_config_name: diff --git a/tests/conftest.py b/tests/conftest.py index 11b10c9..6afbc2b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -from typing import Dict, Any, List +from typing import Dict, Any import pytest from django_vite.core.asset_loader import DjangoViteAssetLoader @@ -13,7 +13,7 @@ def reload_django_vite(): @pytest.fixture() -def patch_settings(settings): +def patch_settings(request, settings): """ 1. Patch new settings into django.conf.settings. 2. Recreate DjangoViteAssetLoader._instance with new settings applied. @@ -31,7 +31,12 @@ def _patch_settings(new_settings: Dict[str, Any]): setattr(settings, key, value) reload_django_vite() - yield _patch_settings + # Apply pytest.mark.parametrize params, if patch_settings was invoked from + # @pytest.mark.parametrize("patch_settings", [param1, param2], indirect=True) + if hasattr(request, "param"): + yield _patch_settings(request.param) + else: + yield _patch_settings for key, value in original_settings_cache.items(): if value == __PYTEST_EMPTY__: @@ -49,11 +54,50 @@ def delete_settings(patch_settings): def _delete_settings(*settings_to_delete: str): new_settings = {key: __PYTEST_DELETE__ for key in settings_to_delete} - patch_settings(new_settings) + return patch_settings(new_settings) return _delete_settings -@pytest.fixture() -def dev_mode_off(patch_settings): - patch_settings({"DJANGO_VITE_DEV_MODE": False}) +@pytest.fixture( + params=[ + { + "DJANGO_VITE_DEV_MODE": False, + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + } + } + }, + ] +) +def patch_dev_mode_false(request, patch_settings): + """ + Run a test with dev_mode=False, parameterized to run under both versions of + settings that we support. + """ + return patch_settings(request.param) + + +@pytest.fixture( + params=[ + { + "DJANGO_VITE_DEV_MODE": True, + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + } + } + }, + ] +) +def patch_dev_mode_true(request, patch_settings): + """ + Run a test with dev_mode=True, parameterized to run under both versions of + settings that we support. + """ + return patch_settings(request.param) diff --git a/tests/settings.py b/tests/settings.py index 4165305..fc86668 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -26,5 +26,3 @@ ] STATIC_ROOT = BASE_DIR / "data" / "staticfiles" - -DJANGO_VITE_DEV_MODE = True diff --git a/tests/tests/templatetags/test_vite_asset.py b/tests/tests/templatetags/test_vite_asset.py index 5ed9834..d2321a0 100644 --- a/tests/tests/templatetags/test_vite_asset.py +++ b/tests/tests/templatetags/test_vite_asset.py @@ -4,6 +4,7 @@ from django_vite.core.exceptions import DjangoViteAssetNotFoundError +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_asset_returns_dev_tags(): template = Template( """ @@ -18,7 +19,7 @@ def test_vite_asset_returns_dev_tags(): assert script_tag["type"] == "module" -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_asset_returns_production_tags(): template = Template( """ @@ -35,6 +36,7 @@ def test_vite_asset_returns_production_tags(): assert len(links) == 13 +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_asset_raises_without_path(): with pytest.raises(TemplateSyntaxError): Template( @@ -45,7 +47,7 @@ def test_vite_asset_raises_without_path(): ) -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_asset_raises_nonexistent_entry(): with pytest.raises(DjangoViteAssetNotFoundError): template = Template( @@ -57,13 +59,37 @@ def test_vite_asset_raises_nonexistent_entry(): template.render(Context({})) -@pytest.mark.parametrize("prefix", ["custom/prefix", "custom/prefix/"]) -def test_vite_asset_dev_prefix(prefix, patch_settings): - patch_settings( +@pytest.mark.parametrize( + "patch_settings", + [ { - "DJANGO_VITE_STATIC_URL_PREFIX": prefix, - } - ) + "DJANGO_VITE_DEV_MODE": True, + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix", + }, + { + "DJANGO_VITE_DEV_MODE": True, + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix/", + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + "static_url_prefix": "custom/prefix", + } + } + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + "static_url_prefix": "custom/prefix/", + } + } + }, + ], + indirect=True, +) +def test_vite_asset_dev_prefix(patch_settings): template = Template( """ {% load django_vite %} @@ -79,14 +105,37 @@ def test_vite_asset_dev_prefix(prefix, patch_settings): assert script_tag["type"] == "module" -@pytest.mark.usefixtures("dev_mode_off") -@pytest.mark.parametrize("prefix", ["custom/prefix", "custom/prefix/"]) -def test_vite_asset_production_prefix(prefix, patch_settings): - patch_settings( +@pytest.mark.parametrize( + "patch_settings", + [ { - "DJANGO_VITE_STATIC_URL_PREFIX": prefix, - } - ) + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix", + }, + { + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix/", + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "static_url_prefix": "custom/prefix", + } + } + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "static_url_prefix": "custom/prefix/", + } + } + }, + ], + indirect=True, +) +def test_vite_asset_production_prefix(patch_settings): template = Template( """ {% load django_vite %} @@ -102,7 +151,7 @@ def test_vite_asset_production_prefix(prefix, patch_settings): assert len(links) == 13 -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_asset_production_staticfiles_storage(patch_settings): patch_settings( { diff --git a/tests/tests/templatetags/test_vite_asset_url.py b/tests/tests/templatetags/test_vite_asset_url.py index acfbdd2..f6972ee 100644 --- a/tests/tests/templatetags/test_vite_asset_url.py +++ b/tests/tests/templatetags/test_vite_asset_url.py @@ -4,6 +4,7 @@ from django_vite.core.exceptions import DjangoViteAssetNotFoundError +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_asset_url_returns_dev_url(): template = Template( """ @@ -17,7 +18,7 @@ def test_vite_asset_url_returns_dev_url(): assert script_tag["src"] == "http://localhost:3000/static/src/entry.ts" -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_asset_url_returns_production_url(): template = Template( """ @@ -31,7 +32,7 @@ def test_vite_asset_url_returns_production_url(): assert script_tag["src"] == "assets/entry-29e38a60.js" -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_asset_url_raises_nonexistent_entry(): with pytest.raises(DjangoViteAssetNotFoundError): template = Template( diff --git a/tests/tests/templatetags/test_vite_hmr_client.py b/tests/tests/templatetags/test_vite_hmr_client.py index 2fee91b..7d5d538 100644 --- a/tests/tests/templatetags/test_vite_hmr_client.py +++ b/tests/tests/templatetags/test_vite_hmr_client.py @@ -3,6 +3,7 @@ from django.template import Context, Template +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_hmr_client_returns_script_tag(): template = Template( """ @@ -17,6 +18,7 @@ def test_vite_hmr_client_returns_script_tag(): assert script_tag["type"] == "module" +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_hmr_client_kwargs(): template = Template( """ @@ -31,8 +33,8 @@ def test_vite_hmr_client_kwargs(): assert script_tag["blocking"] == "render" -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_hmr_client_returns_nothing_with_dev_mode_off(): +@pytest.mark.usefixtures("patch_dev_mode_false") +def test_vite_hmr_client_returns_nothing_with_patch_dev_mode_false(): template = Template( """ {% load django_vite %} @@ -44,17 +46,33 @@ def test_vite_hmr_client_returns_nothing_with_dev_mode_off(): assert str(soup).strip() == "" -def test_vite_hmr_client_uses_correct_settings(patch_settings): - patch_settings( +@pytest.mark.parametrize( + "patch_settings", + [ { + "DJANGO_VITE_DEV_MODE": True, "DJANGO_VITE_DEV_SERVER_PROTOCOL": "https", "DJANGO_VITE_DEV_SERVER_HOST": "127.0.0.2", "DJANGO_VITE_DEV_SERVER_PORT": "5174", - "DJANGO_VITE_STATIC_URL": "static/", + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix", "DJANGO_VITE_WS_CLIENT_URL": "foo/bar", - } - ) - + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + "dev_server_protocol": "https", + "dev_server_host": "127.0.0.2", + "dev_server_port": "5174", + "static_url_prefix": "custom/prefix", + "ws_client_url": "foo/bar", + } + } + }, + ], + indirect=True, +) +def test_vite_hmr_client_uses_correct_settings(patch_settings): template = Template( """ {% load django_vite %} @@ -64,4 +82,4 @@ def test_vite_hmr_client_uses_correct_settings(patch_settings): html = template.render(Context({})) soup = BeautifulSoup(html, "html.parser") script_tag = soup.find("script") - assert script_tag["src"] == "https://127.0.0.2:5174/static/foo/bar" + assert script_tag["src"] == "https://127.0.0.2:5174/static/custom/prefix/foo/bar" diff --git a/tests/tests/templatetags/test_vite_legacy_asset.py b/tests/tests/templatetags/test_vite_legacy_asset.py index aed8dc3..1f02bf9 100644 --- a/tests/tests/templatetags/test_vite_legacy_asset.py +++ b/tests/tests/templatetags/test_vite_legacy_asset.py @@ -4,6 +4,7 @@ from django_vite.core.exceptions import DjangoViteAssetNotFoundError +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_legacy_asset_returns_nothing_with_dev_mode_on(): template = Template( """ @@ -16,14 +17,39 @@ def test_vite_legacy_asset_returns_nothing_with_dev_mode_on(): assert str(soup).strip() == "" -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_legacy_asset_returns_production_tags(patch_settings, settings): - patch_settings( - { - "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT - / "polyfills-manifest.json", - } - ) +@pytest.fixture +def patch_manifest_path(request, settings, patch_settings): + if request.param == "new_settings": + return patch_settings( + { + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + ) + elif request.param == "legacy_settings": + return patch_settings( + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "manifest_path": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + } + } + ) + + +@pytest.mark.parametrize( + "patch_manifest_path", + [ + "new_settings", + "legacy_settings", + ], + indirect=True, +) +def test_vite_legacy_asset_returns_production_tags(patch_manifest_path): template = Template( """ {% load django_vite %} @@ -37,7 +63,7 @@ def test_vite_legacy_asset_returns_production_tags(patch_settings, settings): assert script_tag["nomodule"] == "" -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_legacy_asset_raises_nonexistent_entry(): with pytest.raises(DjangoViteAssetNotFoundError): template = Template( diff --git a/tests/tests/templatetags/test_vite_legacy_polyfills.py b/tests/tests/templatetags/test_vite_legacy_polyfills.py index 70d1292..1f632ca 100644 --- a/tests/tests/templatetags/test_vite_legacy_polyfills.py +++ b/tests/tests/templatetags/test_vite_legacy_polyfills.py @@ -4,6 +4,7 @@ from django_vite.core.exceptions import DjangoViteAssetNotFoundError +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_legacy_polyfills_returns_nothing_with_dev_mode_on(): template = Template( """ @@ -16,14 +17,39 @@ def test_vite_legacy_polyfills_returns_nothing_with_dev_mode_on(): assert str(soup).strip() == "" -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_legacy_polyfills_production(patch_settings, settings): - patch_settings( - { - "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT - / "polyfills-manifest.json", - } - ) +@pytest.fixture +def patch_manifest_path(request, settings, patch_settings): + if request.param == "new_settings": + return patch_settings( + { + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + ) + elif request.param == "legacy_settings": + return patch_settings( + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "manifest_path": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + } + } + ) + + +@pytest.mark.parametrize( + "patch_manifest_path", + [ + "new_settings", + "legacy_settings", + ], + indirect=True, +) +def test_vite_legacy_polyfills_production(patch_manifest_path): template = Template( """ {% load django_vite %} @@ -37,15 +63,41 @@ def test_vite_legacy_polyfills_production(patch_settings, settings): assert script_tag["nomodule"] == "" -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_legacy_polyfills_custom_motif(patch_settings, settings): - patch_settings( - { - "DJANGO_VITE_LEGACY_POLYFILLS_MOTIF": "custom-motif", - "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT - / "custom-motif-polyfills-manifest.json", - } - ) +@pytest.fixture +def patch_manifest_path_custom_motif(request, settings, patch_settings): + if request.param == "new_settings": + return patch_settings( + { + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_LEGACY_POLYFILLS_MOTIF": "custom-motif", + "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT + / "custom-motif-polyfills-manifest.json", + } + ) + elif request.param == "legacy_settings": + return patch_settings( + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "legacy_polyfills_motif": "custom-motif", + "manifest_path": settings.STATIC_ROOT + / "custom-motif-polyfills-manifest.json", + } + } + } + ) + + +@pytest.mark.parametrize( + "patch_manifest_path_custom_motif", + [ + "new_settings", + "legacy_settings", + ], + indirect=True, +) +def test_vite_legacy_polyfills_custom_motif(patch_manifest_path_custom_motif): template = Template( """ {% load django_vite %} @@ -59,15 +111,41 @@ def test_vite_legacy_polyfills_custom_motif(patch_settings, settings): assert script_tag["nomodule"] == "" -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_legacy_polyfills_nonexistent_motif(patch_settings, settings): - patch_settings( - { - "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT - / "polyfills-manifest.json", - "DJANGO_VITE_LEGACY_POLYFILLS_MOTIF": "fake-legacy-polyfills", - } - ) +@pytest.fixture +def patch_manifest_path_bad_motif(request, settings, patch_settings): + if request.param == "new_settings": + return patch_settings( + { + "DJANGO_VITE_DEV_MODE": False, + "DJANGO_VITE_LEGACY_POLYFILLS_MOTIF": "fake-legacy-polyfills", + "DJANGO_VITE_MANIFEST_PATH": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + ) + elif request.param == "legacy_settings": + return patch_settings( + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "legacy_polyfills_motif": "fake-legacy-polyfills", + "manifest_path": settings.STATIC_ROOT + / "polyfills-manifest.json", + } + } + } + ) + + +@pytest.mark.parametrize( + "patch_manifest_path_bad_motif", + [ + "new_settings", + "legacy_settings", + ], + indirect=True, +) +def test_vite_legacy_polyfills_nonexistent_motif(patch_manifest_path_bad_motif): with pytest.raises(DjangoViteAssetNotFoundError): template = Template( """ diff --git a/tests/tests/templatetags/test_vite_preload_asset.py b/tests/tests/templatetags/test_vite_preload_asset.py index fdebc19..967024e 100644 --- a/tests/tests/templatetags/test_vite_preload_asset.py +++ b/tests/tests/templatetags/test_vite_preload_asset.py @@ -4,6 +4,7 @@ from django_vite.core.exceptions import DjangoViteAssetNotFoundError +@pytest.mark.usefixtures("patch_dev_mode_true") def test_preload_vite_asset_returns_nothing_with_dev_mode_on(): template = Template( """ @@ -16,7 +17,7 @@ def test_preload_vite_asset_returns_nothing_with_dev_mode_on(): assert str(soup).strip() == "" -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_preload_vite_asset_returns_production_tags(): template = Template( """ @@ -33,7 +34,7 @@ def test_preload_vite_asset_returns_production_tags(): assert first_link["rel"] == ["modulepreload"] -@pytest.mark.usefixtures("dev_mode_off") +@pytest.mark.usefixtures("patch_dev_mode_false") def test_vite_preload_asset_raises_nonexistent_entry(): with pytest.raises(DjangoViteAssetNotFoundError): template = Template( diff --git a/tests/tests/templatetags/test_vite_react_refresh.py b/tests/tests/templatetags/test_vite_react_refresh.py index e2c31e7..3f07b84 100644 --- a/tests/tests/templatetags/test_vite_react_refresh.py +++ b/tests/tests/templatetags/test_vite_react_refresh.py @@ -3,6 +3,7 @@ from django.template import Context, Template +@pytest.mark.usefixtures("patch_dev_mode_true") def test_vite_react_refresh_returns_script_tag(): template = Template( """ @@ -20,17 +21,33 @@ def test_vite_react_refresh_returns_script_tag(): assert "http://localhost:3000/static/@react-refresh" in script_tag.text -def test_vite_react_refresh_uses_correct_settings(patch_settings): - patch_settings( +@pytest.mark.parametrize( + "patch_settings", + [ { + "DJANGO_VITE_DEV_MODE": True, "DJANGO_VITE_DEV_SERVER_PROTOCOL": "https", "DJANGO_VITE_DEV_SERVER_HOST": "127.0.0.2", "DJANGO_VITE_DEV_SERVER_PORT": "5174", - "DJANGO_VITE_STATIC_URL": "static/", + "DJANGO_VITE_STATIC_URL_PREFIX": "custom/prefix", "DJANGO_VITE_REACT_REFRESH_URL": "foo/bar", - } - ) - + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + "dev_server_protocol": "https", + "dev_server_host": "127.0.0.2", + "dev_server_port": "5174", + "static_url_prefix": "custom/prefix", + "react_refresh_url": "foo/bar", + } + } + }, + ], + indirect=True, +) +def test_vite_react_refresh_uses_correct_settings(patch_settings): template = Template( """ {% load django_vite %} @@ -44,11 +61,11 @@ def test_vite_react_refresh_uses_correct_settings(patch_settings): assert script_tag.has_attr("type") assert script_tag["type"] == "module" assert "__vite_plugin_react_preamble_installed__" in script_tag.text - assert "https://127.0.0.2:5174/static/foo/bar" in script_tag.text + assert "https://127.0.0.2:5174/static/custom/prefix/foo/bar" in script_tag.text -@pytest.mark.usefixtures("dev_mode_off") -def test_vite_react_refresh_returns_nothing_with_dev_mode_off(): +@pytest.mark.usefixtures("patch_dev_mode_false") +def test_vite_react_refresh_returns_nothing_with_patch_dev_mode_false(): template = Template( """ {% load django_vite %} @@ -60,8 +77,25 @@ def test_vite_react_refresh_returns_nothing_with_dev_mode_off(): assert str(soup).strip() == "" +@pytest.mark.parametrize( + "patch_settings", + [ + { + "DJANGO_VITE_DEV_MODE": True, + "DJANGO_VITE_REACT_REFRESH_URL": "foobar", + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": True, + "react_refresh_url": "foobar", + } + } + }, + ], + indirect=True, +) def test_vite_react_refresh_url_setting(patch_settings): - patch_settings({"DJANGO_VITE_REACT_REFRESH_URL": "foobar"}) template = Template( """ {% load django_vite %} diff --git a/tests/tests/test_asset_loader.py b/tests/tests/test_asset_loader.py index 1fa9ccc..9087f58 100644 --- a/tests/tests/test_asset_loader.py +++ b/tests/tests/test_asset_loader.py @@ -9,34 +9,41 @@ def test_django_vite_asset_loader_cannot_be_instantiated(): DjangoViteAssetLoader() -def test_check_loader_instance_happy(patch_settings): - patch_settings( - { - "DJANGO_VITE_DEV_MODE": False, - } - ) +@pytest.mark.usefixtures("patch_dev_mode_false") +def test_check_loader_instance_happy(): warnings = DjangoViteAssetLoader.instance().check() assert len(warnings) == 0 -def test_check_loader_instance_warnings(patch_settings): - patch_settings( +@pytest.mark.parametrize( + "patch_settings", + [ { "DJANGO_VITE_DEV_MODE": False, "DJANGO_VITE_MANIFEST_PATH": "fake.json", - } - ) + }, + { + "DJANGO_VITE": { + "default": { + "dev_mode": False, + "manifest_path": "fake.json", + } + } + }, + ], + indirect=True, +) +def test_check_loader_instance_warnings(patch_settings): warnings = DjangoViteAssetLoader.instance().check() assert len(warnings) == 1 assert "Make sure you have generated a manifest file" in warnings[0].hint -def test_apply_fallback(delete_settings): +def test_apply_fallback(): """ Test that a fallback "default" app is made even when there are no DJANGO_VITE settings defined. """ - delete_settings("DJANGO_VITE_DEV_MODE") default_app = DjangoViteAssetLoader.instance()._apps["default"] assert default_app assert default_app._config == DjangoViteConfig() diff --git a/tests/tests/test_multi_app.py b/tests/tests/test_multi_app.py deleted file mode 100644 index e69de29..0000000