Files
Claude-Code-Workflow/ccw/tests/integration/codexlens-ignore-pattern-routes.test.ts
catlog22 b2fc2f60f1 feat: implement ignore patterns and extension filters in CodexLens
- Added tests to ensure loading of ignore patterns and extension filters from settings.
- Implemented functionality to respect ignore patterns and extension filters during file indexing.
- Created integration tests for CodexLens ignore-pattern configuration routes.
- Added a new AdvancedTab component with tests for managing ignore patterns and extension filters.
- Established a comprehensive branding naming system for the Maestro project, including guidelines for package names, CLI commands, and directory structure.
2026-03-09 14:43:21 +08:00

145 lines
5.1 KiB
TypeScript

/**
* Integration tests for CodexLens ignore-pattern configuration routes.
*
* Notes:
* - Targets runtime implementation shipped in `ccw/dist`.
* - Calls route handler directly (no HTTP server required).
* - Uses temporary CODEXLENS_DATA_DIR to isolate ~/.codexlens writes.
*/
import { after, before, describe, it, mock } from 'node:test';
import assert from 'node:assert/strict';
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const CODEXLENS_HOME = mkdtempSync(join(tmpdir(), 'codexlens-ignore-home-'));
const PROJECT_ROOT = mkdtempSync(join(tmpdir(), 'codexlens-ignore-project-'));
const configRoutesUrl = new URL('../../dist/core/routes/codexlens/config-handlers.js', import.meta.url);
configRoutesUrl.searchParams.set('t', String(Date.now()));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let mod: any;
const originalEnv = {
CODEXLENS_DATA_DIR: process.env.CODEXLENS_DATA_DIR,
};
async function callConfigRoute(
initialPath: string,
method: string,
path: string,
body?: unknown,
): Promise<{ handled: boolean; status: number; json: any }> {
const url = new URL(path, 'http://localhost');
let status = 0;
let text = '';
let postPromise: Promise<void> | null = null;
const res = {
writeHead(code: number) {
status = code;
},
end(chunk?: unknown) {
text = chunk === undefined ? '' : String(chunk);
},
};
const handlePostRequest = (_req: unknown, _res: unknown, handler: (parsed: any) => Promise<any>) => {
postPromise = (async () => {
const result = await handler(body ?? {});
const errorValue = result && typeof result === 'object' ? result.error : undefined;
const statusValue = result && typeof result === 'object' ? result.status : undefined;
if (typeof errorValue === 'string' && errorValue.length > 0) {
res.writeHead(typeof statusValue === 'number' ? statusValue : 500);
res.end(JSON.stringify({ error: errorValue }));
return;
}
res.writeHead(200);
res.end(JSON.stringify(result));
})();
};
const handled = await mod.handleCodexLensConfigRoutes({
pathname: url.pathname,
url,
req: { method },
res,
initialPath,
handlePostRequest,
broadcastToClients() {},
});
if (postPromise) {
await postPromise;
}
return { handled, status, json: text ? JSON.parse(text) : null };
}
describe('codexlens ignore-pattern routes integration', async () => {
before(async () => {
process.env.CODEXLENS_DATA_DIR = CODEXLENS_HOME;
mock.method(console, 'log', () => {});
mock.method(console, 'warn', () => {});
mock.method(console, 'error', () => {});
mod = await import(configRoutesUrl.href);
});
after(() => {
mock.restoreAll();
process.env.CODEXLENS_DATA_DIR = originalEnv.CODEXLENS_DATA_DIR;
rmSync(CODEXLENS_HOME, { recursive: true, force: true });
rmSync(PROJECT_ROOT, { recursive: true, force: true });
});
it('GET /api/codexlens/ignore-patterns returns defaults before config exists', async () => {
const res = await callConfigRoute(PROJECT_ROOT, 'GET', '/api/codexlens/ignore-patterns');
assert.equal(res.handled, true);
assert.equal(res.status, 200);
assert.equal(res.json.success, true);
assert.equal(Array.isArray(res.json.patterns), true);
assert.equal(Array.isArray(res.json.extensionFilters), true);
assert.ok(res.json.patterns.includes('dist'));
assert.ok(res.json.extensionFilters.includes('*.min.js'));
});
it('POST /api/codexlens/ignore-patterns persists custom patterns and filters', async () => {
const saveRes = await callConfigRoute(PROJECT_ROOT, 'POST', '/api/codexlens/ignore-patterns', {
patterns: ['dist', 'frontend/dist'],
extensionFilters: ['*.min.js', 'frontend/skip.ts'],
});
assert.equal(saveRes.handled, true);
assert.equal(saveRes.status, 200);
assert.equal(saveRes.json.success, true);
assert.deepEqual(saveRes.json.patterns, ['dist', 'frontend/dist']);
assert.deepEqual(saveRes.json.extensionFilters, ['*.min.js', 'frontend/skip.ts']);
const settingsPath = join(CODEXLENS_HOME, 'settings.json');
assert.equal(existsSync(settingsPath), true);
const savedSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
assert.deepEqual(savedSettings.ignore_patterns, ['dist', 'frontend/dist']);
assert.deepEqual(savedSettings.extension_filters, ['*.min.js', 'frontend/skip.ts']);
const getRes = await callConfigRoute(PROJECT_ROOT, 'GET', '/api/codexlens/ignore-patterns');
assert.equal(getRes.status, 200);
assert.deepEqual(getRes.json.patterns, ['dist', 'frontend/dist']);
assert.deepEqual(getRes.json.extensionFilters, ['*.min.js', 'frontend/skip.ts']);
});
it('POST /api/codexlens/ignore-patterns rejects invalid entries', async () => {
const res = await callConfigRoute(PROJECT_ROOT, 'POST', '/api/codexlens/ignore-patterns', {
patterns: ['bad pattern!'],
});
assert.equal(res.handled, true);
assert.equal(res.status, 400);
assert.match(String(res.json.error), /Invalid patterns:/);
});
});