feat(ai-character): 관리자 라우트 지연 로딩 적용
This commit is contained in:
@@ -5,7 +5,7 @@ import { build } from "vite";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
describe("production mock graph", () => {
|
||||
test("excludes the browser mock module from the production bundle", async () => {
|
||||
test("splits production chunks and excludes the browser mock module from the production bundle", async () => {
|
||||
// Given
|
||||
const outDir = mkdtempSync(join(tmpdir(), "ai-character-admin-prod-"));
|
||||
const previousNodeEnv = process.env.NODE_ENV;
|
||||
@@ -21,12 +21,16 @@ describe("production mock graph", () => {
|
||||
mode: "production",
|
||||
});
|
||||
const outputFiles = collectFiles(outDir);
|
||||
const output = outputFiles
|
||||
.filter((filePath) => filePath.endsWith(".js"))
|
||||
const jsFiles = outputFiles.filter((filePath) => filePath.endsWith(".js"));
|
||||
const output = jsFiles
|
||||
.map((filePath) => readFileSync(filePath, "utf8"))
|
||||
.join("\n");
|
||||
|
||||
// Then
|
||||
expect(jsFiles.length).toBeGreaterThanOrEqual(2);
|
||||
for (const jsFile of jsFiles) {
|
||||
expect(statSync(jsFile).size).toBeLessThanOrEqual(500_000);
|
||||
}
|
||||
expect(outputFiles.some((filePath) => filePath.endsWith("mockServiceWorker.js"))).toBe(false);
|
||||
expect(output).not.toContain("mockServiceWorker.js");
|
||||
expect(output).not.toContain("startMockWorker");
|
||||
|
||||
@@ -57,7 +57,7 @@ test("ResourcePagination connects each page size label to a unique select", () =
|
||||
expect(labels.map((label) => label.control)).toEqual(selects);
|
||||
});
|
||||
|
||||
test("ResourcePagination separates page size from an equal-width mobile movement row", () => {
|
||||
test("ResourcePagination separates page size from stacked mobile movement controls", () => {
|
||||
render(<ResourcePagination data={pageData} onPageChange={vi.fn()} onSizeChange={vi.fn()} />);
|
||||
|
||||
const sizeControls = screen.getByRole("group", { name: "페이지 크기 설정" });
|
||||
@@ -67,7 +67,7 @@ test("ResourcePagination separates page size from an equal-width mobile movement
|
||||
|
||||
expect(within(sizeControls).getByLabelText("페이지 크기")).toBeInTheDocument();
|
||||
expect(sizeControls).not.toContainElement(previous);
|
||||
expect(movementControls).toHaveClass("grid-cols-2");
|
||||
expect(previous).toHaveClass("min-h-11", "w-full");
|
||||
expect(next).toHaveClass("min-h-11", "w-full");
|
||||
expect(movementControls).toHaveClass("grid-cols-1");
|
||||
expect(previous).toHaveClass("min-h-11", "w-full", "whitespace-nowrap");
|
||||
expect(next).toHaveClass("min-h-11", "w-full", "whitespace-nowrap");
|
||||
});
|
||||
|
||||
@@ -13,10 +13,10 @@ export function ResourcePagination({ data, onPageChange, onSizeChange, sizeOptio
|
||||
|
||||
return (
|
||||
<nav aria-label="페이지" className="flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p className="text-sm font-semibold text-muted-foreground">총 {data.totalCount.toLocaleString("ko-KR")}개 · {data.page + 1}페이지</p>
|
||||
<p className="break-keep text-sm font-semibold text-muted-foreground">총 {data.totalCount.toLocaleString("ko-KR")}개 · {data.page + 1}페이지</p>
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
||||
<div aria-label="페이지 크기 설정" className="flex items-center gap-2" role="group">
|
||||
<label className="text-sm font-semibold" htmlFor={pageSizeId}>
|
||||
<label className="break-keep text-sm font-semibold" htmlFor={pageSizeId}>
|
||||
페이지 크기
|
||||
</label>
|
||||
<select className="min-h-11 rounded-md border border-input bg-card px-3 py-2 text-base" id={pageSizeId} onChange={(event) => onSizeChange(Number(event.currentTarget.value))} value={data.size}>
|
||||
@@ -25,11 +25,11 @@ export function ResourcePagination({ data, onPageChange, onSizeChange, sizeOptio
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div aria-label="페이지 이동" className="grid grid-cols-2 gap-2 sm:flex" role="group">
|
||||
<button className="min-h-11 w-full rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={data.page <= 0} onClick={() => onPageChange(data.page - 1)} type="button">
|
||||
<div aria-label="페이지 이동" className="grid grid-cols-1 gap-2 sm:flex" role="group">
|
||||
<button className="min-h-11 w-full whitespace-nowrap rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={data.page <= 0} onClick={() => onPageChange(data.page - 1)} type="button">
|
||||
이전 페이지
|
||||
</button>
|
||||
<button className="min-h-11 w-full rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={!data.hasNext} onClick={() => onPageChange(data.page + 1)} type="button">
|
||||
<button className="min-h-11 w-full whitespace-nowrap rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={!data.hasNext} onClick={() => onPageChange(data.page + 1)} type="button">
|
||||
다음 페이지
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user