Files
copilotkit__copilotkit/showcase/scripts/__tests__/runtime-manifest-copy.test.ts
Alem Tuzlak 734294155a fix(showcase/ms-agent-dotnet): copy manifest.yaml into the runtime image
PR #6130 added `src/middleware.ts`, which sets the `x-pathname` header that
`src/app/demos/layout.tsx`'s `generateMetadata()` reads. That header is what
makes the layout actually call `loadDemoIndex()` — a request-time
`readFileSync(process.cwd()/manifest.yaml)`. The Dockerfile's runner stage
never copied `manifest.yaml`, so every `/demos/*` route now 500s with "An
error occurred in the Server Components render" (ENOENT), while the
statically-prerendered home page keeps returning 200.

On the dashboard that reads as "service is up, every cell pinned at D3": D4
fails on `page.type` waiting for `textarea`, D5 times out, D6 fails on
`waitForSelector('[role="textbox"]')` — the chat input never mounts because
the page is an error boundary.

langgraph-python hit this exact bug and fixed it with the same one-line COPY;
ms-agent-dotnet is the only integration shipping `middleware.ts` without it.
Adds a ratchet test over that invariant (mutation-verified: fails with the
COPY removed).
2026-07-28 15:10:44 +02:00

50 lines
1.9 KiB
TypeScript

import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { globSync } from "glob";
import { expect, test } from "vitest";
const repositoryRoot = resolve(import.meta.dirname, "../../..");
/**
* `src/app/demos/layout.tsx` reads `manifest.yaml` from `process.cwd()` inside
* `generateMetadata()`, but only once `headers()` returns an `x-pathname` — and
* only `src/middleware.ts` sets that header. So an integration that ships the
* middleware opts every `/demos/*` route into dynamic rendering AND into a
* request-time `readFileSync` of `manifest.yaml`. If the Dockerfile's runner
* stage doesn't copy the manifest, every demo page 500s with "An error occurred
* in the Server Components render" (ENOENT) while the statically-prerendered
* home page keeps returning 200 — which reads on the dashboard as "UI is up,
* every cell stuck at D3". This bit langgraph-python once and ms-agent-dotnet
* once (PR #6130); this test is the ratchet.
*/
const integrationsWithMiddleware = globSync(
"showcase/integrations/*/src/middleware.ts",
{
cwd: repositoryRoot,
posix: true,
},
).map((match) => match.split("/")[2]);
test("integrations that ship middleware.ts exist", () => {
expect(integrationsWithMiddleware.length).toBeGreaterThan(0);
});
test.each(integrationsWithMiddleware)(
"%s copies manifest.yaml into the runtime image",
(integration) => {
const dir = resolve(repositoryRoot, "showcase/integrations", integration);
// Only integrations whose demos layout actually reads the manifest need it.
const layout = resolve(dir, "src/app/demos/layout.tsx");
if (
!existsSync(layout) ||
!readFileSync(layout, "utf8").includes("manifest.yaml")
) {
return;
}
const dockerfile = readFileSync(resolve(dir, "Dockerfile"), "utf8");
expect(dockerfile).toMatch(/^COPY .*manifest\.yaml/m);
},
);