test(web): cover the App-level listed-resource metadata wiring
The bridge-factory tests inject `getListedResourceMeta` directly, so nothing caught App.tsx ceasing to supply it — the fallback would go unused with every test still green. Add a pass-through spy over the factory in App.test.tsx and assert both factories receive a lookup that resolves a listed resource's `_meta` and misses on an unknown URI. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
0c989a0c34
commit
a1c00e51a8
1 changed files with 70 additions and 0 deletions
|
|
@ -355,6 +355,29 @@ vi.mock("@inspector/core/react/useSettingsDraft.js", () => ({
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// --- App bridge factory spy (#2055) -----------------------------------------
|
||||||
|
// Passes through to the real factory but records the deps App hands it, so a
|
||||||
|
// test can drive `getListedResourceMeta` — the wiring that carries a
|
||||||
|
// `resources/list` entry's `_meta.ui` into the sandbox CSP. Without this the
|
||||||
|
// bridge-factory unit tests would still pass while App stopped supplying it.
|
||||||
|
const appBridgeFactoryDeps: AppBridgeFactoryDeps[] = [];
|
||||||
|
vi.mock(
|
||||||
|
"./components/elements/AppRenderer/createAppBridgeFactory",
|
||||||
|
async (importOriginal) => {
|
||||||
|
const actual =
|
||||||
|
await importOriginal<
|
||||||
|
typeof import("./components/elements/AppRenderer/createAppBridgeFactory")
|
||||||
|
>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
createAppBridgeFactory: (deps: AppBridgeFactoryDeps) => {
|
||||||
|
appBridgeFactoryDeps.push(deps);
|
||||||
|
return actual.createAppBridgeFactory(deps);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// --- InspectorView double ---------------------------------------------------
|
// --- InspectorView double ---------------------------------------------------
|
||||||
// Surfaces each piece of session-scoped state under test and exposes buttons
|
// Surfaces each piece of session-scoped state under test and exposes buttons
|
||||||
// that invoke the App's connect / call-tool / get-prompt / read-resource /
|
// that invoke the App's connect / call-tool / get-prompt / read-resource /
|
||||||
|
|
@ -590,6 +613,8 @@ import type {
|
||||||
MessageEntry,
|
MessageEntry,
|
||||||
ServerEntry,
|
ServerEntry,
|
||||||
} from "@inspector/core/mcp/types.js";
|
} from "@inspector/core/mcp/types.js";
|
||||||
|
import type { AppBridgeFactoryDeps } from "./components/elements/AppRenderer/createAppBridgeFactory";
|
||||||
|
import { useManagedResources } from "@inspector/core/react/useManagedResources.js";
|
||||||
|
|
||||||
// Default useInspectorClient return — capabilities empty (no task tool calls).
|
// Default useInspectorClient return — capabilities empty (no task tool calls).
|
||||||
// Individual tests override via vi.mocked(...).mockReturnValue(...).
|
// Individual tests override via vi.mocked(...).mockReturnValue(...).
|
||||||
|
|
@ -3117,3 +3142,48 @@ describe("App background command rejections (#2049)", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("App MCP App listed-resource metadata wiring (#2055)", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
appBridgeFactoryDeps.length = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// The hook mock is module-level and shared, so put the empty-list default
|
||||||
|
// back rather than leaving a populated list for whatever runs next.
|
||||||
|
vi.mocked(useManagedResources).mockReturnValue({
|
||||||
|
resources: [],
|
||||||
|
refresh: vi.fn(),
|
||||||
|
clearListChanged: vi.fn(),
|
||||||
|
} as unknown as ReturnType<typeof useManagedResources>);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("hands the bridge factory a getListedResourceMeta reading the resources/list entries", async () => {
|
||||||
|
// ext-apps treats a listing entry's `_meta.ui` as the static default for a
|
||||||
|
// UI resource, so the App has to surface the listing to the bridge — the
|
||||||
|
// factory's own tests inject the dep and cannot see this wiring break.
|
||||||
|
const listedMeta = {
|
||||||
|
ui: { csp: { connectDomains: ["https://api.example.com"] } },
|
||||||
|
};
|
||||||
|
vi.mocked(useManagedResources).mockReturnValue({
|
||||||
|
resources: [
|
||||||
|
{ uri: "ui://weather/app.html", name: "app", _meta: listedMeta },
|
||||||
|
],
|
||||||
|
refresh: vi.fn(),
|
||||||
|
clearListChanged: vi.fn(),
|
||||||
|
} as unknown as ReturnType<typeof useManagedResources>);
|
||||||
|
|
||||||
|
renderWithMantine(<App />);
|
||||||
|
await waitFor(() => expect(appBridgeFactoryDeps.length).toBeGreaterThan(0));
|
||||||
|
|
||||||
|
// Every factory App builds gets the wiring, not just the Apps-tab one.
|
||||||
|
for (const deps of appBridgeFactoryDeps) {
|
||||||
|
expect(deps.getListedResourceMeta?.("ui://weather/app.html")).toEqual(
|
||||||
|
listedMeta,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
deps.getListedResourceMeta?.("ui://other/app.html"),
|
||||||
|
).toBeUndefined();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue