UNPKG

@qwe8652591/prompt-ai

Version:

DPML-powered AI prompt framework - Revolutionary AI-First CLI system based on Deepractice Prompt Markup Language. Build sophisticated AI agents with structured prompts, memory systems, and execution frameworks.

227 lines (166 loc) 7.82 kB
const ProjectDiscovery = require('../../../../lib/core/resource/discovery/ProjectDiscovery') const path = require('path') describe('ProjectDiscovery', () => { let discovery beforeEach(() => { discovery = new ProjectDiscovery() }) describe('constructor', () => { test('should initialize with PROJECT source and priority 2', () => { expect(discovery.source).toBe('PROJECT') expect(discovery.priority).toBe(2) }) }) describe('discover', () => { test('should discover project resources from .promptx directory', async () => { // Mock project root and .promptx directory jest.spyOn(discovery, '_findProjectRoot').mockResolvedValue('/mock/project/root') jest.spyOn(discovery, '_checkPrompxDirectory').mockResolvedValue(true) jest.spyOn(discovery, '_scanProjectResources').mockResolvedValue([ { id: 'role:custom-role', reference: '@project://.promptx/resource/domain/custom-role/custom-role.role.md' }, { id: 'execution:custom-execution', reference: '@project://.promptx/resource/execution/custom-execution.execution.md' } ]) const resources = await discovery.discover() expect(resources).toHaveLength(2) expect(resources[0]).toMatchObject({ id: 'role:custom-role', reference: '@project://.promptx/resource/domain/custom-role/custom-role.role.md', metadata: { source: 'PROJECT', priority: 2 } }) }) test('should return empty array if .promptx directory does not exist', async () => { jest.spyOn(discovery, '_findProjectRoot').mockResolvedValue('/mock/project/root') jest.spyOn(discovery, '_checkPrompxDirectory').mockResolvedValue(false) const resources = await discovery.discover() expect(resources).toEqual([]) }) test('should handle project root not found', async () => { jest.spyOn(discovery, '_findProjectRoot').mockRejectedValue(new Error('Project root not found')) const resources = await discovery.discover() expect(resources).toEqual([]) }) }) describe('_findProjectRoot', () => { test('should find project root containing package.json', async () => { const mockFsExists = jest.fn() .mockResolvedValueOnce(false) // /current/dir/package.json .mockResolvedValueOnce(true) // /current/package.json discovery._fsExists = mockFsExists // Mock process.cwd() const originalCwd = process.cwd process.cwd = jest.fn().mockReturnValue('/current/dir') const root = await discovery._findProjectRoot() expect(root).toBe('/current') // Restore process.cwd = originalCwd }) test('should return current directory if no package.json found', async () => { const mockFsExists = jest.fn().mockResolvedValue(false) discovery._fsExists = mockFsExists const originalCwd = process.cwd process.cwd = jest.fn().mockReturnValue('/current/dir') const root = await discovery._findProjectRoot() expect(root).toBe('/current/dir') process.cwd = originalCwd }) }) describe('_checkPrompxDirectory', () => { test('should check if .promptx/resource directory exists', async () => { const mockFsExists = jest.fn().mockResolvedValue(true) discovery._fsExists = mockFsExists const exists = await discovery._checkPrompxDirectory('/mock/project/root') expect(exists).toBe(true) expect(mockFsExists).toHaveBeenCalledWith('/mock/project/root/.promptx/resource') }) }) describe('_scanProjectResources', () => { test('should scan for role, execution, thought files in .promptx', async () => { const projectRoot = '/mock/project/root' // Mock file scanner const mockScanResourceFiles = jest.fn() .mockResolvedValueOnce([`${projectRoot}/.promptx/resource/domain/test/test.role.md`]) // roles .mockResolvedValueOnce([`${projectRoot}/.promptx/resource/execution/test.execution.md`]) // executions .mockResolvedValueOnce([`${projectRoot}/.promptx/resource/thought/test.thought.md`]) // thoughts discovery.fileScanner.scanResourceFiles = mockScanResourceFiles // Mock file validation discovery._validateResourceFile = jest.fn().mockResolvedValue(true) const resources = await discovery._scanProjectResources(projectRoot) expect(resources).toHaveLength(3) expect(resources[0].id).toBe('role:test') expect(resources[1].id).toBe('execution:test') expect(resources[2].id).toBe('thought:test') }) test('should handle scan errors gracefully', async () => { const projectRoot = '/mock/project/root' const mockScanResourceFiles = jest.fn().mockRejectedValue(new Error('Scan failed')) discovery.fileScanner.scanResourceFiles = mockScanResourceFiles const resources = await discovery._scanProjectResources(projectRoot) expect(resources).toEqual([]) }) }) describe('_generateProjectReference', () => { test('should generate @project:// reference', () => { const filePath = '/mock/project/root/.promptx/resource/domain/test/test.role.md' const projectRoot = '/mock/project/root' // Mock the fileScanner.getRelativePath method discovery.fileScanner.getRelativePath = jest.fn().mockReturnValue('.promptx/resource/domain/test/test.role.md') const reference = discovery._generateProjectReference(filePath, projectRoot) expect(reference).toBe('@project://.promptx/resource/domain/test/test.role.md') }) test('should handle Windows paths correctly', () => { const filePath = 'C:\\mock\\project\\root\\.promptx\\resource\\domain\\test\\test.role.md' const projectRoot = 'C:\\mock\\project\\root' // Mock the fileScanner.getRelativePath method discovery.fileScanner.getRelativePath = jest.fn().mockReturnValue('.promptx/resource/domain/test/test.role.md') const reference = discovery._generateProjectReference(filePath, projectRoot) expect(reference).toBe('@project://.promptx/resource/domain/test/test.role.md') }) }) describe('_extractResourceId', () => { test('should extract resource id with protocol prefix', () => { const filePath = '/mock/project/root/.promptx/resource/domain/test/test.role.md' const protocol = 'role' const id = discovery._extractResourceId(filePath, protocol, '.role.md') expect(id).toBe('role:test') }) }) describe('_validateResourceFile', () => { test('should validate role file contains required DPML tags', async () => { const filePath = '/mock/test.role.md' const mockContent = ` # Test Role <role> Test role content </role> ` const mockReadFile = jest.fn().mockResolvedValue(mockContent) discovery._readFile = mockReadFile const isValid = await discovery._validateResourceFile(filePath, 'role') expect(isValid).toBe(true) }) test('should return false for invalid role file', async () => { const filePath = '/mock/test.role.md' const mockContent = 'Invalid content without DPML tags' const mockReadFile = jest.fn().mockResolvedValue(mockContent) discovery._readFile = mockReadFile const isValid = await discovery._validateResourceFile(filePath, 'role') expect(isValid).toBe(false) }) test('should handle file read errors', async () => { const filePath = '/mock/test.role.md' const mockReadFile = jest.fn().mockRejectedValue(new Error('File not found')) discovery._readFile = mockReadFile const isValid = await discovery._validateResourceFile(filePath, 'role') expect(isValid).toBe(false) }) }) })