UNPKG

ruch

Version:

Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance. Create maintainable, scalable applications with domain-driven design and integrated AI tooling.

188 lines (152 loc) 7.93 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import fs from 'fs-extra'; import path from 'path'; import { logger } from '../../src/utils/logger'; import { initServiceContext, generateServiceContext, updateServiceContext } from '../../src/commands/context'; vi.mock('fs-extra'); vi.mock('../../src/utils/logger', () => ({ logger: { error: vi.fn(), success: vi.fn(), info: vi.fn(), warning: vi.fn(), log: vi.fn(), } })); describe('Context Commands', () => { const projectRoot = '/test/project'; const contextPath = path.join(projectRoot, 'src', 'context'); const contextFilePath = path.join(contextPath, 'ServiceContext.tsx'); const testFilePath = path.join(contextPath, 'ServiceContext.test.tsx'); const domainsPath = path.join(projectRoot, 'src', 'domains'); beforeEach(() => { vi.clearAllMocks(); }); describe('initServiceContext', () => { it('should create empty service context when none exists', async () => { (fs.exists as any).mockResolvedValue(false); (fs.ensureDir as any).mockResolvedValue(undefined); (fs.writeFile as any).mockResolvedValue(undefined); await initServiceContext(fs, logger, projectRoot); expect(fs.exists).toHaveBeenCalledWith(contextFilePath); expect(fs.ensureDir).toHaveBeenCalledWith(contextPath); expect(fs.writeFile).toHaveBeenCalledTimes(2); expect(logger.success).toHaveBeenCalledWith('Service context created successfully!'); expect(logger.info).toHaveBeenCalledWith(`Location: ${contextFilePath}`); }); it('should not create context when it already exists', async () => { (fs.exists as any).mockResolvedValue(true); await initServiceContext(fs, logger, projectRoot); expect(fs.exists).toHaveBeenCalledWith(contextFilePath); expect(fs.ensureDir).not.toHaveBeenCalled(); expect(fs.writeFile).not.toHaveBeenCalled(); expect(logger.warning).toHaveBeenCalledWith('Service context already exists'); }); it('should handle errors during context creation', async () => { (fs.exists as any).mockResolvedValue(false); (fs.ensureDir as any).mockRejectedValue(new Error('Permission denied')); await initServiceContext(fs, logger, projectRoot); expect(logger.error).toHaveBeenCalledWith('Error initializing service context: Permission denied'); }); }); describe('generateServiceContext', () => { it('should generate context with existing domains', async () => { // Mock context doesn't exist (fs.exists as any).mockImplementation((path: string) => { if (path === contextFilePath) return Promise.resolve(false); if (path === domainsPath) return Promise.resolve(true); if (path.includes('domains/user')) return Promise.resolve(true); if (path.includes('domains/product')) return Promise.resolve(true); if (path.includes('UserService.ts')) return Promise.resolve(true); if (path.includes('UserAdapter.ts')) return Promise.resolve(true); if (path.includes('ProductService.ts')) return Promise.resolve(true); if (path.includes('ProductAdapter.ts')) return Promise.resolve(true); return Promise.resolve(false); }); (fs.readdir as any).mockResolvedValue(['user', 'product']); (fs.stat as any).mockResolvedValue({ isDirectory: () => true }); (fs.ensureDir as any).mockResolvedValue(undefined); (fs.writeFile as any).mockResolvedValue(undefined); await generateServiceContext(fs, logger, projectRoot); expect(fs.writeFile).toHaveBeenCalledTimes(2); expect(logger.success).toHaveBeenCalledWith('Service context created successfully!'); expect(logger.info).toHaveBeenCalledWith('Integrated 2 domain(s):'); }); it('should create empty context when no domains exist', async () => { (fs.exists as any).mockImplementation((path: string) => { if (path === contextFilePath) return Promise.resolve(false); if (path === domainsPath) return Promise.resolve(false); return Promise.resolve(false); }); (fs.ensureDir as any).mockResolvedValue(undefined); (fs.writeFile as any).mockResolvedValue(undefined); await generateServiceContext(fs, logger, projectRoot); expect(logger.warning).toHaveBeenCalledWith('No domains found. Creating empty service context.'); expect(fs.writeFile).toHaveBeenCalledTimes(2); }); it('should not generate when context already exists', async () => { (fs.exists as any).mockResolvedValue(true); await generateServiceContext(fs, logger, projectRoot); expect(logger.warning).toHaveBeenCalledWith('Service context already exists. Use "context update" to add new domains.'); expect(fs.writeFile).not.toHaveBeenCalled(); }); }); describe('updateServiceContext', () => { it('should update context with missing domains', async () => { // Mock context exists (fs.exists as any).mockImplementation((path: string) => { if (path === contextFilePath) return Promise.resolve(true); if (path === domainsPath) return Promise.resolve(true); if (path.includes('domains/user')) return Promise.resolve(true); if (path.includes('domains/product')) return Promise.resolve(true); if (path.includes('UserService.ts')) return Promise.resolve(true); if (path.includes('UserAdapter.ts')) return Promise.resolve(true); if (path.includes('ProductService.ts')) return Promise.resolve(true); if (path.includes('ProductAdapter.ts')) return Promise.resolve(true); return Promise.resolve(false); }); // Mock existing context with only user domain (fs.readFile as any).mockResolvedValue(` interface Services { userService: UserService; } `); (fs.readdir as any).mockResolvedValue(['user', 'product']); (fs.stat as any).mockResolvedValue({ isDirectory: () => true }); (fs.writeFile as any).mockResolvedValue(undefined); await updateServiceContext(fs, logger, projectRoot, true); // Now expects 3 calls: backup + context + test files expect(fs.writeFile).toHaveBeenCalledTimes(3); expect(logger.success).toHaveBeenCalledWith('Service context updated successfully!'); expect(logger.info).toHaveBeenCalledWith('Added 1 domain(s) to service context'); }); it('should not update when context is up to date', async () => { // Mock context exists (fs.exists as any).mockImplementation((path: string) => { if (path === contextFilePath) return Promise.resolve(true); if (path === domainsPath) return Promise.resolve(true); if (path.includes('domains/user')) return Promise.resolve(true); if (path.includes('UserService.ts')) return Promise.resolve(true); if (path.includes('UserAdapter.ts')) return Promise.resolve(true); return Promise.resolve(false); }); // Mock existing context with user domain (fs.readFile as any).mockResolvedValue(` interface Services { userService: UserService; } `); (fs.readdir as any).mockResolvedValue(['user']); (fs.stat as any).mockResolvedValue({ isDirectory: () => true }); await updateServiceContext(fs, logger, projectRoot, true); expect(fs.writeFile).not.toHaveBeenCalled(); expect(logger.info).toHaveBeenCalledWith('Service context is already up to date. No missing domains found.'); }); it('should not update when context does not exist', async () => { (fs.exists as any).mockResolvedValue(false); await updateServiceContext(fs, logger, projectRoot, true); expect(logger.error).toHaveBeenCalledWith('Service context does not exist. Use "context init" or "context generate" first.'); expect(fs.writeFile).not.toHaveBeenCalled(); }); }); });