Skip to content

Commit

Permalink
Ensure rewrites work with manual href/as correctly (#25112)
Browse files Browse the repository at this point in the history
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
ijjk and kodiakhq[bot] committed May 14, 2021
1 parent e6a05ee commit 5bff9ea
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ export default class Router implements BaseRouter {
window.location.href = url
return false
}
const shouldResolveHref = url === as || (options as any)._h

// for static pages with query params in the URL we delay
// marking the router ready until after the query is updated
Expand Down Expand Up @@ -976,7 +977,7 @@ export default class Router implements BaseRouter {
? removePathTrailingSlash(delBasePath(pathname))
: pathname

if (pathname !== '/_error') {
if (shouldResolveHref && pathname !== '/_error') {
if (process.env.__NEXT_HAS_REWRITES && as.startsWith('/')) {
const rewritesResult = resolveRewrites(
addBasePath(addLocale(cleanedAs, this.locale)),
Expand Down
10 changes: 10 additions & 0 deletions test/integration/rewrites-manual-href-as/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
rewrites() {
return [
{
source: '/rewrite-me',
destination: '/another',
},
]
},
}
24 changes: 24 additions & 0 deletions test/integration/rewrites-manual-href-as/pages/another.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useRouter } from 'next/router'
import Link from 'next/link'

export default function Page(props) {
const router = useRouter()

return (
<>
<p id="another">another page</p>
<p id="pathname">{router.pathname}</p>
<p id="query">{JSON.stringify(router.query)}</p>

<Link href="/?imageId=123" as="/preview/123">
<a id="to-modal">open modal for /preview/123</a>
</Link>
<br />

<Link href="/preview/123">
<a id="to-preview">go to /preview/123</a>
</Link>
<br />
</>
)
}
41 changes: 41 additions & 0 deletions test/integration/rewrites-manual-href-as/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useRouter } from 'next/router'
import Link from 'next/link'

export default function Page(props) {
const router = useRouter()

return (
<>
<p id="index">index page</p>
<p id="pathname">{router.pathname}</p>
<p id="query">{JSON.stringify(router.query)}</p>

{router.query.imageId ? <p id="modal">show modal</p> : null}

<Link href="/?imageId=123" as="/preview/123">
<a id="to-modal">open modal for /preview/123</a>
</Link>
<br />

<Link href="/preview/123">
<a id="to-preview">go to /preview/123</a>
</Link>
<br />

<Link href="/another">
<a id="to-another">go to /another</a>
</Link>
<br />

<Link href="/rewrite-me">
<a id="to-rewrite-me">go to /rewrite-me</a>
</Link>
<br />

<Link href="/" as="/rewrite-me">
<a id="to-index-as-rewrite">go to / as /rewrite-me</a>
</Link>
<br />
</>
)
}
59 changes: 59 additions & 0 deletions test/integration/rewrites-manual-href-as/pages/preview/[slug].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useRouter } from 'next/router'
import Link from 'next/link'

export const getStaticProps = ({ params }) => {
return {
props: {
params: params || null,
preview: true,
},
}
}

export const getStaticPaths = () => {
return {
paths: [],
fallback: 'blocking',
}
}

export default function Page(props) {
const router = useRouter()

return (
<>
<p id="preview">preview page</p>
<p id="pathname">{router.pathname}</p>
<p id="query">{JSON.stringify(router.query)}</p>
<p id="props">{JSON.stringify(props)}</p>

<Link href="/?imageId=123" as="/preview/123">
<a id="to-modal">open modal for /preview/123</a>
</Link>
<br />

<Link href="/preview/321">
<a id="to-preview">go to /preview/321</a>
</Link>
<br />

<Link href="/another">
<a id="to-another">go to /another</a>
</Link>
<br />

<Link href="/rewrite-me">
<a id="to-rewrite-me">go to /rewrite-me</a>
</Link>
<br />

<Link
href={{ pathname: '/preview/[slug]', query: { slug: '321' } }}
as="/rewrite-me"
>
<a id="to-preview-as-rewrite">go to /preview/321 as /rewrite-me</a>
</Link>
<br />
</>
)
}
173 changes: 173 additions & 0 deletions test/integration/rewrites-manual-href-as/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/* eslint-env jest */

import { join } from 'path'
import {
check,
findPort,
killApp,
launchApp,
nextBuild,
nextStart,
} from 'next-test-utils'
import webdriver from 'next-webdriver'

jest.setTimeout(1000 * 60 * 2)

const appDir = join(__dirname, '../')

let appPort
let app

const runTests = () => {
it('should allow manual href/as on index page', async () => {
const browser = await webdriver(appPort, '/')

expect(await browser.elementByCss('#index').text()).toBe('index page')
expect(await browser.hasElementByCssSelector('#modal')).toBeFalsy()
await browser.eval('window.beforeNav = 1')

await browser.elementByCss('#to-modal').click()

expect(await browser.elementByCss('#index').text()).toBe('index page')
expect(await browser.hasElementByCssSelector('#modal')).toBeTruthy()
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
imageId: '123',
})

await browser
.elementByCss('#to-preview')
.click()
.waitForElementByCss('#preview')

expect(await browser.elementByCss('#preview').text()).toBe('preview page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
slug: '123',
})

await browser.back()

await browser
.elementByCss('#to-another')
.click()
.waitForElementByCss('#another')

expect(await browser.elementByCss('#another').text()).toBe('another page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

await browser.back()

await browser.elementByCss('#to-rewrite-me').click()

expect(await browser.elementByCss('#another').text()).toBe('another page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

await browser.back()

await browser
.elementByCss('#to-index-as-rewrite')
.click()
.waitForElementByCss('#index')

expect(await browser.elementByCss('#index').text()).toBe('index page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})
})

it('should allow manual href/as on dynamic page', async () => {
const browser = await webdriver(appPort, '/preview/123')

expect(await browser.elementByCss('#preview').text()).toBe('preview page')
await browser.eval('window.beforeNav = 1')

await browser
.elementByCss('#to-modal')
.click()
.waitForElementByCss('#index')

expect(await browser.elementByCss('#index').text()).toBe('index page')
expect(await browser.hasElementByCssSelector('#modal')).toBeTruthy()
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
imageId: '123',
})

await browser
.elementByCss('#to-preview')
.click()
.waitForElementByCss('#preview')

expect(await browser.elementByCss('#preview').text()).toBe('preview page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
slug: '123',
})

await browser.elementByCss('#to-preview').click()

expect(await browser.elementByCss('#preview').text()).toBe('preview page')
expect(await browser.eval('window.beforeNav')).toBe(1)
await check(
async () =>
JSON.parse(
await browser.eval('document.querySelector("#query").innerHTML')
).slug,
'321'
)

await browser
.elementByCss('#to-another')
.click()
.waitForElementByCss('#another')

expect(await browser.elementByCss('#another').text()).toBe('another page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

await browser.back().waitForElementByCss('#preview')
await browser.elementByCss('#to-rewrite-me').click()

expect(await browser.elementByCss('#another').text()).toBe('another page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

await browser.back().waitForElementByCss('#preview')

await browser
.elementByCss('#to-preview-as-rewrite')
.click()
.waitForElementByCss('#preview')

expect(await browser.elementByCss('#preview').text()).toBe('preview page')
expect(await browser.eval('window.beforeNav')).toBe(1)
expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
slug: '321',
})
})
}

describe('rewrites manual href/as', () => {
describe('dev mode', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
})
afterAll(() => killApp(app))

runTests()
})

describe('production mode', () => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))

runTests()
})
})

0 comments on commit 5bff9ea

Please sign in to comment.