Skip to main content
Glama

Curupira

by drzln
project-detector.test.ts9.02 kB
/** * @fileoverview Tests for project detection utilities */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { detectProject, detectPackageManager, checkForUpdates, validateProject } from '../project-detector.js' // Mock dependencies vi.mock('@curupira/shared', () => ({ createLogger: vi.fn(() => ({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() })) })) // Mock file system vi.mock('fs', () => ({ readFileSync: vi.fn(), existsSync: vi.fn() })) describe('project-detector', () => { beforeEach(() => { vi.clearAllMocks() }) afterEach(() => { vi.restoreAllMocks() }) describe('detectProject()', () => { it('should detect React project correctly', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package.json') }) vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }, devDependencies: { 'typescript': '^5.0.0' } })) const result = await detectProject('/test/project') expect(result.hasReact).toBe(true) expect(result.hasTypeScript).toBe(true) expect(result.framework).toBe('react') expect(result.dependencies).toEqual({ 'react': '^18.0.0', 'react-dom': '^18.0.0' }) expect(result.devDependencies).toEqual({ 'typescript': '^5.0.0' }) }) it('should detect Next.js project correctly', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package.json') }) vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' } })) const result = await detectProject('/test/nextjs-project') expect(result.hasNextJs).toBe(true) expect(result.hasReact).toBe(true) expect(result.framework).toBe('next') }) it('should detect Vite + React project correctly', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package.json') }) vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ dependencies: { 'react': '^18.0.0' }, devDependencies: { 'vite': '^5.0.0' } })) const result = await detectProject('/test/vite-project') expect(result.hasVite).toBe(true) expect(result.hasReact).toBe(true) expect(result.framework).toBe('vite') }) it('should detect Gatsby project correctly', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package.json') }) vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ dependencies: { 'gatsby': '^5.0.0', 'react': '^18.0.0' } })) const result = await detectProject('/test/gatsby-project') expect(result.hasGatsby).toBe(true) expect(result.hasReact).toBe(true) expect(result.framework).toBe('gatsby') }) it('should detect TypeScript from tsconfig.json when not in dependencies', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package.json') || path.includes('tsconfig.json') }) vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ dependencies: { 'react': '^18.0.0' } })) const result = await detectProject('/test/project') expect(result.hasTypeScript).toBe(true) }) it('should return default detection when package.json is missing', async () => { const { existsSync } = await import('fs') vi.mocked(existsSync).mockReturnValue(false) const result = await detectProject('/test/no-package') expect(result.hasReact).toBe(false) expect(result.framework).toBe('unknown') expect(result.packageManager).toBe('unknown') }) it('should handle malformed package.json gracefully', async () => { const { readFileSync, existsSync } = await import('fs') vi.mocked(existsSync).mockReturnValue(true) vi.mocked(readFileSync).mockReturnValue('invalid json') const result = await detectProject('/test/malformed') expect(result.framework).toBe('unknown') }) }) describe('detectPackageManager()', () => { it('should detect pnpm', async () => { const { existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('pnpm-lock.yaml') }) const result = detectPackageManager('/test/project') expect(result).toBe('pnpm') }) it('should detect yarn', async () => { const { existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('yarn.lock') }) const result = detectPackageManager('/test/project') expect(result).toBe('yarn') }) it('should detect npm', async () => { const { existsSync } = await import('fs') vi.mocked(existsSync).mockImplementation((path: any) => { return path.includes('package-lock.json') }) const result = detectPackageManager('/test/project') expect(result).toBe('npm') }) it('should return unknown when no lock files found', async () => { const { existsSync } = await import('fs') vi.mocked(existsSync).mockReturnValue(false) const result = detectPackageManager('/test/project') expect(result).toBe('unknown') }) }) describe('checkForUpdates()', () => { it('should return no updates available by default', async () => { const result = await checkForUpdates('curupira', '1.0.0') expect(result.available).toBe(false) expect(result.current).toBe('1.0.0') expect(result.latest).toBe('1.0.0') expect(result.type).toBe('patch') }) }) describe('validateProject()', () => { it('should validate React project as compatible', () => { const detection = { hasReact: true, hasNextJs: false, hasVite: false, hasGatsby: false, hasTypeScript: true, framework: 'react' as const, packageManager: 'npm' as const, dependencies: { 'react': '^18.0.0' }, devDependencies: {} } const result = validateProject(detection) expect(result.valid).toBe(true) expect(result.reason).toBeUndefined() }) it('should validate Next.js project as compatible', () => { const detection = { hasReact: true, hasNextJs: true, hasVite: false, hasGatsby: false, hasTypeScript: true, framework: 'next' as const, packageManager: 'npm' as const, dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }, devDependencies: {} } const result = validateProject(detection) expect(result.valid).toBe(true) }) it('should validate Vite project as compatible', () => { const detection = { hasReact: true, hasNextJs: false, hasVite: true, hasGatsby: false, hasTypeScript: false, framework: 'vite' as const, packageManager: 'npm' as const, dependencies: { 'react': '^18.0.0' }, devDependencies: { 'vite': '^5.0.0' } } const result = validateProject(detection) expect(result.valid).toBe(true) }) it('should reject non-React projects', () => { const detection = { hasReact: false, hasNextJs: false, hasVite: false, hasGatsby: false, hasTypeScript: true, framework: 'unknown' as const, packageManager: 'npm' as const, dependencies: { 'vue': '^3.0.0' }, devDependencies: {} } const result = validateProject(detection) expect(result.valid).toBe(false) expect(result.reason).toContain('No React-based framework detected') }) it('should handle plain Vite without React', () => { const detection = { hasReact: false, hasNextJs: false, hasVite: true, hasGatsby: false, hasTypeScript: false, framework: 'unknown' as const, packageManager: 'npm' as const, dependencies: {}, devDependencies: { 'vite': '^5.0.0' } } const result = validateProject(detection) expect(result.valid).toBe(false) expect(result.reason).toContain('React-based framework') }) }) })

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/drzln/curupira'

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