9c296f1e3f
Framework-level UX fixes found while auditing staging (BUG-216..220).
- chat: route 44 previously discarded composer notices to sonner with
dedupe, so recovery, cancel and archive feedback is actually visible
(BUG-216)
- chat: anchor stream auto-scroll to bottom proximity and add a
jump-to-latest control, so reading history is no longer interrupted
on every token (BUG-218)
- reports: replace the silent 120s poll cutoff with an explicit
timed-out state, an 8m budget, stepped backoff and an elapsed
counter (BUG-217)
- reports: pause polling while the tab is hidden, via a shared hook
- app: add root error, global-error and not-found boundaries (BUG-219)
- admin: add antd SSR style extraction and the React 19 render adapter,
and move admin-only css out of the global stylesheet (BUG-220)
- membership: run bootstrap fetches concurrently and pause payment
polling while hidden
- build: configure optimizePackageImports
Verified on top of 2d370f2e: tsc, eslint, next build, and the related
frontend contract suites.
Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
3.9 KiB
TypeScript
70 lines
3.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
const registry = readFileSync(new URL("../src/components/admin/admin-antd-registry.tsx", import.meta.url), "utf8");
|
|
const adminLayout = readFileSync(new URL("../src/app/admin/layout.tsx", import.meta.url), "utf8");
|
|
const rootLayout = readFileSync(new URL("../src/app/layout.tsx", import.meta.url), "utf8");
|
|
const globalsCss = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
|
const adminCss = readFileSync(new URL("../src/app/admin/admin.css", import.meta.url), "utf8");
|
|
const nextConfig = readFileSync(new URL("../next.config.ts", import.meta.url), "utf8");
|
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")) as {
|
|
dependencies: Record<string, string>;
|
|
};
|
|
|
|
test("admin antd styles are extracted during server rendering", () => {
|
|
assert.match(registry, /^"use client";/);
|
|
assert.match(registry, /import \{ StyleProvider, createCache, extractStyle \} from "@ant-design\/cssinjs";/);
|
|
assert.match(registry, /useServerInsertedHTML\(\(\) => \{/);
|
|
assert.match(registry, /extractStyle\(cache, \{ plain: true, once: true \}\)/);
|
|
assert.match(registry, /<StyleProvider cache=\{cache\}>\{children\}<\/StyleProvider>/);
|
|
assert.match(registry, /id="antd-cssinjs"/);
|
|
assert.match(registry, /data-rc-order="prepend"/);
|
|
assert.ok("@ant-design/cssinjs" in packageJson.dependencies, "cssinjs must be a declared dependency");
|
|
});
|
|
|
|
test("the antd registry wraps the admin subtree only", () => {
|
|
assert.match(adminLayout, /import \{ AdminAntdRegistry \} from "@\/components\/admin\/admin-antd-registry";/);
|
|
assert.match(adminLayout, /<AdminAntdRegistry>\s*<AdminApp>\{children\}<\/AdminApp>\s*<\/AdminAntdRegistry>/);
|
|
assert.doesNotMatch(rootLayout, /AdminAntdRegistry|cssinjs|antd/);
|
|
});
|
|
|
|
test("antd runs with the React 19 render patch inside admin", () => {
|
|
assert.match(registry, /import \{ unstableSetRender \} from "antd";/);
|
|
assert.match(registry, /import \{ createRoot, type Root \} from "react-dom\/client";/);
|
|
assert.match(registry, /unstableSetRender\(\(node, container\) => \{/);
|
|
assert.match(registry, /target\._reactRoot \?\?= createRoot\(target\);/);
|
|
assert.match(registry, /root\.render\(node\);/);
|
|
assert.match(registry, /root\.unmount\(\);/);
|
|
});
|
|
|
|
test("admin antd overrides ship only on admin routes", () => {
|
|
assert.doesNotMatch(globalsCss, /\.admin-app-shell \.ant-layout-content/);
|
|
assert.doesNotMatch(globalsCss, /\.admin-app-shell \.ant-table-wrapper/);
|
|
assert.doesNotMatch(globalsCss, /\.admin-text-list|\.admin-loading/);
|
|
assert.match(adminCss, /\.admin-app-shell \.ant-layout-content \{ padding: 22px; \}/);
|
|
assert.match(adminCss, /\.admin-app-shell \.ant-table-wrapper \.ant-table \{ background: #fbfaf7; \}/);
|
|
assert.match(adminCss, /\.admin-text-list \{ max-width: 680px;/);
|
|
assert.match(adminCss, /\.admin-loading \{ min-height: 100dvh;/);
|
|
assert.match(adminLayout, /import "\.\/admin\.css";/);
|
|
assert.doesNotMatch(rootLayout, /admin\.css/);
|
|
});
|
|
|
|
test("the admin shell keeps one antd reset stylesheet", () => {
|
|
assert.match(adminLayout, /import "antd\/dist\/reset\.css";/);
|
|
assert.doesNotMatch(adminLayout, /@refinedev\/antd\/dist\/reset\.css/);
|
|
});
|
|
|
|
test("barrel-heavy packages are optimized at build time", () => {
|
|
assert.match(nextConfig, /optimizePackageImports: \[/);
|
|
for (const pkg of ["@ant-design/icons", "@refinedev/antd", "@refinedev/core", "antd", "date-fns", "lucide-react"]) {
|
|
assert.ok(nextConfig.includes(`"${pkg}"`), `${pkg} must be listed in optimizePackageImports`);
|
|
assert.ok(pkg in packageJson.dependencies, `${pkg} must be a declared dependency`);
|
|
}
|
|
assert.match(nextConfig, /authInterrupts: true/);
|
|
assert.match(nextConfig, /outputFileTracingIncludes: \{/);
|
|
assert.match(nextConfig, /"\/api\/consult": \[/);
|
|
assert.match(nextConfig, /turbopack: \{ root: repositoryRoot \}/);
|
|
assert.match(nextConfig, /output: "standalone"/);
|
|
});
|