diff --git a/packages/wouter-preact/src/react-deps.js b/packages/wouter-preact/src/react-deps.js
index 3753c661..25de4db5 100644
--- a/packages/wouter-preact/src/react-deps.js
+++ b/packages/wouter-preact/src/react-deps.js
@@ -42,7 +42,7 @@ export function useSyncExternalStore(subscribe, getSnapshot, getSSRSnapshot) {
if (!is(_instance._value, getSnapshot())) {
forceUpdate({ _instance });
}
- }, [subscribe, value, getSnapshot]);
+ }, [subscribe, value, getSnapshot]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
if (!is(_instance._value, _instance._getSnapshot())) {
@@ -54,7 +54,7 @@ export function useSyncExternalStore(subscribe, getSnapshot, getSSRSnapshot) {
forceUpdate({ _instance });
}
});
- }, [subscribe]);
+ }, [subscribe]); // eslint-disable-line react-hooks/exhaustive-deps
return value;
}
diff --git a/packages/wouter/src/index.js b/packages/wouter/src/index.js
index 957a7be6..98f16376 100644
--- a/packages/wouter/src/index.js
+++ b/packages/wouter/src/index.js
@@ -231,7 +231,10 @@ export function useSearchParams() {
tempSearchParams = new URLSearchParams(
typeof nextInit === "function" ? nextInit(tempSearchParams) : nextInit
);
- navigate(location + "?" + tempSearchParams, options);
+ navigate(
+ location + (tempSearchParams.size ? "?" + tempSearchParams : ""),
+ options
+ );
});
return [searchParams, setSearchParams];
diff --git a/packages/wouter/test/history-patch.test.ts b/packages/wouter/test/history-patch.test.ts
index 5ec4e20d..4884e5e0 100644
--- a/packages/wouter/test/history-patch.test.ts
+++ b/packages/wouter/test/history-patch.test.ts
@@ -11,22 +11,20 @@ describe("history patch", () => {
});
test("history should be patched once", () => {
- const fn = mock();
- const { result, unmount } = renderHook(() => reactHook());
+ const pushStateFn = mock();
+ const { result } = renderHook(() => reactHook());
- addEventListener("pushState", (e) => {
- fn();
- });
+ addEventListener("pushState", pushStateFn);
expect(result.current[0]).toBe("/");
- expect(fn).toHaveBeenCalledTimes(0);
+ expect(pushStateFn).toHaveBeenCalledTimes(0);
act(() => result.current[1]("/hello"));
act(() => result.current[1]("/world"));
expect(result.current[0]).toBe("/world");
- expect(fn).toHaveBeenCalledTimes(2);
+ expect(pushStateFn).toHaveBeenCalledTimes(2);
- unmount();
+ removeEventListener("pushstate", pushStateFn);
});
});
diff --git a/packages/wouter/test/link.test.tsx b/packages/wouter/test/link.test.tsx
index 326d594c..74adf677 100644
--- a/packages/wouter/test/link.test.tsx
+++ b/packages/wouter/test/link.test.tsx
@@ -1,12 +1,10 @@
import { type MouseEventHandler } from "react";
-import { test, expect, afterEach, mock, describe } from "bun:test";
-import { render, cleanup, fireEvent, act } from "@testing-library/react";
+import { test, expect, mock, describe } from "bun:test";
+import { render, fireEvent, act } from "@testing-library/react";
import { Router, Link } from "../src/index.js";
import { memoryLocation } from "../src/memory-location.js";
-afterEach(cleanup);
-
describe("", () => {
test("renders a link with proper attributes", () => {
const { getByText } = render(
@@ -102,22 +100,22 @@ describe("", () => {
clickEvt.preventDefault();
fireEvent(getByTestId("link"), clickEvt);
- expect(location.pathname).not.toBe("/users");
+ expect(location.pathname).toBe("/");
});
test("ignores the navigation when event is cancelled", () => {
- const clickHandler: MouseEventHandler = (e) => {
- e.preventDefault();
- };
-
const { getByTestId } = render(
-
+ e.preventDefault()}
+ >
click
);
fireEvent.click(getByTestId("link"));
- expect(location.pathname).not.toBe("/users");
+ expect(location.pathname).toBe("/");
});
test("accepts an `onClick` prop, fired before the navigation", () => {
diff --git a/packages/wouter/test/memory-location.test.ts b/packages/wouter/test/memory-location.test.ts
index 3010bdfa..41a41b0c 100644
--- a/packages/wouter/test/memory-location.test.ts
+++ b/packages/wouter/test/memory-location.test.ts
@@ -5,32 +5,29 @@ import { memoryLocation } from "../src/memory-location.js";
test("returns a hook that is compatible with location spec", () => {
const { hook } = memoryLocation();
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
const [value, update] = result.current;
expect(typeof value).toBe("string");
expect(typeof update).toBe("function");
- unmount();
});
test("should support initial path", () => {
const { hook } = memoryLocation({ path: "/test-case" });
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
const [value] = result.current;
expect(value).toBe("/test-case");
- unmount();
});
test("should support initial path with query", () => {
const { searchHook } = memoryLocation({ path: "/test-case?foo=bar" });
- const { result, unmount } = renderHook(() => searchHook());
+ const { result } = renderHook(() => searchHook());
const value = result.current;
expect(value).toBe("foo=bar");
- unmount();
});
test("should support search path as parameter", () => {
@@ -39,55 +36,50 @@ test("should support search path as parameter", () => {
searchPath: "key=value",
});
- const { result, unmount } = renderHook(() => searchHook());
+ const { result } = renderHook(() => searchHook());
const value = result.current;
expect(value).toBe("foo=bar&key=value");
- unmount();
});
test('should return location hook that has initial path "/" by default', () => {
const { hook } = memoryLocation();
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
const [value] = result.current;
expect(value).toBe("/");
- unmount();
});
test('should return search hook that has initial query "" by default', () => {
const { searchHook } = memoryLocation();
- const { result, unmount } = renderHook(() => searchHook());
+ const { result } = renderHook(() => searchHook());
const value = result.current;
expect(value).toBe("");
- unmount();
});
test("should return standalone `navigate` method", () => {
const { hook, navigate } = memoryLocation();
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
act(() => navigate("/standalone"));
const [value] = result.current;
expect(value).toBe("/standalone");
- unmount();
});
test("should return location hook that supports navigation", () => {
const { hook } = memoryLocation();
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
act(() => result.current[1]("/location"));
const [value] = result.current;
expect(value).toBe("/location");
- unmount();
});
test("should record all history when `record` option is provided", () => {
@@ -97,7 +89,7 @@ test("should record all history when `record` option is provided", () => {
navigate: standalone,
} = memoryLocation({ record: true, path: "/test" });
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
act(() => standalone("/standalone"));
act(() => result.current[1]("/location"));
@@ -113,8 +105,6 @@ test("should record all history when `record` option is provided", () => {
act(() => result.current[1]("/location", { replace: true }));
expect(history).toStrictEqual(["/test", "/standalone", "/location"]);
-
- unmount();
});
test("should not have history when `record` option is falsy", () => {
@@ -145,7 +135,7 @@ test("should have reset method that reset hook location", () => {
record: true,
path: "/test",
});
- const { result, unmount } = renderHook(() => hook());
+ const { result } = renderHook(() => hook());
act(() => navigate("/location"));
@@ -158,6 +148,4 @@ test("should have reset method that reset hook location", () => {
expect(history).toStrictEqual(["/test"]);
expect(result.current[0]).toBe("/test");
-
- unmount();
});
diff --git a/packages/wouter/test/redirect.test.tsx b/packages/wouter/test/redirect.test.tsx
index 9f1f1066..b607ef98 100644
--- a/packages/wouter/test/redirect.test.tsx
+++ b/packages/wouter/test/redirect.test.tsx
@@ -1,83 +1,52 @@
import { test, expect } from "bun:test";
import { render } from "@testing-library/react";
-import { useState } from "react";
import { Redirect, Router } from "../src/index.js";
-export const customHookWithReturn =
- (initialPath = "/") =>
- () => {
- const [path, updatePath] = useState(initialPath);
- const navigate = (path: string) => {
- updatePath(path);
- return "foo";
- };
-
- return [path, navigate];
- };
-
test("renders nothing", () => {
- const { container, unmount } = render();
+ const { container } = render();
expect(container.childNodes.length).toBe(0);
- unmount();
});
test("results in change of current location", () => {
- const { unmount } = render();
+ render();
expect(location.pathname).toBe("/users");
- unmount();
});
test("supports `base` routers with relative path", () => {
- const { unmount } = render(
+ render(
);
expect(location.pathname).toBe("/app/nested");
- unmount();
});
test("supports `base` routers with absolute path", () => {
- const { unmount } = render(
+ render(
);
expect(location.pathname).toBe("/absolute");
- unmount();
});
test("supports replace navigation", () => {
const histBefore = history.length;
- const { unmount } = render();
+ render();
expect(location.pathname).toBe("/users");
expect(history.length).toBe(histBefore);
- unmount();
});
test("supports history state", () => {
const testState = { hello: "world" };
- const { unmount } = render();
+ render();
expect(location.pathname).toBe("/users");
expect(history.state).toStrictEqual(testState);
- unmount();
-});
-
-test("useLayoutEffect should return nothing", () => {
- const { unmount } = render(
- // @ts-expect-error
-
-
-
- );
-
- expect(location.pathname).toBe("/users");
- unmount();
});
diff --git a/packages/wouter/test/route.test.tsx b/packages/wouter/test/route.test.tsx
index 1d17ad2d..17e39694 100644
--- a/packages/wouter/test/route.test.tsx
+++ b/packages/wouter/test/route.test.tsx
@@ -1,13 +1,10 @@
-import { it, expect, afterEach } from "bun:test";
-import { render, act, cleanup } from "@testing-library/react";
+import { it, expect } from "bun:test";
+import { render, act } from "@testing-library/react";
import { Router, Route } from "../src/index.js";
import { memoryLocation } from "../src/memory-location.js";
import { ReactElement } from "react";
-// Clean up after each test to avoid DOM pollution
-afterEach(cleanup);
-
const testRouteRender = (initialPath: string, jsx: ReactElement) => {
return render(
{jsx}
@@ -87,7 +84,7 @@ it("supports `component` prop similar to React-Router", () => {
});
it("supports `base` routers with relative path", () => {
- const { container, unmount } = render(
+ const { container } = render(
Nested
@@ -102,8 +99,6 @@ it("supports `base` routers with relative path", () => {
expect(container.children).toHaveLength(1);
expect(container.firstChild).toHaveProperty("tagName", "H1");
-
- unmount();
});
it("supports `path` prop with regex", () => {
diff --git a/packages/wouter/test/setup.ts b/packages/wouter/test/setup.ts
index 8f17b3ba..731fbd5a 100644
--- a/packages/wouter/test/setup.ts
+++ b/packages/wouter/test/setup.ts
@@ -1,6 +1,7 @@
import { GlobalRegistrator } from "@happy-dom/global-registrator";
-import { expect } from "bun:test";
+import { expect, beforeEach, afterEach } from "bun:test";
import * as matchers from "@testing-library/jest-dom/matchers";
+import { cleanup } from "@testing-library/react";
// Register happy-dom globals (document, window, etc.)
GlobalRegistrator.register({
@@ -26,3 +27,10 @@ export const withoutLocation = (fn: () => T): T => {
globalThis.location = original;
}
};
+
+beforeEach(() => {
+ history.go(-history.length + 1);
+ history.replaceState(null, "", "/");
+});
+
+afterEach(cleanup);
diff --git a/packages/wouter/test/switch.test.tsx b/packages/wouter/test/switch.test.tsx
index cf9315f8..4abedd62 100644
--- a/packages/wouter/test/switch.test.tsx
+++ b/packages/wouter/test/switch.test.tsx
@@ -1,14 +1,11 @@
-import { it, expect, afterEach } from "bun:test";
+import { it, expect } from "bun:test";
import { Router, Route, Switch } from "../src/index.js";
import { memoryLocation } from "../src/memory-location.js";
-import { render, act, cleanup } from "@testing-library/react";
+import { render, act } from "@testing-library/react";
import { PropsWithChildren, ReactElement, JSX } from "react";
-// Clean up after each test to avoid DOM pollution
-afterEach(cleanup);
-
const raf = () => new Promise((resolve) => requestAnimationFrame(resolve));
const testRouteRender = (initialPath: string, jsx: ReactElement) => {
@@ -111,7 +108,7 @@ it("allows to specify which routes to render via `location` prop", () => {
it("always ensures the consistency of inner routes rendering", async () => {
history.replaceState(null, "", "/foo/bar");
- const { unmount } = render(
+ render(
{(params) => {
@@ -127,8 +124,6 @@ it("always ensures the consistency of inner routes rendering", async () => {
await raf();
history.pushState(null, "", "/");
});
-
- unmount();
});
it("supports catch-all routes with wildcard segments", async () => {
diff --git a/packages/wouter/test/use-browser-location.test.tsx b/packages/wouter/test/use-browser-location.test.tsx
index 97c01cc9..059d3dea 100644
--- a/packages/wouter/test/use-browser-location.test.tsx
+++ b/packages/wouter/test/use-browser-location.test.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
-import { test, expect, describe, beforeEach, afterEach } from "bun:test";
-import { renderHook, act, waitFor, cleanup } from "@testing-library/react";
+import { test, expect, describe } from "bun:test";
+import { renderHook, act, waitFor } from "@testing-library/react";
import {
useBrowserLocation,
navigate,
@@ -8,39 +8,32 @@ import {
useHistoryState,
} from "../src/use-browser-location.js";
-afterEach(cleanup);
-
test("returns a pair [value, update]", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
const [value, update] = result.current;
expect(typeof value).toBe("string");
expect(typeof update).toBe("function");
- unmount();
});
describe("`value` first argument", () => {
- beforeEach(() => history.replaceState(null, "", "/"));
-
test("reflects the current pathname", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
expect(result.current[0]).toBe("/");
- unmount();
});
test("reacts to `pushState` / `replaceState`", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
act(() => history.pushState(null, "", "/foo"));
expect(result.current[0]).toBe("/foo");
act(() => history.replaceState(null, "", "/bar"));
expect(result.current[0]).toBe("/bar");
- unmount();
});
test("supports history.back() navigation", async () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
act(() => history.pushState(null, "", "/foo"));
await waitFor(() => expect(result.current[0]).toBe("/foo"));
@@ -59,23 +52,17 @@ describe("`value` first argument", () => {
});
await waitFor(() => expect(result.current[0]).toBe("/"), { timeout: 1000 });
- unmount();
});
test("supports history state", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
- const { result: state, unmount: unmountState } = renderHook(() =>
- useHistoryState()
- );
+ const { result } = renderHook(() => useBrowserLocation());
+ const { result: state } = renderHook(() => useHistoryState());
const navigate = result.current[1];
act(() => navigate("/path", { state: { hello: "world" } }));
expect(state.current).toStrictEqual({ hello: "world" });
-
- unmount();
- unmountState();
});
test("uses fail-safe escaping", () => {
@@ -91,8 +78,6 @@ describe("`value` first argument", () => {
});
describe("`useSearch` hook", () => {
- beforeEach(() => history.replaceState(null, "", "/"));
-
test("allows to get current search string", () => {
const { result: searchResult } = renderHook(() => useSearch());
act(() => navigate("/foo?hello=world&whats=up"));
@@ -152,36 +137,33 @@ describe("`useSearch` hook", () => {
describe("`update` second parameter", () => {
test("rerenders the component", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
const update = result.current[1];
act(() => update("/about"));
expect(result.current[0]).toBe("/about");
- unmount();
});
test("changes the current location", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
const update = result.current[1];
act(() => update("/about"));
expect(location.pathname).toBe("/about");
- unmount();
});
test("saves a new entry in the History object", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
const update = result.current[1];
const histBefore = history.length;
act(() => update("/about"));
expect(history.length).toBe(histBefore + 1);
- unmount();
});
test("replaces last entry with a new entry in the History object", () => {
- const { result, unmount } = renderHook(() => useBrowserLocation());
+ const { result } = renderHook(() => useBrowserLocation());
const update = result.current[1];
const histBefore = history.length;
@@ -189,19 +171,15 @@ describe("`update` second parameter", () => {
expect(history.length).toBe(histBefore);
expect(location.pathname).toBe("/foo");
- unmount();
});
test("stays the same reference between re-renders (function ref)", () => {
- const { result, rerender, unmount } = renderHook(() =>
- useBrowserLocation()
- );
+ const { result, rerender } = renderHook(() => useBrowserLocation());
const updateWas = result.current[1];
rerender();
const updateNow = result.current[1];
expect(updateWas).toBe(updateNow);
- unmount();
});
});
diff --git a/packages/wouter/test/use-hash-location.test.tsx b/packages/wouter/test/use-hash-location.test.tsx
index 336af81e..3a2e7b17 100644
--- a/packages/wouter/test/use-hash-location.test.tsx
+++ b/packages/wouter/test/use-hash-location.test.tsx
@@ -1,4 +1,4 @@
-import { test, expect, beforeEach, mock } from "bun:test";
+import { test, expect, mock } from "bun:test";
import { renderHook, render, act } from "@testing-library/react";
import { renderToStaticMarkup } from "react-dom/server";
@@ -8,11 +8,6 @@ import { useHashLocation } from "../src/use-hash-location.js";
import { waitForHashChangeEvent } from "./test-utils";
import { ReactNode, useSyncExternalStore } from "react";
-beforeEach(() => {
- history.replaceState(null, "", "/");
- location.hash = "";
-});
-
test("gets current location from `location.hash`", () => {
location.hash = "/app/users";
const { result } = renderHook(() => useHashLocation());
@@ -195,7 +190,7 @@ test("works even if `hashchange` listeners are called asynchronously ", async ()
location.hash = "#/a";
});
- const { unmount } = render(
+ render(
@@ -215,7 +210,6 @@ test("works even if `hashchange` listeners are called asynchronously ", async ()
// paths should not contain "b", because the outer route
// does not match, so inner component should not be rendered
expect(paths).toEqual(["/a"]);
- unmount();
});
test("defines a custom way of rendering link hrefs", () => {
@@ -239,14 +233,14 @@ test("handles navigation with data: protocol", async () => {
const initialHistoryLength = history.length;
await waitForHashChangeEvent(() => {
- navigate("/new-path");
+ act(() => navigate("/new-path"));
});
expect(location.hash).toBe("#/new-path");
expect(history.length).toBe(initialHistoryLength + 1);
await waitForHashChangeEvent(() => {
- navigate("/another-path", { replace: true });
+ act(() => navigate("/another-path", { replace: true }));
});
expect(location.hash).toBe("#/another-path");
diff --git a/packages/wouter/test/use-location.test.tsx b/packages/wouter/test/use-location.test.tsx
index 3baee573..df4f3265 100644
--- a/packages/wouter/test/use-location.test.tsx
+++ b/packages/wouter/test/use-location.test.tsx
@@ -43,7 +43,6 @@ describe.each([
navigate: hashNavigation,
act: (cb: () => void) => waitForHashChangeEvent(() => act(cb)),
clear: () => {
- location.hash = "";
history.replaceState(null, "", "/");
},
},
@@ -61,19 +60,18 @@ describe.each([
beforeEach(() => stub.clear());
it("returns a pair [value, update]", () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({ hook: stub.hook }),
});
const [value, update] = result.current;
expect(typeof value).toBe("string");
expect(typeof update).toBe("function");
- unmount();
});
describe("`value` first argument", () => {
it("returns `/` when URL contains only a basepath", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/app",
hook: stub.hook,
@@ -82,11 +80,10 @@ describe.each([
await stub.act(() => stub.navigate("/app"));
expect(result.current[0]).toBe("/");
- unmount();
});
it("basepath should be case-insensitive", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/MyApp",
hook: stub.hook,
@@ -95,11 +92,10 @@ describe.each([
await stub.act(() => stub.navigate("/myAPP/users/JohnDoe"));
expect(result.current[0]).toBe("/users/JohnDoe");
- unmount();
});
it("returns an absolute path in case of unmatched base path", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/MyApp",
hook: stub.hook,
@@ -108,11 +104,10 @@ describe.each([
await stub.act(() => stub.navigate("/MyOtherApp/users/JohnDoe"));
expect(result.current[0]).toBe("~/MyOtherApp/users/JohnDoe");
- unmount();
});
it("automatically unescapes specials characters", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
hook: stub.hook,
}),
@@ -127,11 +122,10 @@ describe.each([
await stub.act(() => stub.navigate("/%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"));
expect(result.current[0]).toBe("/шеллы");
- unmount();
});
it("can accept unescaped basepaths", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/hello мир", // basepath is not escaped
hook: stub.hook,
@@ -140,12 +134,10 @@ describe.each([
await stub.act(() => stub.navigate("/hello%20%D0%BC%D0%B8%D1%80/rel"));
expect(result.current[0]).toBe("/rel");
-
- unmount();
});
it("can accept unescaped basepaths", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/hello%20%D0%BC%D0%B8%D1%80", // basepath is already escaped
hook: stub.hook,
@@ -154,25 +146,22 @@ describe.each([
await stub.act(() => stub.navigate("/hello мир/rel"));
expect(result.current[0]).toBe("/rel");
-
- unmount();
});
});
describe("`update` second parameter", () => {
it("rerenders the component", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({ hook: stub.hook }),
});
const update = result.current[1];
await stub.act(() => update("/about"));
expect(stub.location()).toBe("/about");
- unmount();
});
it("stays the same reference between re-renders (function ref)", () => {
- const { result, rerender, unmount } = renderHook(() => useLocation(), {
+ const { result, rerender } = renderHook(() => useLocation(), {
wrapper: createContainer({ hook: stub.hook }),
});
@@ -181,11 +170,10 @@ describe.each([
const updateNow = result.current[1];
expect(updateWas).toBe(updateNow);
- unmount();
});
it("supports a basepath", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/app",
hook: stub.hook,
@@ -196,11 +184,10 @@ describe.each([
await stub.act(() => update("/dashboard"));
expect(stub.location()).toBe("/app/dashboard");
- unmount();
});
it("ignores the '/' basepath", async () => {
- const { result, unmount } = renderHook(() => useLocation(), {
+ const { result } = renderHook(() => useLocation(), {
wrapper: createContainer({
base: "/",
hook: stub.hook,
@@ -211,7 +198,6 @@ describe.each([
await stub.act(() => update("/dashboard"));
expect(stub.location()).toBe("/dashboard");
- unmount();
});
});
});
diff --git a/packages/wouter/test/use-params.test.tsx b/packages/wouter/test/use-params.test.tsx
index a88be6b3..eb433d21 100644
--- a/packages/wouter/test/use-params.test.tsx
+++ b/packages/wouter/test/use-params.test.tsx
@@ -1,12 +1,9 @@
-import { act, renderHook, cleanup } from "@testing-library/react";
-import { test, expect, beforeEach, afterEach } from "bun:test";
+import { act, renderHook } from "@testing-library/react";
+import { test, expect } from "bun:test";
import { useParams, Router, Route, Switch } from "../src/index.js";
import { memoryLocation } from "../src/memory-location.js";
-beforeEach(() => history.replaceState(null, "", "/"));
-afterEach(cleanup);
-
test("returns empty object when used outside of ", () => {
const { result } = renderHook(() => useParams());
expect(result.current).toEqual({});
diff --git a/packages/wouter/test/use-search-params.test.tsx b/packages/wouter/test/use-search-params.test.tsx
index 151e68ee..27a0d2bf 100644
--- a/packages/wouter/test/use-search-params.test.tsx
+++ b/packages/wouter/test/use-search-params.test.tsx
@@ -1,9 +1,7 @@
import { renderHook, act } from "@testing-library/react";
import { useSearchParams, Router } from "../src/index.js";
import { navigate } from "../src/use-browser-location.js";
-import { it, expect, beforeEach } from "bun:test";
-
-beforeEach(() => history.replaceState(null, "", "/"));
+import { it, expect } from "bun:test";
it("can return browser search params", () => {
history.replaceState(null, "", "/users?active=true");
@@ -60,3 +58,10 @@ it("is safe against parameter injection", () => {
expect(result.current[0].get("search")).toBe("foo¶meter_injection=bar");
});
+
+it("does not add question mark when search string is empty", () => {
+ const { result } = renderHook(() => useSearchParams());
+
+ act(() => result.current[1]({}));
+ expect(location.href).toBe("https://wouter.dev/");
+});
diff --git a/packages/wouter/test/use-search.test.tsx b/packages/wouter/test/use-search.test.tsx
index cacd4577..0005ffbd 100644
--- a/packages/wouter/test/use-search.test.tsx
+++ b/packages/wouter/test/use-search.test.tsx
@@ -1,11 +1,8 @@
-import { renderHook, act, cleanup } from "@testing-library/react";
+import { renderHook, act } from "@testing-library/react";
import { useSearch, Router } from "../src/index.js";
import { navigate } from "../src/use-browser-location.js";
import { memoryLocation } from "../src/memory-location.js";
-import { test, expect, beforeEach, afterEach } from "bun:test";
-
-beforeEach(() => history.replaceState(null, "", "/"));
-afterEach(cleanup);
+import { test, expect } from "bun:test";
test("returns browser search string", () => {
history.replaceState(null, "", "/users?active=true");
diff --git a/packages/wouter/test/view-transitions.test.tsx b/packages/wouter/test/view-transitions.test.tsx
index 6c44c8bd..93dc7ebd 100644
--- a/packages/wouter/test/view-transitions.test.tsx
+++ b/packages/wouter/test/view-transitions.test.tsx
@@ -1,10 +1,13 @@
-import { test, expect, describe, mock, afterEach } from "bun:test";
-import { render, cleanup, fireEvent } from "@testing-library/react";
-import { Router, Link, useLocation, type AroundNavHandler } from "../src/index.js";
+import { test, expect, describe, mock } from "bun:test";
+import { render, fireEvent } from "@testing-library/react";
+import {
+ Router,
+ Link,
+ useLocation,
+ type AroundNavHandler,
+} from "../src/index.js";
import { memoryLocation } from "../src/memory-location.js";
-afterEach(cleanup);
-
describe("view transitions", () => {
test("Link with transition prop triggers aroundNav with transition in options", () => {
// 1. Setup: create aroundNav callback that captures calls
@@ -66,7 +69,8 @@ describe("view transitions", () => {
expect(aroundNav).toHaveBeenCalledTimes(1);
- const [, to, options] = (aroundNav as ReturnType).mock.calls[0];
+ const [, to, options] = (aroundNav as ReturnType).mock
+ .calls[0];
expect(to).toBe("/about");
expect(options.transition).toBe(true);
});