1import GithubSlugger from 'github-slugger'; 2 3import { BASE_HEADING_LEVEL, HeadingManager, HeadingType } from './headingManager'; 4 5const SluggerStub: GithubSlugger = { 6 slug: str => str, 7 reset: () => {}, 8}; 9 10describe('HeadingManager tests', () => { 11 test('instantiates properly', () => { 12 const meta = { maxHeadingDepth: 2 }; 13 const headingManager = new HeadingManager(SluggerStub, meta); 14 15 expect(headingManager.headings).toEqual([]); 16 expect(headingManager.metadata.headings).toEqual([]); 17 expect(headingManager.maxNestingLevel).toBe(BASE_HEADING_LEVEL + 2); 18 }); 19 20 test('_findMetaForTitle not returning same title twice', () => { 21 const TITLE = 'Some Title'; 22 const meta = { headings: [{ title: TITLE, _processed: true }] }; 23 const headingManager = new HeadingManager(SluggerStub, meta); 24 25 const result = headingManager['findMetaForTitle'](TITLE); 26 expect(result).toBeUndefined(); 27 }); 28 29 test('_findMetaForTitle marks meta as processed', () => { 30 const TITLE = 'Some Title'; 31 const meta = { headings: [{ title: TITLE }] }; 32 const headingManager = new HeadingManager(SluggerStub, meta); 33 34 const result = headingManager['findMetaForTitle'](TITLE); 35 expect(result?._processed).toBeTruthy(); 36 }); 37}); 38 39describe('HeadingManager.addHeading()', () => { 40 const META_TITLE = 'Meta heading 1'; 41 const META_LEVEL = 3; 42 const meta = { maxHeadingDepth: 3, headings: [{ title: META_TITLE, level: META_LEVEL }] }; 43 const headingManager = new HeadingManager(SluggerStub, meta); 44 45 test('finds info from meta', () => { 46 const result = headingManager.addHeading(META_TITLE); 47 48 expect(result.metadata).toBeDefined(); 49 expect(result.title).toBe(META_TITLE); 50 expect(result.level).toBe(META_LEVEL); 51 }); 52 53 test('falls back to base level if unspecified', () => { 54 const result = headingManager.addHeading('title not in meta', undefined); 55 56 expect(result.level).toBe(BASE_HEADING_LEVEL); 57 }); 58 59 test('uses argument level over meta level', () => { 60 headingManager.metadata.headings?.forEach(it => (it._processed = false)); 61 62 const result = headingManager.addHeading(META_TITLE, 4); 63 64 expect(result.level).toBe(4); 65 }); 66 67 test('additional params override anything', () => { 68 const result = headingManager.addHeading('unused', 5, { 69 sidebarType: HeadingType.InlineCode, 70 sidebarTitle: 'The Override', 71 sidebarDepth: 2, // level = 4 72 }); 73 74 expect(result.title).toBe('The Override'); 75 expect(result.level).toBe(4); 76 expect(result.type).toBe(HeadingType.InlineCode); 77 }); 78 79 test('level out of range unlisted', () => { 80 const tooLow = headingManager.addHeading('Too Low', BASE_HEADING_LEVEL - 1); 81 const ok = headingManager.addHeading('OK'); 82 const tooHigh = headingManager.addHeading('Too High', 1337); 83 84 expect(headingManager.headings).toContain(ok); 85 expect(headingManager.headings).not.toContain(tooLow); 86 expect(headingManager.headings).not.toContain(tooHigh); 87 }); 88 89 test('explicitly hidden are unlisted', () => { 90 const result = headingManager.addHeading('The Unlisted', 2, { 91 hideInSidebar: true, 92 }); 93 94 expect(headingManager.headings).not.toContain(result); 95 }); 96}); 97