139 lines
4.4 KiB
TypeScript
139 lines
4.4 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { HttpResponse, http } from "msw";
|
|
import { setupServer } from "msw/node";
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import {
|
|
afterAll,
|
|
afterEach,
|
|
beforeAll,
|
|
describe,
|
|
expect,
|
|
it,
|
|
vi,
|
|
} from "vitest";
|
|
|
|
import { createRuntimeComposition } from "../../../src/bootstrap/create-runtime-composition.js";
|
|
import { RuntimeApplication } from "../../../src/bootstrap/runtime-application.jsx";
|
|
|
|
const runtimeConfig = {
|
|
APP_ENV: "local",
|
|
API_BASE_URL: "https://api.test",
|
|
REQUEST_TIMEOUT_MS: 10_000,
|
|
MAX_RETRY_ATTEMPTS: 0,
|
|
TELEMETRY_ENABLED: false,
|
|
AUTH_MODE: "demo",
|
|
CONFIG_SCHEMA_VERSION: "1",
|
|
API_CONTRACT_VERSION: "1",
|
|
RELEASE_MANIFEST_URL: "/release-manifest.json",
|
|
BUILD_ID: "local-build",
|
|
RELEASE_ID: "local-release",
|
|
};
|
|
const releaseManifest = {
|
|
schemaVersion: 1,
|
|
appVersion: "0.1.0",
|
|
buildId: "local-build",
|
|
commitSha: "local",
|
|
configSchemaVersion: "1",
|
|
apiContractVersion: "1",
|
|
assetManifestHash: "test-hash",
|
|
releaseId: "local-release",
|
|
builtAt: "2026-07-26T00:00:00.000Z",
|
|
routeChunks: {
|
|
"route-home": "assets/home.js",
|
|
"route-examples-ui": "assets/ui.js",
|
|
"route-examples-states": "assets/states.js",
|
|
"route-examples-auth": "assets/auth.js",
|
|
"route-reference-resources": "assets/reference.js",
|
|
"route-reference-resource-detail": "assets/reference-detail.js",
|
|
"route-reference-resource-form": "assets/reference-form.js",
|
|
"route-reference-resource-status": "assets/reference-status.js",
|
|
"route-not-found": "assets/not-found.js",
|
|
},
|
|
};
|
|
|
|
const listRequests = vi.fn();
|
|
const createRequests = vi.fn();
|
|
const resources = [{ id: "reference-1", name: "Existing" }];
|
|
const server = setupServer(
|
|
http.get("http://app.test/config.json", () =>
|
|
HttpResponse.json(runtimeConfig),
|
|
),
|
|
http.get("http://app.test/release-manifest.json", () =>
|
|
HttpResponse.json(releaseManifest),
|
|
),
|
|
http.get("https://api.test/api/reference-resources", ({ request }) => {
|
|
listRequests(new URL(request.url).search);
|
|
return HttpResponse.json({
|
|
success: true,
|
|
data: resources,
|
|
meta: { requestId: "request-list", traceId: "trace-list" },
|
|
});
|
|
}),
|
|
http.post("https://api.test/api/reference-resources", async ({ request }) => {
|
|
const body = (await request.json()) as { name: string };
|
|
createRequests(body);
|
|
const created = { id: "reference-created", name: body.name };
|
|
resources.push(created);
|
|
return HttpResponse.json({
|
|
success: true,
|
|
data: created,
|
|
meta: { requestId: "request-create", traceId: "trace-create" },
|
|
});
|
|
}),
|
|
);
|
|
|
|
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
|
afterEach(() => {
|
|
listRequests.mockClear();
|
|
createRequests.mockClear();
|
|
resources.splice(1);
|
|
});
|
|
afterAll(() => server.close());
|
|
|
|
const absoluteFetch: typeof fetch = (input, init) => {
|
|
if (input instanceof Request) return fetch(input, init);
|
|
const url = new URL(
|
|
input instanceof URL ? input.href : input,
|
|
"http://app.test",
|
|
);
|
|
return fetch(url, init);
|
|
};
|
|
|
|
describe("reference feature production vertical path", () => {
|
|
it("traverses bootstrap, router, application, HTTP schema/mapper and query cache", async () => {
|
|
const user = userEvent.setup();
|
|
const composition = await createRuntimeComposition({
|
|
fetcher: absoluteFetch,
|
|
host: {},
|
|
});
|
|
window.history.pushState(
|
|
{},
|
|
"",
|
|
"/examples/reference-resources?tags=open&tags=new&limit=5",
|
|
);
|
|
render(<RuntimeApplication composition={composition} />);
|
|
|
|
await user.click(
|
|
await screen.findByRole("button", { name: "로그인 시작" }),
|
|
);
|
|
expect(await screen.findByText("Existing")).toBeVisible();
|
|
expect(listRequests).toHaveBeenCalledWith(
|
|
"?limit=5&tags=open&tags=new",
|
|
);
|
|
|
|
await user.click(screen.getByRole("button", { name: "새 항목 만들기" }));
|
|
await user.type(
|
|
await screen.findByRole("textbox", { name: /새 항목 이름/ }),
|
|
" Created ",
|
|
);
|
|
await user.click(screen.getByRole("button", { name: "저장" }));
|
|
expect(await screen.findByText("저장했습니다.")).toBeVisible();
|
|
await user.click(screen.getByRole("button", { name: "목록으로 돌아가기" }));
|
|
expect(await screen.findByText("Created")).toBeVisible();
|
|
expect(createRequests).toHaveBeenCalledWith({ name: "Created" });
|
|
expect(listRequests.mock.calls.length).toBeGreaterThanOrEqual(2);
|
|
});
|
|
});
|