This commit introduces a comprehensive Astro integration that automatically generates discovery files for websites: Features: - robots.txt with LLM bot support (Anthropic-AI, GPTBot, etc.) - llms.txt for AI assistant context and instructions - humans.txt for team credits and site information - Automatic sitemap integration via @astrojs/sitemap Technical Details: - TypeScript implementation with full type safety - Configurable HTTP caching headers - Custom template support for all generated files - Sensible defaults with extensive customization options - Date-based versioning (2025.11.03) Testing: - 34 unit tests covering all generators - Test coverage for robots.txt, llms.txt, and humans.txt - Integration with Vitest Documentation: - Comprehensive README with examples - API reference documentation - Contributing guidelines - Example configurations (minimal and full)
167 lines
4.2 KiB
TypeScript
167 lines
4.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { generateLLMsTxt } from '../src/generators/llms.js';
|
|
|
|
describe('generateLLMsTxt', () => {
|
|
const testURL = new URL('https://example.com');
|
|
|
|
it('generates basic llms.txt with site URL', async () => {
|
|
const result = await generateLLMsTxt({}, testURL);
|
|
|
|
expect(result).toContain('# example.com');
|
|
expect(result).toContain('**URL**: https://example.com/');
|
|
});
|
|
|
|
it('includes description when provided', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{ description: 'Test site description' },
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('> Test site description');
|
|
expect(result).toContain('**Description**: Test site description');
|
|
});
|
|
|
|
it('supports dynamic description function', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{ description: () => 'Dynamic description' },
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('> Dynamic description');
|
|
});
|
|
|
|
it('includes key features', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
keyFeatures: ['Feature 1', 'Feature 2', 'Feature 3'],
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Key Features');
|
|
expect(result).toContain('- Feature 1');
|
|
expect(result).toContain('- Feature 2');
|
|
});
|
|
|
|
it('includes important pages', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
importantPages: [
|
|
{
|
|
name: 'Docs',
|
|
path: '/docs',
|
|
description: 'Documentation',
|
|
},
|
|
],
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Important Pages');
|
|
expect(result).toContain('[Docs]');
|
|
expect(result).toContain('https://example.com/docs');
|
|
expect(result).toContain('Documentation');
|
|
});
|
|
|
|
it('supports async important pages function', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
importantPages: async () => [
|
|
{ name: 'Blog', path: '/blog' },
|
|
],
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('[Blog]');
|
|
});
|
|
|
|
it('includes AI instructions', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
instructions: 'Be helpful and accurate',
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Instructions for AI Assistants');
|
|
expect(result).toContain('Be helpful and accurate');
|
|
});
|
|
|
|
it('includes API endpoints', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
apiEndpoints: [
|
|
{
|
|
path: '/api/test',
|
|
method: 'POST',
|
|
description: 'Test endpoint',
|
|
},
|
|
],
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## API Endpoints');
|
|
expect(result).toContain('POST /api/test');
|
|
expect(result).toContain('Test endpoint');
|
|
});
|
|
|
|
it('includes tech stack', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
techStack: {
|
|
frontend: ['Astro', 'React'],
|
|
backend: ['Node.js'],
|
|
ai: ['Claude'],
|
|
},
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Technical Stack');
|
|
expect(result).toContain('**Frontend**: Astro, React');
|
|
expect(result).toContain('**Backend**: Node.js');
|
|
expect(result).toContain('**AI/ML**: Claude');
|
|
});
|
|
|
|
it('includes brand voice', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
brandVoice: ['Professional', 'Friendly'],
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Brand Voice & Guidelines');
|
|
expect(result).toContain('- Professional');
|
|
expect(result).toContain('- Friendly');
|
|
});
|
|
|
|
it('includes custom sections', async () => {
|
|
const result = await generateLLMsTxt(
|
|
{
|
|
customSections: {
|
|
'Contact': 'Email: test@example.com',
|
|
},
|
|
},
|
|
testURL
|
|
);
|
|
|
|
expect(result).toContain('## Contact');
|
|
expect(result).toContain('Email: test@example.com');
|
|
});
|
|
|
|
it('includes last updated date', async () => {
|
|
const result = await generateLLMsTxt({}, testURL);
|
|
const today = new Date().toISOString().split('T')[0];
|
|
|
|
expect(result).toContain(`**Last Updated**: ${today}`);
|
|
});
|
|
|
|
it('ends with newline', async () => {
|
|
const result = await generateLLMsTxt({}, testURL);
|
|
expect(result.endsWith('\n')).toBe(true);
|
|
});
|
|
});
|