--- 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: ```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.