From de0ddd32215c0d2008753b2f42a8a43a1921ab84 Mon Sep 17 00:00:00 2001 From: Nick Lucas Date: Wed, 15 Jan 2025 14:36:13 +0000 Subject: [PATCH 1/3] Add scenario --- e2e/react-router/basic/src/main.tsx | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/e2e/react-router/basic/src/main.tsx b/e2e/react-router/basic/src/main.tsx index 16eda46d5c..0b77eff88a 100644 --- a/e2e/react-router/basic/src/main.tsx +++ b/e2e/react-router/basic/src/main.tsx @@ -7,6 +7,7 @@ import { createRootRoute, createRoute, createRouter, + useNavigate, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/router-devtools' import { NotFoundError, fetchPost, fetchPosts } from './posts' @@ -59,6 +60,15 @@ function RootComponent() { > Layout {' '} + + Search Param Binding + {' '} I'm layout B! } +const searchParamBindingRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/search-param-binding', + component: SearchParamBindingComponent, + validateSearch: (input): { filter?: string } => { + return { + filter: typeof input.filter === 'string' ? input.filter : undefined, + } + }, +}) + +function SearchParamBindingComponent() { + const navigate = useNavigate() + const { filter } = searchParamBindingRoute.useSearch() + + return ( +
+ + navigate({ + to: '.', + search: { filter: e.target.value }, + }) + } + /> +
+ ) +} + const routeTree = rootRoute.addChildren([ postsRoute.addChildren([postRoute, postsIndexRoute]), layoutRoute.addChildren([ layout2Route.addChildren([layoutARoute, layoutBRoute]), ]), + searchParamBindingRoute, indexRoute, ]) From 1948bfb51d08b24589ceeb15e131d5fdb185f1e5 Mon Sep 17 00:00:00 2001 From: Nick Lucas Date: Wed, 15 Jan 2025 14:48:59 +0000 Subject: [PATCH 2/3] Write draft test --- e2e/react-router/basic/src/main.tsx | 2 +- e2e/react-router/basic/tests/app.spec.ts | 27 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/e2e/react-router/basic/src/main.tsx b/e2e/react-router/basic/src/main.tsx index 0b77eff88a..3eb8f3373f 100644 --- a/e2e/react-router/basic/src/main.tsx +++ b/e2e/react-router/basic/src/main.tsx @@ -232,7 +232,7 @@ function SearchParamBindingComponent() { return (
navigate({ diff --git a/e2e/react-router/basic/tests/app.spec.ts b/e2e/react-router/basic/tests/app.spec.ts index 5ccdafa513..927def6489 100644 --- a/e2e/react-router/basic/tests/app.spec.ts +++ b/e2e/react-router/basic/tests/app.spec.ts @@ -45,3 +45,30 @@ test('Navigating to a post page with viewTransition types', async ({ await page.getByRole('link', { name: 'sunt aut facere repe' }).click() await expect(page.getByRole('heading')).toContainText('sunt aut facere') }) + +test('#3162 - Binding an input to search params with stable cursor position', async ({ + page, +}) => { + await page + .getByRole('link', { name: 'Search Param Binding', exact: true }) + .click() + expect(page.url()).toBe('http://localhost:3000/search-param-binding') + + await page.getByRole('textbox', { name: 'Filter' }).fill('Hello World') + expect(page.getByRole('textbox', { name: 'Filter' })).toHaveValue('Hello World') + expect(page.url()).toBe('http://localhost:3000/search-param-binding?filter=Hello%20World') + + await page.getByRole('textbox', { name: 'Filter' }).click() + for (let i = 0; i < 5; i++) { + await page.keyboard.press('ArrowLeft') + } + await page.keyboard.press('Space') + await page.keyboard.press('H') + await page.keyboard.press('A') + await page.keyboard.press('P') + await page.keyboard.press('P') + await page.keyboard.press('Y') + await page.getByRole('textbox', { name: 'Filter' }).blur() + + expect(page.getByRole('textbox', { name: 'Filter' })).toHaveValue('Hello Happy World') + expect(page.url()).toBe('http://localhost:3000/search-param-binding?filter=Hello%20Happy%20World')}) From 2c972672d939b6c3e7346bba4d9fb53b95f1c16e Mon Sep 17 00:00:00 2001 From: Nick Lucas Date: Wed, 15 Jan 2025 14:56:08 +0000 Subject: [PATCH 3/3] Make test case run --- e2e/react-router/basic/src/main.tsx | 2 +- e2e/react-router/basic/tests/app.spec.ts | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/e2e/react-router/basic/src/main.tsx b/e2e/react-router/basic/src/main.tsx index 3eb8f3373f..756686d634 100644 --- a/e2e/react-router/basic/src/main.tsx +++ b/e2e/react-router/basic/src/main.tsx @@ -232,7 +232,7 @@ function SearchParamBindingComponent() { return (
navigate({ diff --git a/e2e/react-router/basic/tests/app.spec.ts b/e2e/react-router/basic/tests/app.spec.ts index 927def6489..6c6a069a8b 100644 --- a/e2e/react-router/basic/tests/app.spec.ts +++ b/e2e/react-router/basic/tests/app.spec.ts @@ -52,13 +52,13 @@ test('#3162 - Binding an input to search params with stable cursor position', as await page .getByRole('link', { name: 'Search Param Binding', exact: true }) .click() - expect(page.url()).toBe('http://localhost:3000/search-param-binding') + expect(page).toHaveURL(/.*\/search-param-binding/) - await page.getByRole('textbox', { name: 'Filter' }).fill('Hello World') - expect(page.getByRole('textbox', { name: 'Filter' })).toHaveValue('Hello World') - expect(page.url()).toBe('http://localhost:3000/search-param-binding?filter=Hello%20World') + await page.getByTestId('filter').fill('Hello World') + expect(page.getByTestId('filter')).toHaveValue('Hello World') + expect(page).toHaveURL(/.*\/search-param-binding\?filter=Hello%20World/) - await page.getByRole('textbox', { name: 'Filter' }).click() + await page.getByTestId('filter').click() for (let i = 0; i < 5; i++) { await page.keyboard.press('ArrowLeft') } @@ -68,7 +68,10 @@ test('#3162 - Binding an input to search params with stable cursor position', as await page.keyboard.press('P') await page.keyboard.press('P') await page.keyboard.press('Y') - await page.getByRole('textbox', { name: 'Filter' }).blur() + await page.getByTestId('filter').blur() - expect(page.getByRole('textbox', { name: 'Filter' })).toHaveValue('Hello Happy World') - expect(page.url()).toBe('http://localhost:3000/search-param-binding?filter=Hello%20Happy%20World')}) + expect(page.getByTestId('filter')).toHaveValue('Hello Happy World') + expect(page).toHaveURL( + /.*\/search-param-binding\?filter=Hello%20Happy%20World/, + ) +})