vitess.io/vitess@v0.16.2/web/vtadmin/src/hooks/useSyncedURLParam.test.tsx (about)

     1  /**
     2   * Copyright 2021 The Vitess Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  import { act } from '@testing-library/react';
    17  import { renderHook } from '@testing-library/react-hooks';
    18  import { createMemoryHistory } from 'history';
    19  import { Router } from 'react-router-dom';
    20  
    21  import { useSyncedURLParam } from './useSyncedURLParam';
    22  
    23  describe('useSyncedURLParam', () => {
    24      it('should push to history when updating initially empty value', () => {
    25          const history = createMemoryHistory();
    26  
    27          jest.spyOn(history, 'push');
    28          jest.spyOn(history, 'replace');
    29  
    30          const { result } = renderHook(() => useSyncedURLParam('hello'), {
    31              wrapper: ({ children }) => {
    32                  return <Router history={history}>{children}</Router>;
    33              },
    34          });
    35  
    36          expect(history.location.search).toEqual('');
    37          expect(result.current.value).toEqual('');
    38  
    39          act(() => {
    40              result.current.updateValue('world');
    41          });
    42  
    43          expect(history.location.search).toEqual('?hello=world');
    44          expect(result.current.value).toEqual('world');
    45  
    46          expect(history.push).toHaveBeenCalledTimes(1);
    47          expect(history.replace).toHaveBeenCalledTimes(0);
    48      });
    49  
    50      it('should replace history when a value is already defined in the URL', () => {
    51          const history = createMemoryHistory({ initialEntries: ['/?hello=world'] });
    52  
    53          jest.spyOn(history, 'push');
    54          jest.spyOn(history, 'replace');
    55  
    56          const { result } = renderHook(() => useSyncedURLParam('hello'), {
    57              wrapper: ({ children }) => {
    58                  return <Router history={history}>{children}</Router>;
    59              },
    60          });
    61  
    62          expect(history.location.search).toEqual('?hello=world');
    63          expect(result.current.value).toEqual('world');
    64  
    65          act(() => {
    66              result.current.updateValue('moon');
    67          });
    68  
    69          expect(history.location.search).toEqual('?hello=moon');
    70          expect(result.current.value).toEqual('moon');
    71  
    72          expect(history.push).toHaveBeenCalledTimes(0);
    73          expect(history.replace).toHaveBeenCalledTimes(1);
    74      });
    75  
    76      it('should clear the URL parameter and push to history when given an empty value', () => {
    77          const history = createMemoryHistory({ initialEntries: ['/?hello=world'] });
    78  
    79          jest.spyOn(history, 'push');
    80          jest.spyOn(history, 'replace');
    81  
    82          const { result } = renderHook(() => useSyncedURLParam('hello'), {
    83              wrapper: ({ children }) => {
    84                  return <Router history={history}>{children}</Router>;
    85              },
    86          });
    87  
    88          expect(history.location.search).toEqual('?hello=world');
    89          expect(result.current.value).toEqual('world');
    90  
    91          act(() => {
    92              result.current.updateValue(null);
    93          });
    94  
    95          expect(history.location.search).toEqual('?');
    96          expect(result.current.value).toEqual('');
    97  
    98          expect(history.push).toHaveBeenCalledTimes(1);
    99          expect(history.replace).toHaveBeenCalledTimes(0);
   100      });
   101  
   102      it('should not modify unrelated URL parameters', () => {
   103          const history = createMemoryHistory({ initialEntries: ['/?goodbye=world'] });
   104  
   105          const { result } = renderHook(() => useSyncedURLParam('hello'), {
   106              wrapper: ({ children }) => {
   107                  return <Router history={history}>{children}</Router>;
   108              },
   109          });
   110  
   111          expect(history.location.search).toEqual('?goodbye=world');
   112          expect(result.current.value).toEqual('');
   113  
   114          act(() => {
   115              result.current.updateValue('moon');
   116          });
   117  
   118          expect(history.location.search).toEqual('?goodbye=world&hello=moon');
   119          expect(result.current.value).toEqual('moon');
   120  
   121          act(() => {
   122              result.current.updateValue(null);
   123          });
   124  
   125          expect(history.location.search).toEqual('?goodbye=world');
   126          expect(result.current.value).toEqual('');
   127      });
   128  
   129      // This is a longer, integration-y test that simulates traversing the history stack
   130      // with the browser's "back" button.
   131      it('should properly manipulate history given a sequence of inputs', () => {
   132          const history = createMemoryHistory();
   133  
   134          jest.spyOn(history, 'push');
   135          jest.spyOn(history, 'replace');
   136  
   137          const { result } = renderHook(() => useSyncedURLParam('sequence'), {
   138              wrapper: ({ children }) => {
   139                  return <Router history={history}>{children}</Router>;
   140              },
   141          });
   142  
   143          act(() => {
   144              result.current.updateValue('one');
   145          });
   146  
   147          expect(history.location.search).toEqual('?sequence=one');
   148          expect(result.current.value).toEqual('one');
   149  
   150          act(() => {
   151              result.current.updateValue('two');
   152          });
   153  
   154          expect(history.location.search).toEqual('?sequence=two');
   155          expect(result.current.value).toEqual('two');
   156  
   157          act(() => {
   158              result.current.updateValue(null);
   159          });
   160  
   161          expect(history.location.search).toEqual('?');
   162          expect(result.current.value).toEqual('');
   163  
   164          act(() => {
   165              result.current.updateValue('three');
   166          });
   167  
   168          expect(history.location.search).toEqual('?sequence=three');
   169          expect(result.current.value).toEqual('three');
   170  
   171          act(() => {
   172              history.back();
   173          });
   174  
   175          expect(history.location.search).toEqual('?');
   176          expect(result.current.value).toEqual('');
   177  
   178          act(() => {
   179              history.back();
   180          });
   181  
   182          expect(history.location.search).toEqual('?sequence=two');
   183          expect(result.current.value).toEqual('two');
   184  
   185          act(() => {
   186              history.back();
   187          });
   188  
   189          // Note that we expect to be missing the "one" value since it was *replaced* by "two"
   190          expect(history.location.search).toEqual('');
   191          expect(result.current.value).toEqual('');
   192      });
   193  });