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 });