Skip to main content
Glama
analyze-coverage-exclude.test.ts6.28 kB
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { handleAnalyzeCoverage } from '../analyze-coverage.js'; import { projectContext } from '../../context/project-context.js'; // Mock dependencies vi.mock('../../context/project-context.js', () => ({ projectContext: { getProjectRoot: vi.fn(), } })); vi.mock('../../utils/file-utils.js', () => ({ fileExists: vi.fn().mockResolvedValue(true), isDirectory: vi.fn().mockResolvedValue(false), })); vi.mock('../../config/config-loader.js', () => ({ getConfig: vi.fn().mockResolvedValue({ testDefaults: { format: 'summary', timeout: 30000, watchMode: false, }, coverageDefaults: { threshold: 80, format: 'summary', thresholds: { lines: 80, functions: 80, branches: 80, statements: 80, }, exclude: [ '**/*.stories.*', '**/*.story.*', '**/.storybook/**', '**/storybook-static/**', '**/e2e/**', '**/*.e2e.*', '**/test-utils/**', '**/mocks/**', '**/__mocks__/**', '**/setup-tests.*', '**/test-setup.*' ], }, discovery: { testPatterns: ['**/*.{test,spec}.{js,ts,jsx,tsx}'], excludePatterns: ['node_modules', 'dist', 'coverage', '.git'], maxDepth: 10, }, server: { verbose: false, validatePaths: true, allowRootExecution: false, workingDirectory: process.cwd(), }, safety: { maxFiles: 100, requireConfirmation: true, allowedRunners: ['vitest'], allowedPaths: undefined, }, }), })); vi.mock('../../utils/version-checker.js', () => ({ checkAllVersions: vi.fn().mockResolvedValue({ errors: [], vitest: { version: '3.0.0' }, coverageProvider: { version: '3.0.0' }, }), generateVersionReport: vi.fn(), })); vi.mock('child_process', () => ({ spawn: vi.fn(), })); describe('analyze-coverage exclude patterns', () => { beforeEach(() => { vi.clearAllMocks(); vi.mocked(projectContext.getProjectRoot).mockReturnValue('/test/project'); }); it('should use default exclude patterns from config', async () => { const spawn = vi.mocked(await import('child_process').then(m => m.spawn)); const mockProcess = { stdout: { on: vi.fn((event, cb) => { if (event === 'data') { // Provide minimal valid JSON output with coverage structure const mockOutput = JSON.stringify({ testResults: [], coverageMap: { files: {}, summary: { lines: { total: 0, covered: 0, skipped: 0, pct: 0 }, functions: { total: 0, covered: 0, skipped: 0, pct: 0 }, statements: { total: 0, covered: 0, skipped: 0, pct: 0 }, branches: { total: 0, covered: 0, skipped: 0, pct: 0 } } } }); cb(Buffer.from(mockOutput)); } }) }, stderr: { on: vi.fn() }, on: vi.fn((event, cb) => { if (event === 'close') { setTimeout(() => cb(0), 0); } }), kill: vi.fn(), }; spawn.mockReturnValue(mockProcess as unknown as ReturnType<typeof spawn>); await handleAnalyzeCoverage({ target: './src/api', }); // Check that spawn was called with exclude patterns expect(spawn).toHaveBeenCalled(); const command = spawn.mock.calls[0][1] as string[]; // Verify that default exclude patterns are included ONLY for coverage (not test execution) // Should NOT have plain --exclude flags (this was the bug) expect(command).not.toContain('--exclude'); // Coverage excludes should use the --coverage.exclude=pattern format // The getExcludePatterns method returns these hardcoded defaults expect(command).toContain('--coverage.exclude=**/storybook/**'); expect(command).toContain('--coverage.exclude=**/.storybook/**'); expect(command).toContain('--coverage.exclude=**/storybook-static/**'); expect(command).toContain('--coverage.exclude=**/*.stories.*'); expect(command).toContain('--coverage.exclude=**/*.story.*'); }); it('should allow custom exclude patterns to override defaults', async () => { const spawn = vi.mocked(await import('child_process').then(m => m.spawn)); const mockProcess = { stdout: { on: vi.fn((event, cb) => { if (event === 'data') { // Provide minimal valid JSON output with coverage structure const mockOutput = JSON.stringify({ testResults: [], coverageMap: { files: {}, summary: { lines: { total: 0, covered: 0, skipped: 0, pct: 0 }, functions: { total: 0, covered: 0, skipped: 0, pct: 0 }, statements: { total: 0, covered: 0, skipped: 0, pct: 0 }, branches: { total: 0, covered: 0, skipped: 0, pct: 0 } } } }); cb(Buffer.from(mockOutput)); } }) }, stderr: { on: vi.fn() }, on: vi.fn((event, cb) => { if (event === 'close') { setTimeout(() => cb(0), 0); } }), kill: vi.fn(), }; spawn.mockReturnValue(mockProcess as unknown as ReturnType<typeof spawn>); await handleAnalyzeCoverage({ target: './src/api', exclude: ['**/*.custom.*', '**/special/**'], }); // Check that spawn was called with custom exclude patterns expect(spawn).toHaveBeenCalled(); const command = spawn.mock.calls[0][1] as string[]; // Verify that custom exclude patterns are used ONLY for coverage (not test execution) // Should NOT have plain --exclude flags (this was the bug) expect(command).not.toContain('--exclude'); // Custom patterns should use the --coverage.exclude=pattern format expect(command).toContain('--coverage.exclude=**/*.custom.*'); expect(command).toContain('--coverage.exclude=**/special/**'); // Should not contain default patterns when custom ones are provided expect(command).not.toContain('--coverage.exclude=**/*.stories.*'); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/djankies/vitest-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server