Welcome to mirror list, hosted at ThFree Co, Russian Federation.

render_sandboxed_mermaid_spec.js « markdown « behaviors « frontend « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: de0e5063e498150bc74030a1cf8325483d6fce72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { createWrapper } from '@vue/test-utils';
import { __ } from '~/locale';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import renderMermaid, {
  MAX_CHAR_LIMIT,
  MAX_MERMAID_BLOCK_LIMIT,
  LAZY_ALERT_SHOWN_CLASS,
} from '~/behaviors/markdown/render_sandboxed_mermaid';

describe('Mermaid diagrams renderer', () => {
  // Finders
  const findMermaidIframes = () => document.querySelectorAll('iframe[src="/-/sandbox/mermaid"]');
  const findDangerousMermaidAlert = () =>
    createWrapper(document.querySelector('[data-testid="alert-warning"]'));

  // Helpers
  const renderDiagrams = () => {
    renderMermaid([...document.querySelectorAll('.js-render-mermaid')]);
    jest.runAllTimers();
  };

  beforeEach(() => {
    document.body.dataset.page = '';
  });

  afterEach(() => {
    resetHTMLFixture();
  });

  it('renders a mermaid diagram', () => {
    setHTMLFixture('<pre><code class="js-render-mermaid"></code></pre>');

    expect(findMermaidIframes()).toHaveLength(0);

    renderDiagrams();

    expect(document.querySelector('pre').classList).toContain('gl-sr-only');
    expect(findMermaidIframes()).toHaveLength(1);
  });

  describe('within a details element', () => {
    beforeEach(() => {
      setHTMLFixture('<details><pre><code class="js-render-mermaid"></code></pre></details>');
      renderDiagrams();
    });

    it('does not render the diagram on load', () => {
      expect(findMermaidIframes()).toHaveLength(0);
    });

    it('render the diagram when the details element is opened', () => {
      document.querySelector('details').setAttribute('open', true);
      document.querySelector('details').dispatchEvent(new Event('toggle'));
      jest.runAllTimers();

      expect(findMermaidIframes()).toHaveLength(1);
    });
  });

  describe('dangerous diagrams', () => {
    describe(`when the diagram's source exceeds ${MAX_CHAR_LIMIT} characters`, () => {
      beforeEach(() => {
        setHTMLFixture(
          `<pre>
            <code class="js-render-mermaid">${Array(MAX_CHAR_LIMIT + 1)
              .fill('a')
              .join('')}</code>
          </pre>`,
        );
        renderDiagrams();
      });
      it('does not render the diagram on load', () => {
        expect(findMermaidIframes()).toHaveLength(0);
      });

      it('shows a warning about performance impact when rendering the diagram', () => {
        expect(document.querySelector('pre').classList).toContain(LAZY_ALERT_SHOWN_CLASS);
        expect(findDangerousMermaidAlert().exists()).toBe(true);
        expect(findDangerousMermaidAlert().text()).toContain(
          __('Warning: Displaying this diagram might cause performance issues on this page.'),
        );
      });

      it("renders the diagram when clicking on the alert's button", () => {
        findDangerousMermaidAlert().find('button').trigger('click');
        jest.runAllTimers();

        expect(findMermaidIframes()).toHaveLength(1);
      });
    });

    it(`stops rendering diagrams once the total rendered source exceeds ${MAX_CHAR_LIMIT} characters`, () => {
      setHTMLFixture(
        `<pre>
          <code class="js-render-mermaid">${Array(MAX_CHAR_LIMIT - 1)
            .fill('a')
            .join('')}</code>
          <code class="js-render-mermaid">2</code>
          <code class="js-render-mermaid">3</code>
          <code class="js-render-mermaid">4</code>
        </pre>`,
      );
      renderDiagrams();

      expect(findMermaidIframes()).toHaveLength(3);
    });

    // Note: The test case below is provided for convenience but should remain skipped as the DOM
    // operations it requires are too expensive and would significantly slow down the test suite.
    // eslint-disable-next-line jest/no-disabled-tests
    it.skip(`stops rendering diagrams when the rendered diagrams count exceeds ${MAX_MERMAID_BLOCK_LIMIT}`, () => {
      setHTMLFixture(
        `<pre>
          ${Array(MAX_MERMAID_BLOCK_LIMIT + 1)
            .fill('<code class="js-render-mermaid"></code>')
            .join('')}
        </pre>`,
      );
      renderDiagrams();

      expect([...document.querySelectorAll('.js-render-mermaid')]).toHaveLength(
        MAX_MERMAID_BLOCK_LIMIT + 1,
      );
      expect(findMermaidIframes()).toHaveLength(MAX_MERMAID_BLOCK_LIMIT);
    });
  });
});