- useMountTransition hook(延迟卸载播放退场,尊重 reduced-motion)+ vitest - Drawer 淡入+滑入进出场;focus/scroll-lock 仍由 open 驱动、focus 键 shouldRender 防丢首焦 - Toast 入场 toast-in 动画(motion-safe) - P4-6 首屏零作品用 callout 暖深色编辑部英雄(对标 cta-band-dark,不干扰工作库) 新增 callout/on-callout/on-callout-soft 双主题成对 token
54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { act, renderHook } from "@testing-library/react";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { useMountTransition } from "./useMountTransition";
|
|
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
// 让 rAF 同步执行,便于断言 isVisible 翻转。
|
|
vi.stubGlobal("requestAnimationFrame", (cb: FrameRequestCallback) => {
|
|
cb(0);
|
|
return 1;
|
|
});
|
|
vi.stubGlobal("cancelAnimationFrame", () => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
describe("useMountTransition", () => {
|
|
it("renders nothing while closed", () => {
|
|
const { result } = renderHook(() => useMountTransition(false, 180));
|
|
expect(result.current.shouldRender).toBe(false);
|
|
expect(result.current.isVisible).toBe(false);
|
|
});
|
|
|
|
it("mounts and becomes visible when opened", () => {
|
|
const { result, rerender } = renderHook(
|
|
({ open }) => useMountTransition(open, 180),
|
|
{ initialProps: { open: false } },
|
|
);
|
|
act(() => rerender({ open: true }));
|
|
expect(result.current.shouldRender).toBe(true);
|
|
expect(result.current.isVisible).toBe(true);
|
|
});
|
|
|
|
it("keeps rendering during exit, then unmounts after the duration", () => {
|
|
const { result, rerender } = renderHook(
|
|
({ open }) => useMountTransition(open, 180),
|
|
{ initialProps: { open: true } },
|
|
);
|
|
act(() => rerender({ open: false }));
|
|
expect(result.current.isVisible).toBe(false);
|
|
expect(result.current.shouldRender).toBe(true);
|
|
|
|
act(() => {
|
|
vi.advanceTimersByTime(180);
|
|
});
|
|
expect(result.current.shouldRender).toBe(false);
|
|
});
|
|
});
|