# S2 Unit Test

> Guidelines for writing and maintaining unit tests in the S2 project. Use when modifying source code to ensure proper test coverage.

- Skill: `antvis/s2-unit-test` (Agent Skill)
- Install (CLI): `npx skillmds@latest add antvis/s2-unit-test`
- Raw SKILL.md: https://api.skillmd.com/api/skills/antvis/s2-unit-test/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: antvis (https://skillmd.com/u/antvis)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/antvis/s2-unit-test

---


# S2 Unit Testing Guidelines

## When to Use This Skill

Use this skill when you:

- Modify code under `packages/*/src/`
- Fix bugs (especially with issue numbers)
- Add new features or functions

**By default, all code changes require corresponding unit tests.**

## Test File Location Strategy

### Step 1: Find Existing Test Files

Search for `__tests__` directories to find where tests for the modified file already exist:

```text
packages/s2-core/__tests__/unit/      # Unit tests organized by module
packages/s2-core/__tests__/bugs/      # Bug regression tests with issue numbers
packages/s2-core/__tests__/spreadsheet/  # Integration-level spreadsheet tests
packages/s2-react/__tests__/          # React component tests
packages/s2-vue/__tests__/            # Vue component tests
```

### Step 2: Choose the Right Location

| Scenario | Location | File Naming |
|----------|----------|-------------|
| Modifying existing function | Add to existing test file for that function | N/A |
| Bug fix with issue number | `packages/s2-core/__tests__/bugs/` | `issue-{number}-spec.ts` |
| New utility function | `packages/s2-core/__tests__/unit/utils/` | `{function-name}-spec.ts` |
| New cell logic | `packages/s2-core/__tests__/unit/cell/` | `{cell-type}-spec.ts` |
| New interaction | `packages/s2-core/__tests__/unit/interaction/` | `{interaction-name}-spec.ts` |

**Prefer adding tests to existing files over creating new ones.** Reuse existing helper functions and test utilities.

## Critical Rules

### ✅ Good Practices

1. **Import from `src` directory** - Tests must exercise actual source code:

```typescript
// Good: Import functions/classes from src
import { getCellWidth, getDisplayText } from '@/utils/text';
import { PivotSheet } from '@/sheet-type';

// Good: Use path aliases
import { createPivotSheet } from 'tests/util/helpers';
```

2. **Test real behavior** - Create actual instances and verify logic:

```typescript
// Good: Create real S2 instance and test behavior
const s2 = createPivotSheet(options);
await s2.render();
expect(s2.facet.getColCells()[0].getMeta().width).toBe(expectedWidth);
```

3. **Reproduce bugs with real code paths**:

```typescript
// Good: Bug reproduction that exercises src code
describe('issue #3212', () => {
  test('should keep column width after hiding value', async () => {
    const s2 = createPivotSheet({ style: { layoutWidthType: 'compact' } });
    await s2.render();
    
    const originalWidth = s2.facet.getColCells()[0].getMeta().width;
    s2.setOptions({ style: { colCell: { hideValue: true } } });
    await s2.render();
    
    expect(s2.facet.getColCells()[0].getMeta().width).toBe(originalWidth);
  });
});
```

### ❌ Bad Practices

1. **Never reimplement logic in tests**:

```typescript
// BAD: Reimplementing the logic defeats the purpose
function myLocalCalculation(a, b) {
  return a + b; // This is useless! If src is broken, test still passes
}
expect(myLocalCalculation(1, 2)).toBe(3);
```

2. **Never import only types**:

```typescript
// BAD: Only importing types doesn't test any actual code
import type { S2Options, SpreadSheet } from '@/common';
// No actual code is being tested!
```

3. **Never test mocked implementations instead of real code**:

```typescript
// BAD: Testing your own mock, not the actual source
const mockFn = jest.fn().mockReturnValue(42);
expect(mockFn()).toBe(42); // This tests nothing useful
```

## Test Structure Template

```typescript
/**
 * @description spec for issue #XXXX (if applicable)
 * https://github.com/antvis/S2/issues/XXXX
 */
import { SomeFunction, SomeClass } from '@/path/to/src';
import { createPivotSheet } from 'tests/util/helpers';

describe('FeatureName', () => {
  test('should do expected behavior', () => {
    // Arrange
    const input = { /* ... */ };
    
    // Act
    const result = SomeFunction(input);
    
    // Assert
    expect(result).toEqual(expectedOutput);
  });
});
```

## Running Tests

```bash
# Run all tests for a package
pnpm --filter @antv/s2 test

# Run specific test file
pnpm --filter @antv/s2 test -- --testPathPattern="issue-3212"

# Run with coverage
pnpm --filter @antv/s2 test:coverage
```

## Goal

The primary goal of unit tests is to:

- **Increase line coverage** - Every line of src code should be exercised
- **Increase branch coverage** - Test all conditional paths
- **Prevent regressions** - Ensure bugs don't reappear

Tests that don't import and exercise actual `src` code provide no coverage benefit.

