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