11const { describe, it } = require ( 'node:test' ) ;
22const assert = require ( 'node:assert' ) ;
3- const { getFlavorConfig, extractPRFlavor, FLAVOR_CONFIG } = require ( './dangerfile-utils.js' ) ;
3+ const { getFlavorConfig, extractPRFlavor, FLAVOR_CONFIG , findChangelogInsertionPoint , generateChangelogSuggestion } = require ( './dangerfile-utils.js' ) ;
44
55describe ( 'dangerfile-utils' , ( ) => {
66 describe ( 'getFlavorConfig' , ( ) => {
@@ -275,4 +275,240 @@ describe('dangerfile-utils', () => {
275275 } ) ;
276276 } ) ;
277277 } ) ;
278+
279+ describe ( 'findChangelogInsertionPoint' , ( ) => {
280+ it ( 'should find insertion point for existing Features section' , ( ) => {
281+ const changelog = `# Changelog
282+
283+ ## Unreleased
284+
285+ ### Features
286+
287+ - Existing feature ([#100](url))
288+
289+ ### Fixes
290+
291+ - Existing fix ([#99](url))
292+
293+ ## 1.0.0
294+
295+ Released content` ;
296+
297+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
298+ assert . deepStrictEqual ( result , {
299+ lineNumber : 7 , // Before "- Existing feature"
300+ createSection : false
301+ } ) ;
302+ } ) ;
303+
304+ it ( 'should find insertion point when Features section exists but is empty' , ( ) => {
305+ const changelog = `# Changelog
306+
307+ ## Unreleased
308+
309+ ### Features
310+
311+ ### Fixes
312+
313+ - Existing fix ([#99](url))` ;
314+
315+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
316+ assert . deepStrictEqual ( result , {
317+ lineNumber : 7 , // Right after "### Features" and empty line
318+ createSection : false
319+ } ) ;
320+ } ) ;
321+
322+ it ( 'should create section when Features section does not exist' , ( ) => {
323+ const changelog = `# Changelog
324+
325+ ## Unreleased
326+
327+ ### Fixes
328+
329+ - Existing fix ([#99](url))` ;
330+
331+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
332+ assert . deepStrictEqual ( result , {
333+ lineNumber : 4 , // Right after "## Unreleased"
334+ createSection : true ,
335+ sectionName : 'Features'
336+ } ) ;
337+ } ) ;
338+
339+ it ( 'should handle changelog with only Unreleased section' , ( ) => {
340+ const changelog = `# Changelog
341+
342+ ## Unreleased
343+
344+ ## 1.0.0
345+
346+ Released content` ;
347+
348+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
349+ assert . deepStrictEqual ( result , {
350+ lineNumber : 4 , // Right after "## Unreleased"
351+ createSection : true ,
352+ sectionName : 'Features'
353+ } ) ;
354+ } ) ;
355+
356+ it ( 'should return null when no Unreleased section found' , ( ) => {
357+ const changelog = `# Changelog
358+
359+ ## 1.0.0
360+
361+ Released content` ;
362+
363+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
364+ assert . strictEqual ( result , null ) ;
365+ } ) ;
366+
367+ it ( 'should handle case-insensitive Unreleased section' , ( ) => {
368+ const changelog = `# Changelog
369+
370+ ## unreleased
371+
372+ ### Features
373+
374+ - Existing feature ([#100](url))` ;
375+
376+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
377+ assert . deepStrictEqual ( result , {
378+ lineNumber : 7 ,
379+ createSection : false
380+ } ) ;
381+ } ) ;
382+
383+ it ( 'should handle different section names' , ( ) => {
384+ const changelog = `# Changelog
385+
386+ ## Unreleased
387+
388+ ### Security
389+
390+ - Security fix ([#101](url))` ;
391+
392+ const result = findChangelogInsertionPoint ( changelog , 'Fixes' ) ;
393+ assert . deepStrictEqual ( result , {
394+ lineNumber : 4 , // After "## Unreleased"
395+ createSection : true ,
396+ sectionName : 'Fixes'
397+ } ) ;
398+ } ) ;
399+
400+ it ( 'should handle extra whitespace around sections' , ( ) => {
401+ const changelog = `# Changelog
402+
403+ ## Unreleased
404+
405+ ### Features
406+
407+ - Existing feature ([#100](url))` ;
408+
409+ const result = findChangelogInsertionPoint ( changelog , 'Features' ) ;
410+ assert . deepStrictEqual ( result , {
411+ lineNumber : 7 , // Before " - Existing feature"
412+ createSection : false
413+ } ) ;
414+ } ) ;
415+ } ) ;
416+
417+ describe ( 'generateChangelogSuggestion' , ( ) => {
418+ it ( 'should generate bullet point for existing section' , ( ) => {
419+ const insertionInfo = { lineNumber : 7 , createSection : false } ;
420+ const result = generateChangelogSuggestion (
421+ 'feat: add new feature' ,
422+ 123 ,
423+ 'https://github.com/repo/pull/123' ,
424+ 'Features' ,
425+ insertionInfo
426+ ) ;
427+
428+ assert . strictEqual ( result , '- add new feature ([#123](https://github.com/repo/pull/123))' ) ;
429+ } ) ;
430+
431+ it ( 'should generate section with bullet point for new section' , ( ) => {
432+ const insertionInfo = { lineNumber : 4 , createSection : true , sectionName : 'Features' } ;
433+ const result = generateChangelogSuggestion (
434+ 'feat: add new feature' ,
435+ 123 ,
436+ 'https://github.com/repo/pull/123' ,
437+ 'Features' ,
438+ insertionInfo
439+ ) ;
440+
441+ assert . strictEqual ( result , '\n### Features\n\n- add new feature ([#123](https://github.com/repo/pull/123))' ) ;
442+ } ) ;
443+
444+ it ( 'should clean up PR title by removing conventional commit prefix' , ( ) => {
445+ const insertionInfo = { lineNumber : 7 , createSection : false } ;
446+
447+ const result1 = generateChangelogSuggestion (
448+ 'feat(auth): add OAuth support' ,
449+ 123 ,
450+ 'url' ,
451+ 'Features' ,
452+ insertionInfo
453+ ) ;
454+ assert . strictEqual ( result1 , '- add OAuth support ([#123](url))' ) ;
455+
456+ const result2 = generateChangelogSuggestion (
457+ 'fix: resolve memory leak' ,
458+ 124 ,
459+ 'url' ,
460+ 'Fixes' ,
461+ insertionInfo
462+ ) ;
463+ assert . strictEqual ( result2 , '- resolve memory leak ([#124](url))' ) ;
464+ } ) ;
465+
466+ it ( 'should handle non-conventional PR titles' , ( ) => {
467+ const insertionInfo = { lineNumber : 7 , createSection : false } ;
468+
469+ const result = generateChangelogSuggestion (
470+ 'Fix memory leak in authentication' ,
471+ 125 ,
472+ 'url' ,
473+ 'Fixes' ,
474+ insertionInfo
475+ ) ;
476+ assert . strictEqual ( result , '- Fix memory leak in authentication ([#125](url))' ) ;
477+ } ) ;
478+
479+ it ( 'should remove trailing periods from title' , ( ) => {
480+ const insertionInfo = { lineNumber : 7 , createSection : false } ;
481+
482+ const result = generateChangelogSuggestion (
483+ 'feat: add new feature...' ,
484+ 126 ,
485+ 'url' ,
486+ 'Features' ,
487+ insertionInfo
488+ ) ;
489+ assert . strictEqual ( result , '- add new feature ([#126](url))' ) ;
490+ } ) ;
491+
492+ it ( 'should handle various section names' , ( ) => {
493+ const insertionInfo = { lineNumber : 4 , createSection : true } ;
494+
495+ const securityResult = generateChangelogSuggestion (
496+ 'sec: fix vulnerability' ,
497+ 127 ,
498+ 'url' ,
499+ 'Security' ,
500+ insertionInfo
501+ ) ;
502+ assert . strictEqual ( securityResult , '\n### Security\n\n- fix vulnerability ([#127](url))' ) ;
503+
504+ const perfResult = generateChangelogSuggestion (
505+ 'perf: optimize queries' ,
506+ 128 ,
507+ 'url' ,
508+ 'Performance' ,
509+ insertionInfo
510+ ) ;
511+ assert . strictEqual ( perfResult , '\n### Performance\n\n- optimize queries ([#128](url))' ) ;
512+ } ) ;
513+ } ) ;
278514} ) ;
0 commit comments