| name | s2-unit-test |
| description | Guidelines for writing and maintaining unit tests in the S2 project. Use when modifying source code to ensure proper test coverage. |
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:
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
- Import from
src directory - Tests must exercise actual source code:
import { getCellWidth, getDisplayText } from '@/utils/text';
import { PivotSheet } from '@/sheet-type';
import { createPivotSheet } from 'tests/util/helpers';
- Test real behavior - Create actual instances and verify logic:
const s2 = createPivotSheet(options);
await s2.render();
expect(s2.facet.getColCells()[0].getMeta().width).toBe(expectedWidth);
- Reproduce bugs with real code paths:
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
- Never reimplement logic in tests:
function myLocalCalculation(a, b) {
return a + b;
}
expect(myLocalCalculation(1, 2)).toBe(3);
- Never import only types:
import type { S2Options, SpreadSheet } from '@/common';
- Never test mocked implementations instead of real code:
const mockFn = jest.fn().mockReturnValue(42);
expect(mockFn()).toBe(42);
Test Structure Template
import { SomeFunction, SomeClass } from '@/path/to/src';
import { createPivotSheet } from 'tests/util/helpers';
describe('FeatureName', () => {
test('should do expected behavior', () => {
const input = { };
const result = SomeFunction(input);
expect(result).toEqual(expectedOutput);
});
});
Running Tests
pnpm --filter @antv/s2 test
pnpm --filter @antv/s2 test -- --testPathPattern="issue-3212"
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.