Skip to content

Instantly share code, notes, and snippets.

@DanielBarbakadze
Created July 30, 2024 16:38
Show Gist options
  • Save DanielBarbakadze/7ad00231ec8ee2371a83e6b046bfafe5 to your computer and use it in GitHub Desktop.
Save DanielBarbakadze/7ad00231ec8ee2371a83e6b046bfafe5 to your computer and use it in GitHub Desktop.
use-query-params mocked adapter for Vitest (ReactRouter6Adapter, typescript)
import React, { useContext } from 'react';
import {
BrowserRouter,
useNavigate,
useLocation,
UNSAFE_NavigationContext,
UNSAFE_DataRouterContext,
} from 'react-router-dom';
import {
type QueryParamAdapterComponent,
type QueryParamAdapter,
} from 'use-query-params';
import { QueryParamProvider } from 'use-query-params';
type ChildrenProps = {
children?: React.ReactNode;
};
const ProvidersHoC = ({ children }: ChildrenProps) => (
<BrowserRouter>
<QueryParamProvider adapter={MockReactRouter6Adapter}>
{children}
</QueryParamProvider>
</BrowserRouter>
);
export { ProvidersHoC };
type Location = {
search?: string;
state?: unknown;
};
type Adapter = {
location: Location;
replace(location: Location): void;
push(location: Location): void;
};
type MockReactRouter6AdapterProps = {
readonly children: (adapter: QueryParamAdapter) => React.ReactElement | null;
};
const MockReactRouter6Adapter: QueryParamAdapterComponent = ({
children,
}: MockReactRouter6AdapterProps): React.ReactElement | null => {
const navigator = useContext(UNSAFE_NavigationContext)?.navigator;
const navigate = useNavigate();
const router = useContext(UNSAFE_DataRouterContext)?.router;
const location = useLocation();
const adapter: Adapter = {
replace(location2: Location) {
navigate(location2.search ?? '?', {
replace: true,
state: location2.state,
});
},
push(location2: Location) {
navigate(location2.search ?? '?', {
replace: false,
state: location2.state,
});
},
get location() {
return (
router?.state?.location ??
(navigator && 'location' in navigator
? navigator.location
: undefined) ??
location
);
},
};
return <>{children(adapter as QueryParamAdapter)}</>;
};
@DanielBarbakadze
Copy link
Author

This can be also a simpler implementation

import React from 'react';

type Location = {
  readonly search: string;
  readonly state?: any;
};

type Adapter = {
  location: Location;
  replace(location: Location): void;
  push(location: Location): void;
};

type MockReactRouter6AdapterProps = {
  readonly children: (adapter: Adapter) => React.ReactElement | null;
};

const MockReactRouter6Adapter = ({
  children,
}: MockReactRouter6AdapterProps): React.ReactElement | null => {
  const adapter: Adapter = {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    replace(location2: Location) {
      // Does nothing
    },
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    push(location2: Location) {
      // Does nothing
    },
    get location() {
      return { search: '' };
    },
  };

  return <>{children(adapter)}</>;
};

export { MockReactRouter6Adapter };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment