Skip to main content

How-To: Testing JIT Discovery & Namespacing

Because the DiscoveryClient and PluginRegistry are singletons, state isolation is the most critical factor when writing unit and integration tests in the macroservice architecture.

1. Mandatory State Reset

To prevent discovery state from leaking between tests, you must reset the global singletons in your test setup.

Vitest (Frontend)

Add this to your vitest.setup.ts or within an afterEach block:

import { DiscoveryClient, PluginRegistry } from "@framework-m/plugin-sdk";

afterEach(() => {
DiscoveryClient.get_instance().reset();
PluginRegistry.get_instance().reset();
});

2. Mocking Resource Ownership

In component tests, you often want to avoid real discovery pings to the gateway. Use preRegisterOwners to statically map DocTypes to services.

import { PluginRegistry } from "@framework-m/plugin-sdk";

test("renders invoice with namespaced URL", () => {
PluginRegistry.get_instance().preRegisterOwners({
"sales.Invoice": "finance"
});

// Now calls to useMFetch("sales.Invoice") will resolve
// immediately to /api/finance/v1/sales.Invoice
});

3. Mocking NATS Discovery (Backend)

If you are writing backend integration tests that involve discovery, use AsyncMock to simulate NATS connectivity. The legacy patch("nats.connect") with a standard Mock will cause RuntimeWarning: unawaited coroutine errors.

from unittest.mock import AsyncMock

async def test_broadcast_logic(monkeypatch):
mock_nats = AsyncMock()
monkeypatch.setattr("nats.connect", mock_nats)
# ...

4. Configuration Mocking

Because WebConfig uses Pydantic's cached settings, you must use the monkeypatch fixture (or patch.dict(os.environ)) before the app container is initialized.

def test_macroservice_prefixing(monkeypatch, client):
monkeypatch.setenv("FRAMEWORK_MODE", "MACROSERVICE")
monkeypatch.setenv("FRAMEWORK_M_SERVICE_NAME", "finance")
# Trigger container reload or use a fresh client