github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/packages/pyroscope-flamegraph/src/FlameGraph/FlameGraphComponent/index.spec.tsx (about)

     1  import React from 'react';
     2  import userEvent from '@testing-library/user-event';
     3  import { render, screen, waitFor } from '@testing-library/react';
     4  import { Maybe } from 'true-myth';
     5  import FlamegraphComponent from './index';
     6  import TestData from './testData';
     7  import { BAR_HEIGHT } from './constants';
     8  import { DefaultPalette, FlamegraphPalette } from './colorPalette';
     9  
    10  // the leaves have already been tested
    11  // this is just to guarantee code is compiling
    12  // and the callbacks are being called correctly
    13  describe('FlamegraphComponent', () => {
    14    const setPalette = (p: FlamegraphPalette) => {};
    15    it('renders', () => {
    16      const onZoom = jest.fn();
    17      const onReset = jest.fn();
    18      const isDirty = jest.fn();
    19      const onFocusOnNode = jest.fn();
    20  
    21      render(
    22        <FlamegraphComponent
    23          updateFitMode={() => ({})}
    24          selectedItem={Maybe.nothing()}
    25          setActiveItem={() => ({})}
    26          showCredit
    27          fitMode="HEAD"
    28          zoom={Maybe.nothing()}
    29          focusedNode={Maybe.nothing()}
    30          highlightQuery=""
    31          onZoom={onZoom}
    32          onFocusOnNode={onFocusOnNode}
    33          onReset={onReset}
    34          isDirty={isDirty}
    35          flamebearer={TestData.SimpleTree}
    36          palette={DefaultPalette}
    37          setPalette={setPalette}
    38        />
    39      );
    40    });
    41  
    42    it('resizes correctly', () => {
    43      const onZoom = jest.fn();
    44      const onReset = jest.fn();
    45      const isDirty = jest.fn();
    46      const onFocusOnNode = jest.fn();
    47  
    48      render(
    49        <FlamegraphComponent
    50          updateFitMode={() => ({})}
    51          selectedItem={Maybe.nothing()}
    52          setActiveItem={() => ({})}
    53          showCredit
    54          fitMode="HEAD"
    55          zoom={Maybe.nothing()}
    56          focusedNode={Maybe.nothing()}
    57          highlightQuery=""
    58          onZoom={onZoom}
    59          onFocusOnNode={onFocusOnNode}
    60          onReset={onReset}
    61          isDirty={isDirty}
    62          flamebearer={TestData.SimpleTree}
    63          palette={DefaultPalette}
    64          setPalette={setPalette}
    65        />
    66      );
    67  
    68      Object.defineProperty(window, 'innerWidth', {
    69        writable: true,
    70        configurable: true,
    71        value: 800,
    72      });
    73  
    74      window.dispatchEvent(new Event('resize'));
    75  
    76      // there's nothing much to assert here
    77      expect(window.innerWidth).toBe(800);
    78    });
    79  
    80    it('zooms on click', () => {
    81      const onZoom = jest.fn();
    82      const onReset = jest.fn();
    83      const isDirty = jest.fn();
    84      const onFocusOnNode = jest.fn();
    85  
    86      render(
    87        <FlamegraphComponent
    88          updateFitMode={() => ({})}
    89          selectedItem={Maybe.nothing()}
    90          setActiveItem={() => ({})}
    91          showCredit
    92          fitMode="HEAD"
    93          zoom={Maybe.nothing()}
    94          focusedNode={Maybe.nothing()}
    95          highlightQuery=""
    96          onZoom={onZoom}
    97          onFocusOnNode={onFocusOnNode}
    98          onReset={onReset}
    99          isDirty={isDirty}
   100          flamebearer={TestData.SimpleTree}
   101          palette={DefaultPalette}
   102          setPalette={setPalette}
   103        />
   104      );
   105  
   106      userEvent.click(screen.getByTestId('flamegraph-canvas'), {
   107        clientX: 0,
   108        clientY: BAR_HEIGHT * 3,
   109      });
   110  
   111      expect(onZoom).toHaveBeenCalled();
   112    });
   113  
   114    describe('context menu', () => {
   115      it(`enables "reset view" menuitem when it's dirty`, async () => {
   116        const onZoom = jest.fn();
   117        const onReset = jest.fn();
   118        const isDirty = jest.fn();
   119        const onFocusOnNode = jest.fn();
   120  
   121        const { rerender } = render(
   122          <FlamegraphComponent
   123            updateFitMode={() => ({})}
   124            selectedItem={Maybe.nothing()}
   125            setActiveItem={() => ({})}
   126            showCredit
   127            fitMode="HEAD"
   128            zoom={Maybe.nothing()}
   129            focusedNode={Maybe.nothing()}
   130            highlightQuery=""
   131            onZoom={onZoom}
   132            onFocusOnNode={onFocusOnNode}
   133            onReset={onReset}
   134            isDirty={isDirty}
   135            flamebearer={TestData.SimpleTree}
   136            palette={DefaultPalette}
   137            setPalette={setPalette}
   138          />
   139        );
   140  
   141        userEvent.click(screen.getByTestId('flamegraph-canvas'), {
   142          button: 2,
   143          clientX: 1,
   144          clientY: 1,
   145        });
   146  
   147        // should not be available unless we zoom
   148        await waitFor(() =>
   149          expect(
   150            screen.queryByRole('menuitem', { name: /Reset View/ })
   151          ).toHaveAttribute('aria-disabled', 'true')
   152        );
   153  
   154        // it's dirty now
   155        isDirty.mockReturnValue(true);
   156  
   157        rerender(
   158          <FlamegraphComponent
   159            updateFitMode={() => ({})}
   160            selectedItem={Maybe.nothing()}
   161            setActiveItem={() => ({})}
   162            showCredit
   163            fitMode="HEAD"
   164            zoom={Maybe.nothing()}
   165            focusedNode={Maybe.nothing()}
   166            highlightQuery=""
   167            onZoom={onZoom}
   168            onFocusOnNode={onFocusOnNode}
   169            onReset={onReset}
   170            isDirty={isDirty}
   171            flamebearer={TestData.SimpleTree}
   172            palette={DefaultPalette}
   173            setPalette={setPalette}
   174          />
   175        );
   176  
   177        userEvent.click(screen.getByTestId('flamegraph-canvas'), {
   178          button: 2,
   179        });
   180  
   181        // should be enabled now
   182        expect(
   183          screen.queryByRole('menuitem', { name: /Reset View/ })
   184        ).not.toHaveAttribute('aria-disabled', 'true');
   185      });
   186  
   187      it('triggers a highlight', () => {
   188        const onZoom = jest.fn();
   189        const onReset = jest.fn();
   190        const isDirty = jest.fn();
   191        const onFocusOnNode = jest.fn();
   192  
   193        render(
   194          <FlamegraphComponent
   195            updateFitMode={() => ({})}
   196            selectedItem={Maybe.nothing()}
   197            setActiveItem={() => ({})}
   198            showCredit
   199            fitMode="HEAD"
   200            zoom={Maybe.nothing()}
   201            focusedNode={Maybe.nothing()}
   202            highlightQuery=""
   203            onZoom={onZoom}
   204            onFocusOnNode={onFocusOnNode}
   205            onReset={onReset}
   206            isDirty={isDirty}
   207            flamebearer={TestData.SimpleTree}
   208            palette={DefaultPalette}
   209            setPalette={setPalette}
   210          />
   211        );
   212  
   213        // initially the context highlight is not visible
   214        expect(
   215          screen.getByTestId('flamegraph-highlight-contextmenu')
   216        ).not.toBeVisible();
   217  
   218        // then we click
   219        userEvent.click(screen.getByTestId('flamegraph-canvas'), { button: 2 });
   220  
   221        // should be visible now
   222        expect(
   223          screen.getByTestId('flamegraph-highlight-contextmenu')
   224        ).toBeVisible();
   225      });
   226    });
   227  
   228    describe('header', () => {
   229      const onZoom = jest.fn();
   230      const onReset = jest.fn();
   231      const isDirty = jest.fn();
   232      const onFocusOnNode = jest.fn();
   233  
   234      it('renders when type is single', () => {
   235        render(
   236          <FlamegraphComponent
   237            updateFitMode={() => ({})}
   238            selectedItem={Maybe.nothing()}
   239            setActiveItem={() => ({})}
   240            showCredit
   241            fitMode="HEAD"
   242            zoom={Maybe.nothing()}
   243            focusedNode={Maybe.nothing()}
   244            highlightQuery=""
   245            onZoom={onZoom}
   246            onFocusOnNode={onFocusOnNode}
   247            onReset={onReset}
   248            isDirty={isDirty}
   249            flamebearer={TestData.SimpleTree}
   250            palette={DefaultPalette}
   251            setPalette={setPalette}
   252            toolbarVisible
   253          />
   254        );
   255  
   256        expect(screen.queryByRole('heading', { level: 2 })).toHaveTextContent(
   257          'Frame width represents CPU time per function'
   258        );
   259      });
   260  
   261      it('renders when type is "double"', () => {
   262        const flamebearer = TestData.DiffTree;
   263        render(
   264          <FlamegraphComponent
   265            updateFitMode={() => ({})}
   266            selectedItem={Maybe.nothing()}
   267            setActiveItem={() => ({})}
   268            showCredit
   269            fitMode="HEAD"
   270            zoom={Maybe.nothing()}
   271            focusedNode={Maybe.nothing()}
   272            highlightQuery=""
   273            onZoom={onZoom}
   274            onFocusOnNode={onFocusOnNode}
   275            onReset={onReset}
   276            isDirty={isDirty}
   277            flamebearer={flamebearer}
   278            palette={DefaultPalette}
   279            setPalette={setPalette}
   280            toolbarVisible
   281          />
   282        );
   283  
   284        expect(screen.queryByRole('heading', { level: 2 })).toHaveTextContent(
   285          '(-) RemovedAdded (+)'
   286        );
   287  
   288        expect(screen.getByTestId('flamegraph-legend')).toBeInTheDocument();
   289      });
   290    });
   291  });