import { describe, it, expect, beforeEach } from 'vitest';
import { resolve } from 'path';
import { PathResolver } from '../../src/utils/path-resolver.js';
import { readMdxTool } from '../../src/tools/read-mdx.js';
const FIXTURES_DIR = resolve(process.cwd(), 'tests', 'fixtures');
describe('read_mdx tool', () => {
let pathResolver: PathResolver;
beforeEach(() => {
pathResolver = new PathResolver(FIXTURES_DIR);
});
describe('successful reads', () => {
it('should read and convert basic MDX file', async () => {
const result = await readMdxTool(
{ path: 'basic-with-frontmatter.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
expect(result.content).toHaveLength(1);
expect(result.content[0].type).toBe('text');
const parsed = JSON.parse(result.content[0].text);
expect(parsed).toHaveProperty('markdown');
expect(parsed).toHaveProperty('originalPath');
expect(parsed).toHaveProperty('resolvedPath');
expect(parsed.markdown).toContain('Getting Started with MDX');
expect(parsed.originalPath).toBe('basic-with-frontmatter.mdx');
});
it('should handle MDX with JSX components', async () => {
const result = await readMdxTool(
{ path: 'simple-jsx.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.markdown).toContain('Interactive Documentation');
});
it('should handle MDX files that reference undefined components', async () => {
const result = await readMdxTool(
{ path: 'missing-component.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.markdown).toContain('This content uses an Alert component');
});
it('should handle MDX without frontmatter', async () => {
const result = await readMdxTool(
{ path: 'no-frontmatter.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.markdown).toContain('Simple MDX Document');
expect(parsed.markdown).toContain('Section 1');
});
it('should return absolute resolved path', async () => {
const result = await readMdxTool(
{ path: 'basic-with-frontmatter.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.resolvedPath).toBe(
resolve(FIXTURES_DIR, 'basic-with-frontmatter.mdx')
);
});
});
describe('error handling', () => {
it('should handle non-existent files', async () => {
const result = await readMdxTool(
{ path: 'nonexistent.mdx' },
pathResolver
);
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('File not found');
});
it('should handle unsafe paths (directory traversal)', async () => {
const result = await readMdxTool(
{ path: '../../etc/passwd' },
pathResolver
);
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('outside workspace root');
});
it('should handle absolute paths outside workspace', async () => {
const result = await readMdxTool(
{ path: '/etc/passwd' },
pathResolver
);
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('outside workspace root');
});
});
describe('path handling', () => {
it('should handle relative paths correctly', async () => {
const result = await readMdxTool(
{ path: './basic-with-frontmatter.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.markdown).toContain('Getting Started with MDX');
});
it('should preserve original path in response', async () => {
const originalPath = 'search-test.mdx';
const result = await readMdxTool(
{ path: originalPath },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.originalPath).toBe(originalPath);
});
});
describe('content validation', () => {
it('should return valid markdown content', async () => {
const result = await readMdxTool(
{ path: 'basic-with-frontmatter.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
expect(typeof parsed.markdown).toBe('string');
expect(parsed.markdown.length).toBeGreaterThan(0);
});
it('should convert JSX to markdown appropriately', async () => {
const result = await readMdxTool(
{ path: 'simple-jsx.mdx' },
pathResolver
);
expect(result.isError).toBeFalsy();
const parsed = JSON.parse(result.content[0].text);
// The markdown should still be readable
expect(parsed.markdown).toBeTruthy();
expect(typeof parsed.markdown).toBe('string');
});
});
});