feat: 기능 추가 과정중
This commit is contained in:
@@ -8,21 +8,27 @@ import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { createDemoSessionAdapter } from "../../../src/adapters/auth/external-session-adapter.js";
|
||||
import { createDemoSessionAdapter } from "../../../src/adapters/auth/external-session-adapter.ts";
|
||||
import type { AuthSessionPort } from "../../../src/application/ports/auth-session-port.ts";
|
||||
import type {
|
||||
ReferenceFeatureInput,
|
||||
ReferenceResult,
|
||||
} from "../../../src/features/reference-feature/application/reference-feature-api.js";
|
||||
import { REFERENCE_FEATURE_ID } from "../../../src/features/reference-feature/contracts/reference-feature-contract.js";
|
||||
import type { ReferenceResourceView } from "../../../src/features/reference-feature/contracts/reference-mapper.js";
|
||||
import { createFailure } from "../../../src/contracts/errors.js";
|
||||
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.js";
|
||||
import { AppRouter } from "../../../src/presentation/routes/app-router.js";
|
||||
import { createTestApplication } from "../../helpers/create-test-application.js";
|
||||
} from "../../../src/features/reference-feature/application/reference-feature-api.ts";
|
||||
import { REFERENCE_FEATURE_ID } from "../../../src/features/reference-feature/contracts/reference-feature-contract.ts";
|
||||
import type { ReferenceResourceView } from "../../../src/features/reference-feature/contracts/reference-mapper.ts";
|
||||
import { createFailure } from "../../../src/contracts/errors.ts";
|
||||
import type { QueryInvalidationCoordinator } from "../../../src/contracts/query-invalidation.ts";
|
||||
import { QueryInvalidationProvider } from "../../../src/presentation/adapters/query/query-invalidation-provider.tsx";
|
||||
import { ServerStateScopeProvider } from "../../../src/presentation/adapters/query/server-state-scope-provider.tsx";
|
||||
import { createServerStateScopeRuntime } from "../../../src/adapters/query-cache/server-state-scope-runtime.ts";
|
||||
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.tsx";
|
||||
import { AppRouter } from "../../../src/presentation/routes/app-router.tsx";
|
||||
import { createTestApplication } from "../../helpers/create-test-application.ts";
|
||||
|
||||
function renderReference(
|
||||
input: ReferenceFeatureInput,
|
||||
url = "/examples/reference-resources?limit=5",
|
||||
session: AuthSessionPort = createDemoSessionAdapter("authenticated"),
|
||||
) {
|
||||
window.history.pushState({}, "", url);
|
||||
const client = new QueryClient({
|
||||
@@ -31,16 +37,34 @@ function renderReference(
|
||||
mutations: { retry: false },
|
||||
},
|
||||
});
|
||||
const invalidation: QueryInvalidationCoordinator = Object.freeze({
|
||||
async invalidate() {},
|
||||
beginMutation() {
|
||||
return Object.freeze({
|
||||
async release() {},
|
||||
});
|
||||
},
|
||||
async resetLocal() {},
|
||||
dispose() {},
|
||||
});
|
||||
const serverStateScope = createServerStateScopeRuntime({
|
||||
session,
|
||||
queryInvalidation: invalidation,
|
||||
});
|
||||
return render(
|
||||
<QueryClientProvider client={client}>
|
||||
<ApplicationProvider
|
||||
application={createTestApplication({
|
||||
session: createDemoSessionAdapter("authenticated"),
|
||||
featureInputs: { [REFERENCE_FEATURE_ID]: input },
|
||||
})}
|
||||
>
|
||||
<AppRouter />
|
||||
</ApplicationProvider>
|
||||
<ServerStateScopeProvider runtime={serverStateScope}>
|
||||
<QueryInvalidationProvider coordinator={invalidation}>
|
||||
<ApplicationProvider
|
||||
application={createTestApplication({
|
||||
session,
|
||||
featureInputs: { [REFERENCE_FEATURE_ID]: input },
|
||||
})}
|
||||
>
|
||||
<AppRouter />
|
||||
</ApplicationProvider>
|
||||
</QueryInvalidationProvider>
|
||||
</ServerStateScopeProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
@@ -120,6 +144,7 @@ describe("reference feature page states", () => {
|
||||
});
|
||||
|
||||
it("renders backend forbidden even when the client access hint allowed entry", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderReference(
|
||||
inputWith({
|
||||
listResources: async () => ({
|
||||
@@ -135,6 +160,71 @@ describe("reference feature page states", () => {
|
||||
expect(await screen.findByRole("alert")).toHaveTextContent(
|
||||
"이 작업을 수행할 권한이 없습니다.",
|
||||
);
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "안전한 화면으로 이동" }),
|
||||
);
|
||||
expect(
|
||||
await screen.findByRole("heading", {
|
||||
level: 1,
|
||||
name: "Clean Architecture Frontend",
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it("starts sign-in with the current route for a backend auth failure", async () => {
|
||||
const user = userEvent.setup();
|
||||
const demoSession = createDemoSessionAdapter("authenticated");
|
||||
const beginSignIn = vi.fn(async () => {});
|
||||
const session = { ...demoSession, beginSignIn };
|
||||
renderReference(
|
||||
inputWith({
|
||||
listResources: async () => ({
|
||||
ok: false,
|
||||
error: createFailure(
|
||||
"AUTH_REQUIRED",
|
||||
"LIST_REFERENCE_RESOURCES",
|
||||
0,
|
||||
),
|
||||
}),
|
||||
}),
|
||||
"/examples/reference-resources?limit=5",
|
||||
session,
|
||||
);
|
||||
|
||||
await user.click(await screen.findByRole("button", { name: "로그인" }));
|
||||
expect(beginSignIn).toHaveBeenCalledWith(
|
||||
"/examples/reference-resources?limit=5",
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to a public route when starting sign-in fails", async () => {
|
||||
const user = userEvent.setup();
|
||||
const demoSession = createDemoSessionAdapter("authenticated");
|
||||
const beginSignIn = vi.fn(async () => {
|
||||
throw new Error("identity provider unavailable");
|
||||
});
|
||||
renderReference(
|
||||
inputWith({
|
||||
listResources: async () => ({
|
||||
ok: false,
|
||||
error: createFailure(
|
||||
"AUTH_REQUIRED",
|
||||
"LIST_REFERENCE_RESOURCES",
|
||||
0,
|
||||
),
|
||||
}),
|
||||
}),
|
||||
"/examples/reference-resources?limit=5",
|
||||
{ ...demoSession, beginSignIn },
|
||||
);
|
||||
|
||||
await user.click(await screen.findByRole("button", { name: "로그인" }));
|
||||
expect(
|
||||
await screen.findByRole("heading", {
|
||||
level: 1,
|
||||
name: "Clean Architecture Frontend",
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it("deduplicates create, preserves input and surfaces a conflict", async () => {
|
||||
|
||||
Reference in New Issue
Block a user