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.

255 lines (218 loc) 9.3 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import fs from 'fs-extra'; import { logger } from '../../src/utils/logger'; import * as templates from '../../src/templates/domains'; import { createDomain } from '../../src/commands/create'; import path from 'path'; import * as paths from '../../src/utils/paths'; import type { FileSystem } from '../../src/utils/file-operations'; import type { Logger } from '../../src/utils/logging'; import type { DomainGenerationOptions } from '../../src/templates/domains'; vi.mock('fs-extra', () => ({ default: { exists: vi.fn(), ensureDir: vi.fn(), writeFile: vi.fn(), remove: vi.fn(), }, })); vi.mock('../src/utils/logger', () => ({ logger: { error: vi.fn(), success: vi.fn(), info: vi.fn(), warning: vi.fn(), log: vi.fn(), }, })); vi.mock('../src/templates/domains', () => ({ getDomainFiles: vi.fn(), })); vi.mock('../src/utils/paths', () => ({ validateDomainName: vi.fn(), buildDomainDirectoryPath: vi.fn(), getDomainsSourceDirectoryPath: vi.fn(), })); const domainName = 'testdomain'; const domainPath = path.join(process.cwd(), 'src', 'domains', domainName); const domainsSourcePath = path.join(process.cwd(), 'src', 'domains'); const fullOptions: DomainGenerationOptions = { withApi: true, withQueries: true, withStore: true, withUi: true, }; const minimalOptions: DomainGenerationOptions = { withApi: false, withQueries: false, withStore: false, withUi: false, }; describe('createDomain', () => { let mockFileSystem: FileSystem; let mockLogger: Logger; beforeEach(() => { vi.clearAllMocks(); vi.spyOn(paths, 'buildDomainDirectoryPath').mockReturnValue(domainPath); vi.spyOn(paths, 'validateDomainName').mockReturnValue(true); vi.spyOn(templates, 'getDomainFiles').mockImplementation((domainName, options = { withUi: true, withStore: true, withQueries: true, withApi: true }) => { const files = [ { path: 'entities/Testdomain.ts', content: '// entities' }, { path: 'entities/Testdomain.test.ts', content: '// entities test' }, { path: 'ports/TestdomainPort.ts', content: '// ports' }, { path: 'services/TestdomainService.ts', content: '// services' }, { path: 'services/TestdomainService.test.ts', content: '// services test' }, { path: 'adapters/TestdomainAdapter.ts', content: '// adapters' }, { path: 'adapters/TestdomainAdapter.test.ts', content: '// adapters test' }, { path: 'hooks/useTestdomain.ts', content: '// hooks' }, { path: 'hooks/useTestdomain.test.ts', content: '// hooks test' } ]; if (options.withUi) { files.push({ path: 'ui/TestdomainView.tsx', content: '// ui' }); files.push({ path: 'ui/TestdomainView.test.tsx', content: '// ui test' }); } return files; }); // Mocks FileSystem mockFileSystem = { exists: vi.fn(), pathExists: vi.fn(), ensureDir: vi.fn(), writeFile: vi.fn(), remove: vi.fn(), readFile: vi.fn(), readdir: vi.fn(), stat: vi.fn(), mkdir: vi.fn(), } as unknown as FileSystem; // Mocks Logger mockLogger = { error: vi.fn(), success: vi.fn(), info: vi.fn(), warning: vi.fn(), log: vi.fn(), }; }); it('should create a domain with all modules', async () => { const existsMock = vi.fn().mockResolvedValue(false); const ensureDirMock = vi.fn().mockResolvedValue(undefined); const writeFileMock = vi.fn().mockResolvedValue(undefined); vi.mocked(mockFileSystem.exists).mockImplementation(existsMock); vi.mocked(mockFileSystem.ensureDir).mockImplementation(ensureDirMock); vi.mocked(mockFileSystem.writeFile).mockImplementation(writeFileMock); await createDomain(domainName, { withUi: true, withStore: true, withQueries: true, withApi: true }, mockFileSystem, mockLogger); const expectedDirs = [ domainPath, path.join(domainPath, 'entities'), path.join(domainPath, 'ports'), path.join(domainPath, 'services'), path.join(domainPath, 'adapters'), path.join(domainPath, 'hooks'), path.join(domainPath, 'ui') ]; const ensureDirCalls = vi.mocked(mockFileSystem.ensureDir).mock.calls.map(call => call[0]); expectedDirs.forEach(dir => { expect(ensureDirCalls).toContain(dir); }); const expectedFiles = [ path.join(domainPath, 'entities', 'Testdomain.ts'), path.join(domainPath, 'entities', 'Testdomain.test.ts'), path.join(domainPath, 'ports', 'TestdomainPort.ts'), path.join(domainPath, 'services', 'TestdomainService.ts'), path.join(domainPath, 'services', 'TestdomainService.test.ts'), path.join(domainPath, 'adapters', 'TestdomainAdapter.ts'), path.join(domainPath, 'adapters', 'TestdomainAdapter.test.ts'), path.join(domainPath, 'hooks', 'useTestdomain.ts'), path.join(domainPath, 'hooks', 'useTestdomain.test.ts'), path.join(domainPath, 'ui', 'TestdomainView.tsx'), path.join(domainPath, 'ui', 'TestdomainView.test.tsx') ]; expectedFiles.forEach(file => { expect(mockFileSystem.writeFile).toHaveBeenCalledWith(file, expect.any(String), 'utf8'); }); expect(mockLogger.success).toHaveBeenCalledWith(`Domain "${domainName}" created successfully!`); }); it('should create a domain with minimal structure', async () => { const existsMock = vi.fn().mockResolvedValue(false); const ensureDirMock = vi.fn().mockResolvedValue(undefined); const writeFileMock = vi.fn().mockResolvedValue(undefined); vi.mocked(mockFileSystem.exists).mockImplementation(existsMock); vi.mocked(mockFileSystem.ensureDir).mockImplementation(ensureDirMock); vi.mocked(mockFileSystem.writeFile).mockImplementation(writeFileMock); await createDomain(domainName, { withUi: false, withStore: false, withQueries: false, withApi: false }, mockFileSystem, mockLogger); const expectedDirs = [ domainPath, path.join(domainPath, 'entities'), path.join(domainPath, 'ports'), path.join(domainPath, 'services'), path.join(domainPath, 'adapters'), path.join(domainPath, 'hooks') ]; const ensureDirCalls = vi.mocked(mockFileSystem.ensureDir).mock.calls.map(call => call[0]); expectedDirs.forEach(dir => { expect(ensureDirCalls).toContain(dir); }); const expectedFiles = [ path.join(domainPath, 'entities', 'Testdomain.ts'), path.join(domainPath, 'entities', 'Testdomain.test.ts'), path.join(domainPath, 'ports', 'TestdomainPort.ts'), path.join(domainPath, 'services', 'TestdomainService.ts'), path.join(domainPath, 'services', 'TestdomainService.test.ts'), path.join(domainPath, 'adapters', 'TestdomainAdapter.ts'), path.join(domainPath, 'adapters', 'TestdomainAdapter.test.ts'), path.join(domainPath, 'hooks', 'useTestdomain.ts'), path.join(domainPath, 'hooks', 'useTestdomain.test.ts') ]; expectedFiles.forEach(file => { expect(mockFileSystem.writeFile).toHaveBeenCalledWith(file, expect.any(String), 'utf8'); }); // Vérifier que les fichiers UI ne sont pas créés const uiFiles = [ path.join(domainPath, 'ui', 'TestdomainView.tsx'), path.join(domainPath, 'ui', 'TestdomainView.test.tsx') ]; uiFiles.forEach(file => { const matchingCall = vi.mocked(mockFileSystem.writeFile).mock.calls.find( (call) => call[0] === file ); expect(matchingCall).toBeUndefined(); }); expect(mockLogger.success).toHaveBeenCalledWith(`Domain "${domainName}" created successfully!`); }); it('should not create domain if it already exists', async () => { (mockFileSystem.exists as any).mockResolvedValue(true); await createDomain(domainName, fullOptions, mockFileSystem, mockLogger); expect(mockFileSystem.ensureDir).not.toHaveBeenCalled(); expect(mockFileSystem.writeFile).not.toHaveBeenCalled(); expect(mockLogger.error).toHaveBeenCalledWith(`Domain "${domainName}" already exists at ${domainPath}`); }); it('should not create domain if name is invalid', async () => { (paths.validateDomainName as any).mockReturnValue(false); await createDomain(domainName, fullOptions, mockFileSystem, mockLogger); expect(mockFileSystem.ensureDir).not.toHaveBeenCalled(); expect(mockFileSystem.writeFile).not.toHaveBeenCalled(); expect(mockLogger.error).toHaveBeenCalledWith(`❌ Invalid domain name: "${domainName}"`); }); it('should clean up on error', async () => { (mockFileSystem.exists as any) .mockResolvedValueOnce(false) // avant création .mockResolvedValueOnce(true); // après l'erreur, pour cleanup (mockFileSystem.ensureDir as any).mockResolvedValue(undefined); (mockFileSystem.writeFile as any).mockRejectedValue(new Error('Test error')); await createDomain(domainName, fullOptions, mockFileSystem, mockLogger); expect(mockFileSystem.remove).toHaveBeenCalledWith(domainPath); expect(mockLogger.error).toHaveBeenCalledWith('Error creating domain: Test error'); expect(mockLogger.info).toHaveBeenCalledWith('Cleanup completed after error.'); }); });