Repository: remix-run/react-router
File: packages/react-router-dom/__tests__/special-characters-test.tsx (TypeScript)

Code before:
  // Edge case scenarios where the incoming `char` (or string) is pre-encoded
  // because it contains special characters such as `&`, `%`, or `#`.  For these
  // we provide a `decodedChar` so we can assert the param value gets decoded
  // properly and so we can ensure we can match these decoded values in static
  // paths
  {
    char: "a%25b",
    pathChar: "a%25b",
    searchChar: "a%25b",
    hashChar: "a%25b",
    decodedChar: "a%b",
  },
  {
    char: "a%23b%25c",
    pathChar: "a%23b%25c",
    searchChar: "a%23b%25c",
    hashChar: "a%23b%25c",
    decodedChar: "a#b%c",
  },
  {
    char: "a%26b%25c",
    pathChar: "a%26b%25c",
    searchChar: "a%26b%25c",
    hashChar: "a%26b%25c",
    decodedChar: "a&b%c",
  },
];

describe("special character tests", () => {
  // Mutable vars we'll use to capture the useLocation/useParams values during
  // the render pass.  this avoids stringifying them into the DOM and parsing
  // them back out which can mess with the encoding
  let renderedUseLocation: Omit<Location, "state" | "key"> | null = null;
  let renderedParams: Params<string> | null = null;

  function CaptureLocation() {
    let location = {
      ...useLocation(),
      state: undefined,
      key: undefined,
    };
    let params = useParams();
    renderedUseLocation = {
      pathname: location.pathname,
      search: location.search,
      hash: location.hash,
    };
    renderedParams = params;
    return (
      <>
        <p>{location.pathname}</p>

Review comment (bug):
These are the net new tests for the bugs being reported, if you pre-encode because that portion of the URL has URL-sensitive characters - you weren't previously getting back the proper decoded value.  These are the only tests right now that have a different `char` versus `decodedChar`

Code after:
      }

      let routeElements = (
        <>
          <Route path="/path" element={<Comp heading="Static Route" />} />
          <Route
            path="/inline-param/:slug"
            element={<Comp heading="Inline Nested Param Route" />}
          />
          <Route path="/param">
            <Route
              path=":slug"
              element={<Comp heading="Parent Nested Param Route" />}
            />
          </Route>
          <Route
            path="/inline-splat/*"
            element={<Comp heading="Inline Nested Splat Route" />}
          />
          <Route path="/splat">
            <Route
              path="*"
              element={<Comp heading="Parent Nested Splat Route" />}
            />
          </Route>
          <Route
            path="/reset"
            element={<Link to={navigatePath}>Link to path</Link>}
          />
          <Route
            path="/descendant/:param/*"
            element={
              <Routes>
                <Route
                  path="match"
                  element={<Comp heading="Descendant Route" />}
                />
              </Routes>
            }
          />
          <Route path="/*" element={<Comp heading="Root Splat Route" />} />
        </>
      );

      // Render BrowserRouter at the initialized location and confirm we get
      // the right route match, window.location, useLocation(), and useParams()
      // values
      let ctx = render(
        <BrowserRouter window={testWindow}>
          <Routes>{routeElements}</Routes>
        </BrowserRouter>