django-ninja icon indicating copy to clipboard operation
django-ninja copied to clipboard

[BUG] Cannot use Django's Test Client when Ninja TestClient is used in a pytest suite

Open arpanpreneur opened this issue 8 months ago • 3 comments

Describe the bug I have the following pytest tests, running in the same order as below. The first one uses the NinjaTestClient. Once this client1.get("/whoami", user=simple_user) is executed, the next test using Django Test Client fails with the exception Router@'/access-control/' has already been attached to API NinjaAPI:1.0.0. The stack trace is also pasted below.

from ninja.testing import TestClient as NinjaTestClient
...

@pytest.mark.django_db
def test_api_whoami_happy_path(simple_user):
    assert True
    client1 = NinjaTestClient(router)

    response_happy: NinjaResponse = client1.get("/whoami", user=simple_user)
    assert response_happy.status_code == 200

    user: AppUserResponseSchema = AppUserResponseSchema.model_validate(
        response_happy.json()
    )
    assert user.id == simple_user.id

    response_sad: NinjaResponse = client1.get("/whoami")
    assert response_sad.status_code == 401

@pytest.mark.django_db
def test_authenticated_tenanted_request(
    client: DjangoTestClient,
    simple_user: AppUser,
    simple_tenant: AppTenant,
    fake_token_generator: FakeAuth0TokenGenerator,
):
    simple_tenant.app_users.add(simple_user)
    access_token = fake_token_generator.get_fake_token_for_user(simple_user)

    response: HttpResponse = client.get(
        "/api/v1/access-control/tenant/access-check",
        HTTP_AUTHORIZATION=f"Bearer {access_token}",
        HTTP_TENANT_ID=f"{simple_tenant.id}",
    )

    assert response.status_code == 200

    response_data = response.json()
    parsed_data = TenantedAccessCheckResponseSchema.model_validate(response_data)

    assert parsed_data.app_tenant.id == simple_tenant.id
    assert parsed_data.app_user.id == simple_user.id

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <ninja.router.Router object at 0x109b1a490>, prefix = '/access-control/'

    def build_routers(self, prefix: str) -> List[Tuple[str, "Router"]]:
        if self.api is not None:
            from ninja.main import debug_server_url_reimport
    
            if not debug_server_url_reimport():
>               raise ConfigError(
                    f"Router@'{prefix}' has already been attached to API"
                    f" {self.api.title}:{self.api.version} "
                )
E               ninja.errors.ConfigError: Router@'/access-control/' has already been attached to API NinjaAPI:1.0.0

../../../Library/Caches/pypoetry/virtualenvs/some-backend-adgzL-V0-py3.11/lib/python3.11/site-packages/ninja/router.py:367: ConfigError

Versions (please complete the following information):

  • Python version: 3.11
  • Django version: '4.2.13'
  • Django-Ninja version: '1.1.0'
  • Pydantic version: '2.7.4'

arpanpreneur avatar Jun 17 '24 19:06 arpanpreneur