Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions packages/cli/tests/config-loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,111 @@ describe('config loader', () => {
expect(config?.output.dir).toBe('./docs');
});

it('loads TypeScript config files', async () => {
const tempDir = await createTempDir();
const configPath = path.join(tempDir, 'autodocs.config.ts');
await fs.writeFile(
configPath,
`export default { include: ['src/**/*.ts'], output: { dir: './typed', format: 'json' } };`,
'utf-8'
);

const config = await loadConfig(tempDir);
expect(config).not.toBeNull();
expect(config?.output.dir).toBe('./typed');
expect(config?.output.format).toBe('json');
});

it('loads JSON config from an explicit config path', async () => {
const tempDir = await createTempDir();
const configPath = path.join(tempDir, 'autodocs.config.json');
await fs.writeFile(
configPath,
JSON.stringify({ include: ['lib/**/*.ts'], output: { dir: './explicit', format: 'json' } }),
'utf-8'
);

const config = await loadConfig(configPath);
expect(config).not.toBeNull();
expect(config?.include).toContain('lib/**/*.ts');
expect(config?.output.dir).toBe('./explicit');
expect(config?.output.format).toBe('json');
});

it('returns null when no config file exists', async () => {
const tempDir = await createTempDir();
const config = await loadConfig(tempDir);
expect(config).toBeNull();
});

it('falls back to manual JSON parsing when cosmiconfig returns null for explicit path', async () => {
const tempDir = await createTempDir();
const configPath = path.join(tempDir, 'autodocs.config.json');
await fs.writeFile(
configPath,
JSON.stringify({ output: { dir: './fallback-json', format: 'json' } }),
'utf-8'
);

await jest.isolateModulesAsync(async () => {
jest.doMock('cosmiconfig', () => ({
cosmiconfig: () => ({
search: jest.fn(),
load: jest.fn().mockResolvedValue(null),
}),
}));

const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader');
const config = await isolatedLoadConfig(configPath);
expect(config).not.toBeNull();
expect(config?.output.dir).toBe('./fallback-json');
expect(config?.output.format).toBe('json');
});
});

it('falls back to jiti for explicit JS config when cosmiconfig returns null for explicit path', async () => {
const tempDir = await createTempDir();
const configPath = path.join(tempDir, 'autodocs.config.js');
await fs.writeFile(
configPath,
`module.exports = { output: { dir: './fallback-js', format: 'json' } };`,
'utf-8'
);

await jest.isolateModulesAsync(async () => {
jest.doMock('cosmiconfig', () => ({
cosmiconfig: () => ({
search: jest.fn(),
load: jest.fn().mockResolvedValue(null),
}),
}));

const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader');
const config = await isolatedLoadConfig(configPath);
expect(config).not.toBeNull();
expect(config?.output.dir).toBe('./fallback-js');
expect(config?.output.format).toBe('json');
});
});

it('wraps loader errors with a clear message', async () => {
const tempDir = await createTempDir();

await jest.isolateModulesAsync(async () => {
jest.doMock('cosmiconfig', () => ({
cosmiconfig: () => ({
search: jest.fn().mockRejectedValue(new Error('broken loader')),
load: jest.fn(),
}),
}));

const { loadConfig: isolatedLoadConfig } = await import('../src/config/loader');
await expect(isolatedLoadConfig(tempDir)).rejects.toThrow(
'Failed to load config: broken loader'
);
});
});

it('resolves relative paths', async () => {
const tempDir = await createTempDir();
const config = resolveConfigPaths(
Expand Down
Loading