---
title: 测试文档
order: 4
category: pro
---

# GridView 测试文档

## 测试目标

确保 GridView 组件在各种场景下都能正常工作，包括：

- ✅ 基础渲染
- ✅ 属性传递
- ✅ 样式定制
- ✅ 子组件渲染
- ✅ 边界情况

## 测试环境

- **测试框架**: Jest
- **测试工具**: React Testing Library
- **测试类型**: 单元测试、集成测试

## 测试用例

### 1. 基础渲染测试

#### 1.1 组件正常渲染

```
import { render } from '@testing-library/react';
import GridView from '../index';

test('should render without crashing', () => {
  const { container } = render(<GridView />);
  expect(container).toBeInTheDocument();
});
```

#### 1.2 正确渲染 DOM 结构

```
test('should render with correct structure', () => {
  const { container } = render(<GridView />);

  const viewElement = container.querySelector('.pisell-grid-pro-view');
  expect(viewElement).toBeInTheDocument();
});
```

#### 1.3 包含 PisellScrollView

```
test('should contain PisellScrollView', () => {
  const { container } = render(<GridView />);

  // 检查是否渲染了 PisellScrollView
  expect(container.querySelector('.pisell-scroll-view')).toBeInTheDocument();
});
```

### 2. 属性传递测试

#### 2.1 className 属性

```
test('should apply custom className', () => {
  const { container } = render(
    <GridView className="custom-view" />
  );

  const viewElement = container.querySelector('.custom-view');
  expect(viewElement).toBeInTheDocument();
  expect(viewElement).toHaveClass('pisell-grid-pro-view');
  expect(viewElement).toHaveClass('custom-view');
});
```

#### 2.2 style 属性

```
test('should apply custom style', () => {
  const customStyle = {
    backgroundColor: '#f5f5f5',
    padding: '20px',
  };

  const { container } = render(
    <GridView style={customStyle} />
  );

  const viewElement = container.querySelector('.pisell-grid-pro-view');
  expect(viewElement).toHaveStyle({
    backgroundColor: '#f5f5f5',
    padding: '20px',
  });
});
```

### 3. 子组件渲染测试

#### 3.1 渲染子元素

```
test('should render children', () => {
  const { getByText } = render(
    <GridView>
      <div>Test Content</div>
    </GridView>
  );

  expect(getByText('Test Content')).toBeInTheDocument();
});
```

#### 3.2 渲染多个子元素

```
test('should render multiple children', () => {
  const { getByText } = render(
    <GridView>
      <div>Content 1</div>
      <div>Content 2</div>
      <div>Content 3</div>
    </GridView>
  );

  expect(getByText('Content 1')).toBeInTheDocument();
  expect(getByText('Content 2')).toBeInTheDocument();
  expect(getByText('Content 3')).toBeInTheDocument();
});
```

#### 3.3 渲染复杂子组件

```
import { Card } from 'antd';

test('should render complex children', () => {
  const { getByText } = render(
    <GridView>
      <Card title="Test Card">
        <p>Card Content</p>
      </Card>
    </GridView>
  );

  expect(getByText('Test Card')).toBeInTheDocument();
  expect(getByText('Card Content')).toBeInTheDocument();
});
```

### 4. 边界情况测试

#### 4.1 无子元素

```
test('should render without children', () => {
  const { container } = render(<GridView />);

  const viewElement = container.querySelector('.pisell-grid-pro-view');
  expect(viewElement).toBeInTheDocument();
  expect(viewElement).toBeEmptyDOMElement();
});
```

#### 4.2 null 子元素

```
test('should handle null children', () => {
  const { container } = render(
    <GridView>{null}</GridView>
  );

  expect(container.querySelector('.pisell-grid-pro-view')).toBeInTheDocument();
});
```

#### 4.3 undefined 子元素

```
test('should handle undefined children', () => {
  const { container } = render(
    <GridView>{undefined}</GridView>
  );

  expect(container.querySelector('.pisell-grid-pro-view')).toBeInTheDocument();
});
```

#### 4.4 空字符串 className

```
test('should handle empty className', () => {
  const { container } = render(
    <GridView className="" />
  );

  const viewElement = container.querySelector('.pisell-grid-pro-view');
  expect(viewElement).toBeInTheDocument();
});
```

#### 4.5 空对象 style

```
test('should handle empty style', () => {
  const { container } = render(
    <GridView style={{}} />
  );

  expect(container.querySelector('.pisell-grid-pro-view')).toBeInTheDocument();
});
```

### 5. 集成测试

#### 5.1 与 PisellGridPro 配合

