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

Code before:
        expect(container.querySelector("form")?.getAttribute("action")).toBe(
          "/inbox/messages"
        );
      });

      it("navigates relative to the URL for layout routes", async () => {
        let router = createTestRouter(
          createRoutesFromElements(
            <Route path="inbox">
              <Route path="messages" />
              <Route
                path="messages/:id"
                element={
                  <>
                    <Form action=".." relative="path" />
                    <Outlet />
                  </>
                }
              >
                <Route index element={<h1>Form</h1>} />
              </Route>
            </Route>
          ),
          {
            window: getWindow("/inbox/messages/1"),
          }
        );
        let { container } = render(<RouterProvider router={router} />);

        expect(container.querySelector("form")?.getAttribute("action")).toBe(
          "/inbox/messages"
        );
      });

      it("navigates relative to the URL for index routes", async () => {
        let router = createTestRouter(
          createRoutesFromElements(
            <Route path="inbox">
              <Route path="messages" />
              <Route path="messages/:id">
                <Route index element={<Form action=".." relative="path" />} />
              </Route>
            </Route>
          ),
          {
            window: getWindow("/inbox/messages/1"),
          }
        );
        let { container } = render(<RouterProvider router={router} />);

        expect(container.querySelector("form")?.getAttribute("action")).toBe(

Review comment (suggestion):
`Form`/`fetcher.Form` did not have this issue since `useFormAction` handled it - but the logic in `useFormAction`to remove the `?index` param was naive and removed all index params, not preserving user-specified ones.  This PR also fixes that issue

Code after:
          await tick();
          await waitFor(() => screen.getByText(new RegExp("INDEX ACTION")));
          expect(getHtml(container.querySelector("#index")!)).toContain(
            "INDEX ACTION: http://localhost/parent?index&index=keep"
          );
        });

        it("Form", async () => {
          let router = createTestRouter(
            createRoutesFromElements(
              <Route
                id="parent"
                path="/parent"
                element={<Parent />}
                action={({ request }) => "PARENT ACTION: " + request.url}
              >
                <Route
                  id="index"
                  index
                  element={<Index />}
                  action={({ request }) => "INDEX ACTION: " + request.url}
                />
              </Route>
            ),
            {
              window: getWindow("/parent?index&index=keep"),
            }
          );
          let { container } = render(<RouterProvider router={router} />);

          function Parent() {
            let actionData = useActionData();
            return (
              <>
                <p id="parent">{actionData}</p>
                <Form method="post" id="parent-form">
                  <button type="submit">Submit from parent</button>
                </Form>
                <Outlet />
              </>
            );
          }

          function Index() {
            let actionData = useActionData();
            return (
              <>
                <p id="index">{actionData}</p>
                <Form method="post" id="index-form">
                  <button type="submit">Submit from index</button>
                </Form>