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.

153 lines (125 loc) 6.13 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import fs from 'fs-extra'; import { logger } from '../../src/utils/logger'; import { listDomains } from '../../src/commands/list'; 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'; 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(), } })); vi.mock('../../src/utils/paths', () => ({ getDomainsSourceDirectoryPath: vi.fn(), })); describe('listDomains', () => { const domainsSourcePath = path.join(process.cwd(), 'src', 'domains'); const mockFileSystem: FileSystem = fs; const mockLogger: Logger = logger; beforeEach(() => { vi.clearAllMocks(); vi.mocked(paths.getDomainsSourceDirectoryPath).mockReturnValue(domainsSourcePath); }); it('should list all domains when domains exist', async () => { const domains = ['domain1', 'domain2', 'domain3']; const existsMock = vi.fn().mockResolvedValue(true); const readdirMock = vi.fn().mockResolvedValue(domains); const statMock = vi.fn().mockResolvedValue({ isDirectory: () => true } as fs.Stats); vi.mocked(fs.exists).mockImplementation(existsMock); vi.mocked(fs.readdir).mockImplementation(readdirMock); vi.mocked(fs.stat).mockImplementation(statMock); await listDomains(mockFileSystem, mockLogger); expect(fs.exists).toHaveBeenCalledWith(domainsSourcePath); expect(fs.readdir).toHaveBeenCalledWith(domainsSourcePath); expect(logger.success).toHaveBeenCalledWith(`${domains.length} domain(s) found:`); expect(logger.info).toHaveBeenCalledWith(`Total: ${domains.length} domain(s)`); expect(logger.info).toHaveBeenCalledWith(`Location: ${domainsSourcePath}`); domains.forEach(domain => { expect(logger.log).toHaveBeenCalledWith(expect.stringContaining(domain)); }); }); it('should show message when no domains exist', async () => { const existsMock = vi.fn().mockResolvedValue(true); const readdirMock = vi.fn().mockResolvedValue([]); vi.mocked(fs.exists).mockImplementation(existsMock); vi.mocked(fs.readdir).mockImplementation(readdirMock); await listDomains(mockFileSystem, mockLogger); expect(fs.exists).toHaveBeenCalledWith(domainsSourcePath); expect(fs.readdir).toHaveBeenCalledWith(domainsSourcePath); expect(logger.info).toHaveBeenCalledWith('No domains found in src/domains.'); expect(logger.info).toHaveBeenCalledWith('💡 Use "ruch create <domain-name>" to create your first domain.'); }); it('should handle errors when reading directory', async () => { const error = new Error('Failed to read directory'); const existsMock = vi.fn().mockResolvedValue(true); const readdirMock = vi.fn().mockRejectedValue(error); vi.mocked(fs.exists).mockImplementation(existsMock); vi.mocked(fs.readdir).mockImplementation(readdirMock); await listDomains(mockFileSystem, mockLogger); expect(fs.exists).toHaveBeenCalledWith(domainsSourcePath); expect(logger.error).toHaveBeenCalledWith(`Error reading domains: ${error.message}`); }); it('should only list directories', async () => { const files = ['domain1', 'domain2', 'file.txt', 'README.md']; const existsMock = vi.fn().mockResolvedValue(true); const readdirMock = vi.fn().mockResolvedValue(files); const statMock = vi.fn().mockImplementation(async (p) => ({ isDirectory: () => typeof p === 'string' && p.includes('domain') } as fs.Stats)); vi.mocked(fs.exists).mockImplementation(existsMock); vi.mocked(fs.readdir).mockImplementation(readdirMock); vi.mocked(fs.stat).mockImplementation(statMock); await listDomains(mockFileSystem, mockLogger); expect(fs.exists).toHaveBeenCalledWith(domainsSourcePath); expect(logger.success).toHaveBeenCalledWith('4 domain(s) found:'); expect(logger.info).toHaveBeenCalledWith('Total: 4 domain(s)'); expect(logger.info).toHaveBeenCalledWith(`Location: ${domainsSourcePath}`); expect(logger.log).toHaveBeenCalledWith(expect.stringContaining('domain1')); expect(logger.log).toHaveBeenCalledWith(expect.stringContaining('domain2')); }); it('should show message when domains folder does not exist', async () => { const existsMock = vi.fn().mockResolvedValue(false); vi.mocked(fs.exists).mockImplementation(existsMock); await listDomains(mockFileSystem, mockLogger); expect(fs.exists).toHaveBeenCalledWith(domainsSourcePath); expect(logger.info).toHaveBeenCalledWith('No domains found in src/domains.'); expect(logger.info).toHaveBeenCalledWith('💡 Use "ruch create <domain-name>" to create your first domain.'); }); it('should sort folders in logical order', async () => { const domain = 'test-domain'; const folders = ['hooks', 'ui', 'services', 'adapters', 'entities', 'ports']; const existsMock = vi.fn().mockResolvedValue(true); const readdirMock = vi.fn().mockResolvedValue([domain]); const statMock = vi.fn().mockResolvedValue({ isDirectory: () => true } as fs.Stats); const domainReaddirMock = vi.fn().mockResolvedValue(folders); const domainStatMock = vi.fn().mockResolvedValue({ isDirectory: () => true } as fs.Stats); vi.mocked(fs.exists).mockImplementation(existsMock); vi.mocked(fs.readdir) .mockImplementationOnce(readdirMock) .mockImplementationOnce(domainReaddirMock); vi.mocked(fs.stat) .mockImplementationOnce(statMock) .mockImplementation(domainStatMock); await listDomains(mockFileSystem, mockLogger); const expectedOrder = ['entities', 'ports', 'services', 'adapters', 'hooks', 'ui']; const logCalls = vi.mocked(logger.log).mock.calls; const folderLogs = logCalls .map(call => call?.[0] ?? '') .filter(log => log.includes('📂')) .map(log => log.split('📂')[1]?.trim() ?? ''); expect(folderLogs).toEqual(expectedOrder); }); });