feat(ai-character): 관리자 웹 기반 구성
This commit is contained in:
10
src/app/App.test.tsx
Normal file
10
src/app/App.test.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
|
||||
import { App } from "./App";
|
||||
|
||||
test("renders Korean root shell with a main landmark", () => {
|
||||
render(<App />);
|
||||
|
||||
expect(document.documentElement).toHaveAttribute("lang", "ko");
|
||||
expect(screen.getByRole("main")).toHaveTextContent("AI 캐릭터 관리자");
|
||||
});
|
||||
13
src/app/App.tsx
Normal file
13
src/app/App.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function App() {
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = "ko";
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>AI 캐릭터 관리자</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
19
src/main.tsx
Normal file
19
src/main.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
import { App } from "@/app/App";
|
||||
import { getRuntimeEnv } from "@/shared/config/env";
|
||||
|
||||
getRuntimeEnv();
|
||||
|
||||
const root = document.getElementById("root");
|
||||
|
||||
if (!root) {
|
||||
throw new Error("Root element #root was not found");
|
||||
}
|
||||
|
||||
createRoot(root).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
27
src/shared/config/env.test.ts
Normal file
27
src/shared/config/env.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { getRuntimeEnv } from "./env";
|
||||
|
||||
describe("getRuntimeEnv", () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
test("returns the configured API base URL", () => {
|
||||
vi.stubEnv("VITE_API_BASE_URL", "https://api.example.com");
|
||||
|
||||
expect(getRuntimeEnv()).toEqual({ apiBaseUrl: "https://api.example.com" });
|
||||
});
|
||||
|
||||
test("blocks startup when VITE_API_BASE_URL is missing", () => {
|
||||
vi.stubEnv("VITE_API_BASE_URL", "");
|
||||
|
||||
expect(() => getRuntimeEnv()).toThrow("VITE_API_BASE_URL is required");
|
||||
});
|
||||
|
||||
test("blocks startup when VITE_API_BASE_URL is not an http URL", () => {
|
||||
vi.stubEnv("VITE_API_BASE_URL", "not-a-url");
|
||||
|
||||
expect(() => getRuntimeEnv()).toThrow("VITE_API_BASE_URL must be a valid http(s) URL");
|
||||
});
|
||||
});
|
||||
23
src/shared/config/env.ts
Normal file
23
src/shared/config/env.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export type RuntimeEnv = {
|
||||
apiBaseUrl: string;
|
||||
};
|
||||
|
||||
export function getRuntimeEnv(): RuntimeEnv {
|
||||
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
if (!apiBaseUrl) {
|
||||
throw new Error("VITE_API_BASE_URL is required");
|
||||
}
|
||||
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(apiBaseUrl);
|
||||
} catch {
|
||||
throw new Error("VITE_API_BASE_URL must be a valid http(s) URL");
|
||||
}
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
||||
throw new Error("VITE_API_BASE_URL must be a valid http(s) URL");
|
||||
}
|
||||
|
||||
return { apiBaseUrl };
|
||||
}
|
||||
10
src/shared/test/setup.ts
Normal file
10
src/shared/test/setup.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import { afterEach, vi } from "vitest";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.clearAllMocks();
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
});
|
||||
Reference in New Issue
Block a user