useQueryParamState.spec.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import {LocationFixture} from 'sentry-fixture/locationFixture';
  2. import {act, renderHook} from 'sentry-test/reactTestingLibrary';
  3. import {useLocation} from 'sentry/utils/useLocation';
  4. import {useNavigate} from 'sentry/utils/useNavigate';
  5. import {useQueryParamState} from 'sentry/views/dashboards/widgetBuilder/hooks/useQueryParamState';
  6. jest.mock('sentry/utils/useLocation');
  7. jest.mock('sentry/utils/useNavigate');
  8. const mockedUseLocation = jest.mocked(useLocation);
  9. const mockedUseNavigate = jest.mocked(useNavigate);
  10. describe('useQueryParamState', () => {
  11. beforeEach(() => {
  12. jest.useFakeTimers();
  13. });
  14. afterEach(() => {
  15. jest.useRealTimers();
  16. });
  17. it('should get the initial value from the query param', () => {
  18. mockedUseLocation.mockReturnValue(
  19. LocationFixture({query: {testField: 'initial state'}})
  20. );
  21. const {result} = renderHook(() => useQueryParamState({fieldName: 'testField'}));
  22. expect(result.current[0]).toBe('initial state');
  23. });
  24. it('should update the local state and the query param', () => {
  25. const mockedNavigate = jest.fn();
  26. mockedUseNavigate.mockReturnValue(mockedNavigate);
  27. const {result} = renderHook(() => useQueryParamState({fieldName: 'testField'}));
  28. act(() => {
  29. result.current[1]('newValue');
  30. });
  31. // The local state should be updated
  32. expect(result.current[0]).toBe('newValue');
  33. // The query param should not be updated yet
  34. expect(mockedNavigate).not.toHaveBeenCalledWith({
  35. ...LocationFixture(),
  36. query: {testField: 'initial state'},
  37. });
  38. // Run the timers to trigger queued updates
  39. jest.runAllTimers();
  40. // The query param should be updated
  41. expect(mockedNavigate).toHaveBeenCalledWith({
  42. ...LocationFixture(),
  43. query: {testField: 'newValue'},
  44. });
  45. // The local state should be still reflect the new value
  46. expect(result.current[0]).toBe('newValue');
  47. });
  48. it('should use the decoder function to decode the query param value if provided', () => {
  49. mockedUseLocation.mockReturnValue(
  50. LocationFixture({query: {testField: 'initial state'}})
  51. );
  52. const testDeserializer = (value: string) => `${value.toUpperCase()} - decoded`;
  53. const {result} = renderHook(() =>
  54. useQueryParamState({fieldName: 'testField', deserializer: testDeserializer})
  55. );
  56. expect(result.current[0]).toBe('INITIAL STATE - decoded');
  57. });
  58. it('can take any kind of value and serialize it to a string compatible with query params', () => {
  59. type TestType = {
  60. count: number;
  61. isActive: boolean;
  62. value: string;
  63. };
  64. const mockedNavigate = jest.fn();
  65. mockedUseNavigate.mockReturnValue(mockedNavigate);
  66. const testSerializer = (value: TestType) =>
  67. `${value.value} - ${value.count} - ${value.isActive}`;
  68. const {result} = renderHook(() =>
  69. useQueryParamState({fieldName: 'testField', serializer: testSerializer})
  70. );
  71. act(() => {
  72. result.current[1]({value: 'newValue', count: 2, isActive: true});
  73. });
  74. expect(mockedNavigate).toHaveBeenCalledWith({
  75. ...LocationFixture(),
  76. query: {testField: 'newValue - 2 - true'},
  77. });
  78. });
  79. });