Specif-ai MCP Server
Official
by vj-presidio
import { FileService } from '../file.service'
import { ConsoleManager } from './test-utils'
// Mock fs/promises module
jest.mock('fs/promises', () => ({
readdir: jest.fn(),
readFile: jest.fn(),
}))
// Import mocked fs/promises to access mock functions
import { readdir, readFile } from 'fs/promises'
describe('FileService', () => {
let fileService: FileService
let mockReaddir: jest.Mock
let mockReadFile: jest.Mock
beforeAll(() => {
ConsoleManager.suppressConsole()
})
afterAll(() => {
ConsoleManager.restoreConsole()
})
beforeEach(() => {
// Reset mocks before each test
mockReaddir = readdir as jest.Mock
mockReadFile = readFile as jest.Mock
// Set default mock implementations
mockReaddir.mockResolvedValue(['test.json', 'test2.txt'])
mockReadFile.mockResolvedValue('{"title": "Test", "requirement": "Test req"}')
// Clear mock calls
mockReaddir.mockClear()
mockReadFile.mockClear()
fileService = new FileService()
})
describe('readAllJsonFiles', () => {
test('should filter out non-JSON files', async () => {
// Mock readdir to return mixed file types
const files = ['test.json', 'test.txt', 'test.js', 'test2.json', 'test.jsx', 'test.JSON']
mockReaddir.mockResolvedValue(files)
const result = await fileService.readAllJsonFiles('/test/dir')
// Should only process .json files (case sensitive)
expect(result).toHaveLength(2)
expect(result.map((f) => f.name).sort()).toEqual(['test.json', 'test2.json'])
// Verify each file was checked for .json extension
files.forEach((file) => {
expect(file.endsWith('.json')).toBe(result.some((r) => r.name === file))
})
})
test('should read and parse multiple JSON files from directory', async () => {
// Mock readdir to return multiple JSON files
mockReaddir.mockResolvedValue(['test1.json', 'test2.json'])
// Mock readFile to return different content for each file
mockReadFile.mockImplementation((path: string) => {
if (path.includes('test1.json')) {
return Promise.resolve('{"title": "Test 1", "requirement": "Req 1"}')
} else {
return Promise.resolve('{"title": "Test 2", "requirement": "Req 2"}')
}
})
const result = await fileService.readAllJsonFiles('/test/dir')
expect(result).toHaveLength(2)
expect(result[0]).toEqual({
name: 'test1.json',
content: {
title: 'Test 1',
requirement: 'Req 1',
},
})
expect(result[1]).toEqual({
name: 'test2.json',
content: {
title: 'Test 2',
requirement: 'Req 2',
},
})
})
test('should handle mixed valid and invalid JSON files', async () => {
// Setup fresh mocks for this test
const mockFiles = ['valid.json', 'invalid.json']
const mockContents = new Map([
['/test/dir/valid.json', '{"title": "Valid", "requirement": "Valid req"}'],
['/test/dir/invalid.json', 'invalid json content'],
])
mockReaddir.mockResolvedValue(mockFiles)
mockReadFile.mockImplementation((path: string) => Promise.resolve(mockContents.get(path)))
const result = await fileService.readAllJsonFiles('/test/dir')
expect(result).toHaveLength(2)
expect(result).toEqual([
{
name: 'valid.json',
content: {
title: 'Valid',
requirement: 'Valid req',
},
},
{
name: 'invalid.json',
content: null,
error: 'Invalid JSON',
},
])
})
test('should handle invalid JSON files', async () => {
mockReadFile.mockResolvedValue('invalid json')
const result = await fileService.readAllJsonFiles('/test/dir')
expect(result[0]).toEqual({
name: 'test.json',
content: null,
error: 'Invalid JSON',
})
})
test('should return empty array when directory does not exist', async () => {
mockReaddir.mockRejectedValue(new Error('Directory not found'))
const result = await fileService.readAllJsonFiles('/test/dir')
expect(result).toEqual([])
})
})
describe('isDirectory', () => {
test('should return true for valid directory', async () => {
const result = await fileService.isDirectory('/test/dir')
expect(result).toBe(true)
})
test('should return false for invalid directory', async () => {
mockReaddir.mockRejectedValue(new Error())
const result = await fileService.isDirectory('/test/dir')
expect(result).toBe(false)
})
})
})