import { describe, expect, it } from 'vitest';import { LessonsManager } from '../tools/prr/state/lessons.js';function normalize(lesson: string): string | null { const manager = new LessonsManager('test-owner', 'test-repo', 'test-branch'); return (manager as any).normalizeLessonText(lesson) as string | null;}describe('normalizeLessonText (direct)', () => { it('strips code blocks and keeps lesson text or returns null', () => { expect( normalize('```ts\nconst x = 1;\n```\n# Header\n**Bold line**\n- Keep this lesson text for later reference') ).toBe('Keep this lesson text for later reference'); expect(normalize('```ts\ncode\n```\n# Header\n**Bold line**')).toBe(null); }); it('normalizes lists and bullets to single line', () => { expect(normalize('1. item one\n2. item two\n- bullet\n+ plus\n* star')).toBe('item one item two bullet plus'); expect(normalize('- **bold bullet**\n- kept lesson about sync errors')).toBe('kept lesson about sync errors'); }); it('strips comment-only lines but keeps lesson after', () => { expect(normalize('// comment only')).toBe(null); expect(normalize('// comment only\n- keep this lesson about conflict resolution')).toBe( 'keep this lesson about conflict resolution' ); expect(normalize('/* comment */\n1. keep this lesson about merge failures')).toBe( 'keep this lesson about merge failures' ); }); it('strips code-like lines but keeps lesson on same input', () => { expect(normalize('private isShuttingDown = false;\n- keep this lesson about safe shutdowns')).toBe( 'keep this lesson about safe shutdowns' ); expect(normalize('const foo = 1;\n- keep this lesson about timeouts')).toBe('keep this lesson about timeouts'); expect(normalize('class Foo {}\n- keep this lesson about retries')).toBe('keep this lesson about retries'); expect(normalize('import { foo } from "bar"\n- keep this lesson about error handling')).toBe( 'keep this lesson about error handling' ); }); it('strips (inferred) suffix', () => { expect(normalize('use this (inferred) before publishing changes')).toBe('use this before publishing changes'); }); it('strips file extension suffixes like - ts, - js, - ts:8', () => { expect(normalize('Always validate user input - ts')).toBe('Always validate user input'); expect(normalize('Always validate user input - js')).toBe('Always validate user input'); expect(normalize('Always validate user input - md')).toBe('Always validate user input'); expect(normalize('Always validate user input - json')).toBe('Always validate user input'); expect(normalize('Always validate user input - yml')).toBe('Always validate user input'); expect(normalize('Always validate user input - ts:8')).toBe('Always validate user input'); expect(normalize('ts:8` already includes all runners')).toBe('already includes all runners'); expect(normalize('Always document decisions - a:123')).toBe('Always document decisions'); expect(normalize('Always document decisions - a.ts:123')).toBe('Always document decisions - a.ts:123'); }); it('normalizes tool-made-no-changes phrasing', () => { expect( normalize('claude-code with gpt-5-mini made no changes: without explanation - trying different approach') ).toBe('tool made no changes without explanation - trying different approach'); expect(normalize('tool made no changes, tool made no changes and tool made no changes')).toBe( 'tool made no changes' ); }); it('preserves or drops Fix for / rejected lines as expected', () => { expect( normalize('Fix for README.md:null rejected: The diff only adds an import for `rm` from fs/promises') ).toBe('Fix for README.md rejected: The diff only adds an import for `rm` from fs/promises'); expect(normalize('Fix for src/resolver.ts:null - (inferred) : string;')).toBe(null); expect(normalize('Do NOT repeat them:')).toBe(null); expect(normalize('chars truncated')).toBe(null); }); it('handles edge cases', () => { expect(normalize('Always document decisions:')).toBe('Always document decisions'); expect(normalize('Always document decisions -')).toBe('Always document decisions'); expect(normalize('Fix for README.md. rejected: ok')).toBe('Fix for README.md rejected: ok'); expect(normalize('123')).toBe(null); expect(normalize('123.')).toBe(null); });});
import { describe, expect, it } from 'vitest';
import { LessonsManager } from '../tools/prr/state/lessons.js';
function normalize(lesson: string): string | null {
const manager = new LessonsManager('test-owner', 'test-repo', 'test-branch');
return (manager as any).normalizeLessonText(lesson) as string | null;
}
describe('normalizeLessonText (direct)', () => {
it('strips code blocks and keeps lesson text or returns null', () => {
expect(
normalize('```ts\nconst x = 1;\n```\n# Header\n**Bold line**\n- Keep this lesson text for later reference')
).toBe('Keep this lesson text for later reference');
expect(normalize('```ts\ncode\n```\n# Header\n**Bold line**')).toBe(null);
});
it('normalizes lists and bullets to single line', () => {
expect(normalize('1. item one\n2. item two\n- bullet\n+ plus\n* star')).toBe('item one item two bullet plus');
expect(normalize('- **bold bullet**\n- kept lesson about sync errors')).toBe('kept lesson about sync errors');
});
it('strips comment-only lines but keeps lesson after', () => {
expect(normalize('// comment only')).toBe(null);
expect(normalize('// comment only\n- keep this lesson about conflict resolution')).toBe(
'keep this lesson about conflict resolution'
);
expect(normalize('/* comment */\n1. keep this lesson about merge failures')).toBe(
'keep this lesson about merge failures'
);
});
it('strips code-like lines but keeps lesson on same input', () => {
expect(normalize('private isShuttingDown = false;\n- keep this lesson about safe shutdowns')).toBe(
'keep this lesson about safe shutdowns'
);
expect(normalize('const foo = 1;\n- keep this lesson about timeouts')).toBe('keep this lesson about timeouts');
expect(normalize('class Foo {}\n- keep this lesson about retries')).toBe('keep this lesson about retries');
expect(normalize('import { foo } from "bar"\n- keep this lesson about error handling')).toBe(
'keep this lesson about error handling'
);
});
it('strips (inferred) suffix', () => {
expect(normalize('use this (inferred) before publishing changes')).toBe('use this before publishing changes');
});
it('strips file extension suffixes like - ts, - js, - ts:8', () => {
expect(normalize('Always validate user input - ts')).toBe('Always validate user input');
expect(normalize('Always validate user input - js')).toBe('Always validate user input');
expect(normalize('Always validate user input - md')).toBe('Always validate user input');
expect(normalize('Always validate user input - json')).toBe('Always validate user input');
expect(normalize('Always validate user input - yml')).toBe('Always validate user input');
expect(normalize('Always validate user input - ts:8')).toBe('Always validate user input');
expect(normalize('ts:8` already includes all runners')).toBe('already includes all runners');
expect(normalize('Always document decisions - a:123')).toBe('Always document decisions');
expect(normalize('Always document decisions - a.ts:123')).toBe('Always document decisions - a.ts:123');
});
it('normalizes tool-made-no-changes phrasing', () => {
expect(
normalize('claude-code with gpt-5-mini made no changes: without explanation - trying different approach')
).toBe('tool made no changes without explanation - trying different approach');
expect(normalize('tool made no changes, tool made no changes and tool made no changes')).toBe(
'tool made no changes'
);
});
it('preserves or drops Fix for / rejected lines as expected', () => {
expect(
normalize('Fix for README.md:null rejected: The diff only adds an import for `rm` from fs/promises')
).toBe('Fix for README.md rejected: The diff only adds an import for `rm` from fs/promises');
expect(normalize('Fix for src/resolver.ts:null - (inferred) : string;')).toBe(null);
expect(normalize('Do NOT repeat them:')).toBe(null);
expect(normalize('chars truncated')).toBe(null);
});
it('handles edge cases', () => {
expect(normalize('Always document decisions:')).toBe('Always document decisions');
expect(normalize('Always document decisions -')).toBe('Always document decisions');
expect(normalize('Fix for README.md. rejected: ok')).toBe('Fix for README.md rejected: ok');
expect(normalize('123')).toBe(null);
expect(normalize('123.')).toBe(null);
});
});