Files
novalon-website/src/components/ui/loading-state.test.tsx
T
zhangxiang 602ed6a671 test(hooks): finalize mutation test improvements and release acceptance
- Raise use-swipe-gesture mutation score to 66.13% (target 65%+)
- Maintain use-reduced-motion mutation score at 76.32% (target 50%+)
- Fix use-reduced-motion.ts ESLint set-state-in-effect warning
- Add UJ-10 deep searcher journey (category browse → article read → content discovery)
- Add 40 new test files (analytics, detail, sections, ui, lib components)
- Update test-strategy-plan.md to v2.0 (sync test count to 1591)
- Sync README.md with final release metrics

Quality gates: TS 0 errors, ESLint 0 errors, 121 suites / 1591 tests passed
2026-08-02 19:39:27 +08:00

209 lines
6.4 KiB
TypeScript

// @ts-nocheck
import { describe, it, expect, jest } from '@jest/globals';
import { render, screen, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import { LoadingState, Spinner, PageLoader } from './loading-state';
// ─── Mocks ───────────────────────────────────────────────────────────────
jest.mock('framer-motion', () => ({
motion: {
div: ({ children, className, ...props }: any) => (
<div className={className} {...props}>{children}</div>
),
},
}));
jest.mock('@/components/ui/skeleton', () => ({
Skeleton: ({ className }: any) => <div className={className} data-testid="skeleton" />,
SkeletonHero: () => <div data-testid="skeleton-hero" />,
SkeletonList: ({ items }: any) => <div data-testid="skeleton-list" data-items={items} />,
SkeletonCard: () => <div data-testid="skeleton-card" />,
SkeletonForm: ({ fields }: any) => <div data-testid="skeleton-form" data-fields={fields} />,
}));
// ─── Tests ───────────────────────────────────────────────────────────────
describe('Spinner', () => {
it('should render with default size', () => {
render(<Spinner />);
const svg = document.querySelector('svg');
expect(svg).toBeInTheDocument();
expect(svg).toHaveAttribute('role', 'status');
});
it('should render with small size', () => {
render(<Spinner size="sm" />);
const svg = document.querySelector('svg');
expect(svg?.getAttribute('class')).toContain('w-4');
});
it('should render with large size', () => {
render(<Spinner size="lg" />);
const svg = document.querySelector('svg');
expect(svg?.getAttribute('class')).toContain('w-12');
});
it('should apply custom className', () => {
render(<Spinner className="custom-spinner" />);
const svg = document.querySelector('svg');
expect(svg?.getAttribute('class')).toContain('custom-spinner');
});
});
describe('PageLoader', () => {
it('should render when loading', () => {
render(<PageLoader isLoading={true} />);
expect(screen.getByText('正在加载...')).toBeInTheDocument();
expect(screen.getByRole('alertdialog')).toBeInTheDocument();
});
it('should render custom message', () => {
render(<PageLoader isLoading={true} message="请稍候..." />);
expect(screen.getByText('请稍候...')).toBeInTheDocument();
});
it('should not render when not loading', () => {
const { container } = render(<PageLoader isLoading={false} />);
expect(container.innerHTML).toBe('');
});
});
describe('LoadingState', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
it('should render children when not loading', () => {
render(
<LoadingState isLoading={false}>
<div data-testid="content">Content</div>
</LoadingState>
);
expect(screen.getByTestId('content')).toBeInTheDocument();
});
it('should show skeleton after delay when loading', () => {
// Mount as not loading first, then switch to loading
const { rerender } = render(
<LoadingState isLoading={false}>
<div data-testid="content">Content</div>
</LoadingState>
);
expect(screen.getByTestId('content')).toBeInTheDocument();
rerender(
<LoadingState isLoading={true}>
<div data-testid="content">Content</div>
</LoadingState>
);
// Before delay, skeleton should not be shown
expect(screen.queryByRole('status')).not.toBeInTheDocument();
// After delay, skeleton should appear
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
});
it('should render hero variant skeleton', () => {
const { rerender } = render(
<LoadingState isLoading={false} variant="hero">
<div>Content</div>
</LoadingState>
);
rerender(
<LoadingState isLoading={true} variant="hero">
<div>Content</div>
</LoadingState>
);
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByTestId('skeleton-hero')).toBeInTheDocument();
});
it('should render list variant skeleton', () => {
const { rerender } = render(
<LoadingState isLoading={false} variant="list">
<div>Content</div>
</LoadingState>
);
rerender(
<LoadingState isLoading={true} variant="list">
<div>Content</div>
</LoadingState>
);
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByTestId('skeleton-list')).toBeInTheDocument();
});
it('should render card variant skeleton', () => {
const { rerender } = render(
<LoadingState isLoading={false} variant="card">
<div>Content</div>
</LoadingState>
);
rerender(
<LoadingState isLoading={true} variant="card">
<div>Content</div>
</LoadingState>
);
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
});
it('should render form variant skeleton', () => {
const { rerender } = render(
<LoadingState isLoading={false} variant="form">
<div>Content</div>
</LoadingState>
);
rerender(
<LoadingState isLoading={true} variant="form">
<div>Content</div>
</LoadingState>
);
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByTestId('skeleton-form')).toBeInTheDocument();
});
it('should render children when loading stops', () => {
const { rerender } = render(
<LoadingState isLoading={false}>
<div data-testid="content">Content</div>
</LoadingState>
);
rerender(
<LoadingState isLoading={true}>
<div data-testid="content">Content</div>
</LoadingState>
);
act(() => {
jest.advanceTimersByTime(150);
});
expect(screen.getByRole('status')).toBeInTheDocument();
rerender(
<LoadingState isLoading={false}>
<div data-testid="content">Content</div>
</LoadingState>
);
expect(screen.getByTestId('content')).toBeInTheDocument();
});
});