Просмотр исходного кода

add mocking strategies for CommonJS modules and decision tree for mocking

Yuki Takei 1 месяц назад
Родитель
Сommit
3d4b33bd19
1 измененных файлов с 65 добавлено и 0 удалено
  1. 65 0
      .claude/skills/learned/essential-test-patterns/SKILL.md

+ 65 - 0
.claude/skills/learned/essential-test-patterns/SKILL.md

@@ -372,6 +372,71 @@ vi.mock('~/utils/myUtils', () => ({
 }));
 ```
 
+### Mocking CommonJS Modules with mock-require
+
+**IMPORTANT**: When `vi.mock()` fails with ESModule/CommonJS compatibility issues, use `mock-require` instead:
+
+```typescript
+import mockRequire from 'mock-require';
+
+describe('Service with CommonJS dependencies', () => {
+  beforeEach(() => {
+    // Mock CommonJS module before importing the code under test
+    mockRequire('legacy-module', {
+      someFunction: vi.fn().mockReturnValue('mocked'),
+      someProperty: 'mocked-value',
+    });
+  });
+
+  afterEach(() => {
+    // Clean up mocks to avoid leakage between tests
+    mockRequire.stopAll();
+  });
+
+  it('should use mocked module', async () => {
+    // Import AFTER mocking (dynamic import if needed)
+    const { MyService } = await import('~/services/MyService');
+
+    const result = MyService.doSomething();
+    expect(result).toBe('mocked');
+  });
+});
+```
+
+**When to use `mock-require`**:
+- Legacy CommonJS modules that don't work with `vi.mock()`
+- Mixed ESM/CJS environments causing module resolution issues
+- Third-party libraries with complex module systems
+- When `vi.mock()` fails with "Cannot redefine property" or "Module is not defined"
+
+**Key points**:
+- ✅ Mock **before** importing the code under test
+- ✅ Use `mockRequire.stopAll()` in `afterEach()` to prevent test leakage
+- ✅ Use dynamic imports (`await import()`) when needed
+- ✅ Works with both CommonJS and ESModule targets
+
+### Choosing the Right Mocking Strategy
+
+```typescript
+// ✅ Prefer vi.mock() for ESModules (simplest)
+vi.mock('~/modern-module', () => ({
+  myFunction: vi.fn(),
+}));
+
+// ✅ Use mock-require for CommonJS or mixed environments
+import mockRequire from 'mock-require';
+mockRequire('legacy-module', { myFunction: vi.fn() });
+
+// ✅ Use vitest-mock-extended for type-safe object mocks
+import { mockDeep } from 'vitest-mock-extended';
+const mockService = mockDeep<MyService>();
+```
+
+**Decision tree**:
+1. Can use `vi.mock()`? → Use it (simplest)
+2. CommonJS or module error? → Use `mock-require`
+3. Need type-safe object mock? → Use `vitest-mock-extended`
+
 ## Integration Tests (with Database)
 
 Integration tests (*.integ.ts) can access in-memory databases: