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

     1  import React from 'react';
     2  import { render, screen } from '@testing-library/react';
     3  import userEvent from '@testing-library/user-event';
     4  import { Maybe } from 'true-myth';
     5  import Toolbar from './Toolbar';
     6  import { HeadMode, TailMode } from './fitMode/fitMode';
     7  
     8  // since 'react-debounce-input' uses lodash.debounce under the hood
     9  jest.mock('lodash.debounce', () =>
    10    jest.fn((fn) => {
    11      fn.flush = () => {};
    12      return fn;
    13    })
    14  );
    15  
    16  describe('ProfileHeader', () => {
    17    beforeAll(() => {
    18      window.HTMLElement.prototype.getBoundingClientRect = function () {
    19        return {
    20          x: 0,
    21          y: 0,
    22          bottom: 0,
    23          right: 0,
    24          toJSON: () => {},
    25          height: 0,
    26          top: 0,
    27          left: 0,
    28          width: 900,
    29        };
    30      };
    31    });
    32  
    33    it('should render toolbar correctly', () => {
    34      const { asFragment } = render(
    35        <Toolbar
    36          view="both"
    37          flamegraphType="single"
    38          handleSearchChange={() => {}}
    39          reset={() => {}}
    40          updateFitMode={() => {}}
    41          fitMode={HeadMode}
    42          updateView={() => {}}
    43          isFlamegraphDirty={false}
    44          selectedNode={Maybe.nothing()}
    45          onFocusOnSubtree={() => {}}
    46          highlightQuery=""
    47        />
    48      );
    49  
    50      expect(screen.getByRole('toolbar')).toBeInTheDocument();
    51      expect(asFragment()).toMatchSnapshot();
    52    });
    53  
    54    describe('Reset button', () => {
    55      const onReset = jest.fn();
    56  
    57      beforeEach(() => {});
    58  
    59      afterEach(() => {
    60        jest.clearAllMocks();
    61      });
    62  
    63      it('renders as disabled when flamegraph is not dirty', () => {
    64        const component = (
    65          <Toolbar
    66            view="both"
    67            flamegraphType="single"
    68            isFlamegraphDirty={false}
    69            handleSearchChange={() => {}}
    70            reset={onReset}
    71            updateFitMode={() => {}}
    72            fitMode={HeadMode}
    73            updateView={() => {}}
    74            selectedNode={Maybe.nothing()}
    75            onFocusOnSubtree={() => {}}
    76            highlightQuery=""
    77          />
    78        );
    79        render(component);
    80        expect(screen.getByRole('button', { name: /Reset/ })).toBeDisabled();
    81      });
    82  
    83      it('calls onReset when clicked (and enabled)', () => {
    84        const component = (
    85          <Toolbar
    86            view="both"
    87            flamegraphType="single"
    88            isFlamegraphDirty
    89            handleSearchChange={() => {}}
    90            reset={onReset}
    91            updateFitMode={() => {}}
    92            fitMode={HeadMode}
    93            updateView={() => {}}
    94            selectedNode={Maybe.nothing()}
    95            onFocusOnSubtree={() => {}}
    96            highlightQuery=""
    97          />
    98        );
    99        render(component);
   100        expect(screen.getByRole('button', { name: /Reset/ })).not.toBeDisabled();
   101        screen.getByRole('button', { name: /Reset/ }).click();
   102  
   103        expect(onReset).toHaveBeenCalled();
   104      });
   105    });
   106  
   107    describe('HighlightSearch', () => {
   108      it('calls callback when typed', () => {
   109        const onChange = jest.fn();
   110  
   111        const component = (
   112          <Toolbar
   113            view="both"
   114            flamegraphType="single"
   115            isFlamegraphDirty
   116            handleSearchChange={onChange}
   117            reset={() => {}}
   118            updateFitMode={() => {}}
   119            fitMode={HeadMode}
   120            updateView={() => {}}
   121            selectedNode={Maybe.nothing()}
   122            onFocusOnSubtree={() => {}}
   123            highlightQuery=""
   124          />
   125        );
   126  
   127        render(component);
   128        userEvent.type(screen.getByRole('searchbox'), 'foobar');
   129        expect(onChange).toHaveBeenCalledWith('foobar');
   130      });
   131    });
   132  
   133    describe('FitMode', () => {
   134      const updateFitMode = jest.fn();
   135      const component = (
   136        <Toolbar
   137          view="both"
   138          flamegraphType="single"
   139          handleSearchChange={() => {}}
   140          reset={() => {}}
   141          updateFitMode={updateFitMode}
   142          fitMode={HeadMode}
   143          updateView={() => {}}
   144          isFlamegraphDirty={false}
   145          selectedNode={Maybe.nothing()}
   146          onFocusOnSubtree={() => {}}
   147          highlightQuery=""
   148        />
   149      );
   150  
   151      beforeEach(() => {
   152        render(component);
   153      });
   154  
   155      afterEach(() => {
   156        jest.clearAllMocks();
   157      });
   158  
   159      it('updates to HEAD first', () => {
   160        screen.getByRole('button', { name: 'Head first' }).click();
   161  
   162        expect(updateFitMode).toHaveBeenCalledWith(HeadMode);
   163      });
   164  
   165      it('updates to TAIL first', () => {
   166        screen.getByRole('button', { name: 'Tail first' }).click();
   167  
   168        expect(updateFitMode).toHaveBeenCalledWith(TailMode);
   169      });
   170    });
   171  
   172    describe('Focus on subtree', () => {
   173      it('renders as disabled when theres no selected node', () => {
   174        const component = (
   175          <Toolbar
   176            view="both"
   177            flamegraphType="single"
   178            isFlamegraphDirty={false}
   179            handleSearchChange={() => {}}
   180            reset={() => {}}
   181            updateFitMode={() => {}}
   182            fitMode={HeadMode}
   183            updateView={() => {}}
   184            selectedNode={Maybe.nothing()}
   185            onFocusOnSubtree={() => {}}
   186            highlightQuery=""
   187          />
   188        );
   189        render(component);
   190        expect(screen.getByRole('button', { name: /Collapse/ })).toBeDisabled();
   191      });
   192  
   193      it('calls callback when clicked', () => {
   194        const onFocusOnSubtree = jest.fn();
   195        const component = (
   196          <Toolbar
   197            view="both"
   198            flamegraphType="single"
   199            isFlamegraphDirty={false}
   200            handleSearchChange={() => {}}
   201            reset={() => {}}
   202            updateFitMode={() => {}}
   203            fitMode={HeadMode}
   204            updateView={() => {}}
   205            selectedNode={Maybe.just({ i: 999, j: 999 })}
   206            onFocusOnSubtree={onFocusOnSubtree}
   207            highlightQuery=""
   208          />
   209        );
   210  
   211        render(component);
   212        screen.getByRole('button', { name: /Collapse/ }).click();
   213  
   214        expect(onFocusOnSubtree).toHaveBeenCalledWith(999, 999);
   215      });
   216    });
   217  });