xref: /expo/docs/common/headingManager.test.ts (revision e7a398eb)
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