|
1 | 1 | import * as React from "react"; |
2 | 2 | import * as ReactDOM from "react-dom/client"; |
3 | 3 | import { act } from "react-dom/test-utils"; |
4 | | -import { MemoryRouter, Routes, Route, useSearchParams } from "../../index"; |
| 4 | +import { |
| 5 | + MemoryRouter, |
| 6 | + Routes, |
| 7 | + Route, |
| 8 | + useSearchParams, |
| 9 | + createBrowserRouter, |
| 10 | + useBlocker, |
| 11 | + RouterProvider, |
| 12 | + useLocation, |
| 13 | +} from "../../index"; |
5 | 14 |
|
6 | 15 | describe("useSearchParams", () => { |
7 | 16 | let node: HTMLDivElement; |
@@ -182,4 +191,107 @@ describe("useSearchParams", () => { |
182 | 191 | `"<p>value=initial&a=1&b=2</p>"` |
183 | 192 | ); |
184 | 193 | }); |
| 194 | + |
| 195 | + it("does not reflect functional update mutation when navigation is blocked", () => { |
| 196 | + let router = createBrowserRouter([ |
| 197 | + { |
| 198 | + path: "/", |
| 199 | + Component() { |
| 200 | + let location = useLocation(); |
| 201 | + let [searchParams, setSearchParams] = useSearchParams(); |
| 202 | + let [shouldBlock, setShouldBlock] = React.useState(false); |
| 203 | + let b = useBlocker(shouldBlock); |
| 204 | + return ( |
| 205 | + <> |
| 206 | + <pre id="output"> |
| 207 | + {`location.search=${location.search}`} |
| 208 | + {`searchParams=${searchParams.toString()}`} |
| 209 | + {`blocked=${b.state}`} |
| 210 | + </pre> |
| 211 | + <button |
| 212 | + id="toggle-blocking" |
| 213 | + onClick={() => setShouldBlock(!shouldBlock)} |
| 214 | + > |
| 215 | + Toggle Blocking |
| 216 | + </button> |
| 217 | + <button |
| 218 | + id="navigate1" |
| 219 | + onClick={() => { |
| 220 | + setSearchParams((prev) => { |
| 221 | + prev.set("foo", "bar"); |
| 222 | + return prev; |
| 223 | + }); |
| 224 | + }} |
| 225 | + > |
| 226 | + Navigate 1 |
| 227 | + </button> |
| 228 | + <button |
| 229 | + id="navigate2" |
| 230 | + onClick={() => { |
| 231 | + setSearchParams((prev) => { |
| 232 | + prev.set("foo", "baz"); |
| 233 | + return prev; |
| 234 | + }); |
| 235 | + }} |
| 236 | + > |
| 237 | + Navigate 2 |
| 238 | + </button> |
| 239 | + </> |
| 240 | + ); |
| 241 | + }, |
| 242 | + }, |
| 243 | + ]); |
| 244 | + |
| 245 | + act(() => { |
| 246 | + ReactDOM.createRoot(node).render(<RouterProvider router={router} />); |
| 247 | + }); |
| 248 | + |
| 249 | + expect(node.querySelector("#output")).toMatchInlineSnapshot(` |
| 250 | + <pre |
| 251 | + id="output" |
| 252 | + > |
| 253 | + location.search= |
| 254 | + searchParams= |
| 255 | + blocked=unblocked |
| 256 | + </pre> |
| 257 | + `); |
| 258 | + |
| 259 | + act(() => { |
| 260 | + node |
| 261 | + .querySelector("#navigate1")! |
| 262 | + .dispatchEvent(new Event("click", { bubbles: true })); |
| 263 | + }); |
| 264 | + |
| 265 | + expect(node.querySelector("#output")).toMatchInlineSnapshot(` |
| 266 | + <pre |
| 267 | + id="output" |
| 268 | + > |
| 269 | + location.search=?foo=bar |
| 270 | + searchParams=foo=bar |
| 271 | + blocked=unblocked |
| 272 | + </pre> |
| 273 | + `); |
| 274 | + |
| 275 | + act(() => { |
| 276 | + node |
| 277 | + .querySelector("#toggle-blocking")! |
| 278 | + .dispatchEvent(new Event("click", { bubbles: true })); |
| 279 | + }); |
| 280 | + |
| 281 | + act(() => { |
| 282 | + node |
| 283 | + .querySelector("#navigate2")! |
| 284 | + .dispatchEvent(new Event("click", { bubbles: true })); |
| 285 | + }); |
| 286 | + |
| 287 | + expect(node.querySelector("#output")).toMatchInlineSnapshot(` |
| 288 | + <pre |
| 289 | + id="output" |
| 290 | + > |
| 291 | + location.search=?foo=bar |
| 292 | + searchParams=foo=bar |
| 293 | + blocked=blocked |
| 294 | + </pre> |
| 295 | + `); |
| 296 | + }); |
185 | 297 | }); |
0 commit comments