```
import PisellGridPro from '../../GridPro';

test('should work with PisellGridPro', () => {
  const { getByText } = render(
    <PisellGridPro>
      <GridView>
        <div>Content in GridPro</div>
      </GridView>
    </PisellGridPro>
  );

  expect(getByText('Content in GridPro')).toBeInTheDocument();
});
```

#### 5.2 与其他布局组件配合

```
test('should work with ToolBar and Footer', () => {
  const { getByText } = render(
    <PisellGridPro>
      <PisellGridPro.ToolBar>
        <div>Toolbar</div>
      </PisellGridPro.ToolBar>
      <GridView>
        <div>Main Content</div>
      </GridView>
      <PisellGridPro.Footer>
        <div>Footer</div>
      </PisellGridPro.Footer>
    </PisellGridPro>
  );

  expect(getByText('Toolbar')).toBeInTheDocument();
  expect(getByText('Main Content')).toBeInTheDocument();
  expect(getByText('Footer')).toBeInTheDocument();
});
```

### 6. 滚动功能测试

#### 6.1 滚动容器存在

```
test('should have scroll container', () => {
  const { container } = render(
    <GridView>
      <div style={{ height: '2000px' }}>Tall Content</div>
    </GridView>
  );

  const scrollView = container.querySelector('.pisell-scroll-view');
  expect(scrollView).toBeInTheDocument();
});
```

#### 6.2 滚动属性正确

```
test('should have correct scroll properties', () => {
  const { container } = render(
    <GridView>
      <div>Content</div>
    </GridView>
  );

  const scrollView = container.querySelector('.pisell-scroll-view');
  // 验证 PisellScrollView 的配置
  expect(scrollView).toBeInTheDocument();
});
```

### 7. 性能测试

#### 7.1 渲染性能

```
import { Profiler } from 'react';

test('should render efficiently', () => {
  let renderTime = 0;

  const onRender = (id: string, phase: string, actualDuration: number) => {
    renderTime = actualDuration;
  };

  render(
    <Profiler id="GridView" onRender={onRender}>
      <GridView>
        {Array.from({ length: 100 }).map((_, i) => (
          <div key={i}>Item {i}</div>
        ))}
      </GridView>
    </Profiler>
  );

  // 渲染时间应该合理（小于 100ms）
  expect(renderTime).toBeLessThan(100);
});
```

#### 7.2 重渲染测试

```
test('should not re-render unnecessarily', () => {
  let renderCount = 0;

  const TestComponent = () => {
    renderCount++;
    return <div>Test</div>;
  };

  const { rerender } = render(
    <GridView>
      <TestComponent />
    </GridView>
  );

  const initialRenderCount = renderCount;

  // 使用相同的 props 重新渲染
  rerender(
    <GridView>
      <TestComponent />
    </GridView>
  );

  // 应该触发重渲染（因为没有 memo）
  expect(renderCount).toBeGreaterThan(initialRenderCount);
});
```

## 测试覆盖率要求

- **语句覆盖率**: ≥ 90%
- **分支覆盖率**: ≥ 85%
- **函数覆盖率**: ≥ 90%
- **行覆盖率**: ≥ 90%

## 运行测试

### 运行所有测试

```bash
pnpm test
```

### 运行单个组件测试

```bash
pnpm test GridView
```

### 查看测试覆盖率

```bash
pnpm test:coverage
```

### 监听模式

```bash
pnpm test:watch
```

## 持续集成

测试会在以下情况自动运行：

- ✅ 提交代码时（pre-commit hook）
- ✅ 推送到远程仓库时（CI/CD pipeline）
- ✅ 创建 Pull Request 时

## 测试最佳实践

1. **测试用户行为**: 从用户角度测试组件功能
2. **避免测试实现细节**: 关注组件行为而非内部实现
3. **测试边界条件**: 包括空值、极值等边界情况
4. **保持测试独立**: 每个测试应该独立运行
5. **清晰的测试描述**: 测试名称应该清楚说明测试内容

## 问题排查

### 测试失败常见原因

1. **组件未挂载**: 检查 render 方法是否正确调用
2. **选择器错误**: 验证 CSS 选择器是否正确
3. **异步问题**: 使用 waitFor 等待异步操作完成
4. **依赖未 mock**: 确保外部依赖正确 mock

### 调试技巧

```
import { render, screen } from '@testing-library/react';

test('debug test', () => {
  const { debug } = render(<GridView>Test</GridView>);

  // 输出整个 DOM 树
  debug();

  // 输出特定元素
  screen.debug(screen.getByText('Test'));
});
```

## 未来改进

- [ ] 添加视觉回归测试
- [ ] 添加滚动性能测试
- [ ] 添加可访问性测试
- [ ] 增加端到端测试
- [ ] 添加快照测试
