xref: /expo/docs/common/headingManager.test.ts (revision fccf9c8c)
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, headings: [] };
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, depth: 1, type: 'text', _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, depth: 1, type: 'text' }] };
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 = {
43    maxHeadingDepth: 3,
44    headings: [{ title: META_TITLE, depth: META_LEVEL, type: 'text' }],
45  };
46  const headingManager = new HeadingManager(SluggerStub, meta);
47
48  test('finds info from meta', () => {
49    const result = headingManager.addHeading(META_TITLE);
50
51    expect(result.metadata).toBeDefined();
52    expect(result.title).toBe(META_TITLE);
53    expect(result.level).toBe(META_LEVEL);
54  });
55
56  test('falls back to base level if unspecified', () => {
57    const result = headingManager.addHeading('title not in meta', undefined);
58
59    expect(result.level).toBe(BASE_HEADING_LEVEL);
60  });
61
62  test('uses argument level over meta level', () => {
63    headingManager.metadata.headings?.forEach(it => (it._processed = false));
64
65    const result = headingManager.addHeading(META_TITLE, 4);
66
67    expect(result.level).toBe(4);
68  });
69
70  test('additional params override anything', () => {
71    const result = headingManager.addHeading('unused', 5, {
72      sidebarType: HeadingType.InlineCode,
73      sidebarTitle: 'The Override',
74      sidebarDepth: 2, // level = 4
75    });
76
77    expect(result.title).toBe('The Override');
78    expect(result.level).toBe(4);
79    expect(result.type).toBe(HeadingType.InlineCode);
80  });
81
82  test('level out of range unlisted', () => {
83    const tooLow = headingManager.addHeading('Too Low', BASE_HEADING_LEVEL - 1);
84    const ok = headingManager.addHeading('OK');
85    const tooHigh = headingManager.addHeading('Too High', 1337);
86
87    expect(headingManager.headings).toContain(ok);
88    expect(headingManager.headings).not.toContain(tooLow);
89    expect(headingManager.headings).not.toContain(tooHigh);
90  });
91
92  test('explicitly hidden are unlisted', () => {
93    const result = headingManager.addHeading('The Unlisted', 2, {
94      hideInSidebar: true,
95    });
96
97    expect(headingManager.headings).not.toContain(result);
98  });
99});
100