Skip to content

Commit

Permalink
New Router Tests (#38390)
Browse files Browse the repository at this point in the history
* test: added some test cases for new client side router

* tests: added additional test cases

* test: improved test support

* feat: added support for `<Link soft />`

* tests: improved test reliability

* tests: added more cases for catch-all routes

* tests: added app -> pages -> app tests

* tests: add tests for useCookies + useHeaders

* tests: added tests for usePreviewData

* tests: added more tests for hooks and client components

* tests: added tests for query/params handling

* tests: fix tests for param/query to use props

* tests: added some skipped tests for unimplemented features

* tests: linting

* refactor: updated TODO -> TODO-APP

* tests: added some more test cases

* tests: skipped failing test
  • Loading branch information
wyattjoh committed Jul 14, 2022
1 parent c1ce6bf commit 3430ac1
Show file tree
Hide file tree
Showing 39 changed files with 990 additions and 9 deletions.
44 changes: 36 additions & 8 deletions packages/next/client/link.tsx
Expand Up @@ -8,7 +8,10 @@ import {
} from '../shared/lib/router/router'
import { addLocale } from './add-locale'
import { RouterContext } from '../shared/lib/router-context'
import { AppRouterContext } from '../shared/lib/app-router-context'
import {
AppRouterContext,
AppRouterInstance,
} from '../shared/lib/app-router-context'
import { useIntersection } from './use-intersection'
import { getDomainLocale } from './get-domain-locale'
import { addBasePath } from './add-base-path'
Expand All @@ -28,6 +31,11 @@ type InternalLinkProps = {
href: Url
as?: Url
replace?: boolean

/**
* TODO-APP
*/
soft?: boolean
scroll?: boolean
shallow?: boolean
passHref?: boolean
Expand Down Expand Up @@ -95,10 +103,11 @@ function isModifiedEvent(event: React.MouseEvent): boolean {

function linkClicked(
e: React.MouseEvent,
router: NextRouter,
router: NextRouter | AppRouterInstance,
href: string,
as: string,
replace?: boolean,
soft?: boolean,
shallow?: boolean,
scroll?: boolean,
locale?: string | false,
Expand All @@ -117,12 +126,27 @@ function linkClicked(
e.preventDefault()

const navigate = () => {
// replace state instead of push if prop is present
router[replace ? 'replace' : 'push'](href, as, {
shallow,
locale,
scroll,
})
// If the router is an AppRouterInstance, then it'll have `softPush` and
// `softReplace`.
if ('softPush' in router && 'softReplace' in router) {
// If we're doing a soft navigation, use the soft variants of
// replace/push.
const method: keyof AppRouterInstance = soft
? replace
? 'softReplace'
: 'softPush'
: replace
? 'replace'
: 'push'

router[method](href)
} else {
router[replace ? 'replace' : 'push'](href, as, {
shallow,
locale,
scroll,
})
}
}

if (startTransition) {
Expand Down Expand Up @@ -183,6 +207,7 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkPropsReal>(
const optionalPropsGuard: Record<LinkPropsOptional, true> = {
as: true,
replace: true,
soft: true,
scroll: true,
shallow: true,
passHref: true,
Expand Down Expand Up @@ -224,6 +249,7 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkPropsReal>(
}
} else if (
key === 'replace' ||
key === 'soft' ||
key === 'scroll' ||
key === 'shallow' ||
key === 'passHref' ||
Expand Down Expand Up @@ -264,6 +290,7 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkPropsReal>(
prefetch: prefetchProp,
passHref,
replace,
soft,
shallow,
scroll,
locale,
Expand Down Expand Up @@ -416,6 +443,7 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkPropsReal>(
href,
as,
replace,
soft,
shallow,
scroll,
locale,
Expand Down
11 changes: 11 additions & 0 deletions test/e2e/app-dir/app/app/catch-all/[...slug]/page.server.js
@@ -0,0 +1,11 @@
export function getServerSideProps({ params }) {
return { props: { params } }
}

export default function Page({ params }) {
return (
<h1 id="text" data-params={params.slug.join('/') ?? ''}>
hello from /catch-all/{params.slug.join('/')}
</h1>
)
}
@@ -0,0 +1,7 @@
export function getServerSideProps() {
return { props: {} }
}

export default function Page() {
return null
}
@@ -0,0 +1,7 @@
export function getStaticProps() {
return { props: {} }
}

export default function Page() {
return null
}
4 changes: 3 additions & 1 deletion test/e2e/app-dir/app/app/dashboard/page.server.js
Expand Up @@ -2,7 +2,9 @@ import ClientComp from './client-comp.client'
export default function DashboardPage(props) {
return (
<>
<p className="p">hello from app/dashboard</p>
<p id="from-dashboard" className="p">
hello from app/dashboard
</p>
<p className="green">this is green</p>
<ClientComp />
</>
Expand Down
@@ -0,0 +1,8 @@
import { useCookies } from 'next/dist/client/components/hooks-server'

export default function Page() {
// This should throw an error.
useCookies()

return null
}
19 changes: 19 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-cookies/page.server.js
@@ -0,0 +1,19 @@
import { useCookies } from 'next/dist/client/components/hooks-server'

export default function Page() {
const cookies = useCookies()

const hasCookie =
'use-cookies' in cookies && cookies['use-cookies'] === 'value'

return (
<>
<h1 id="text">hello from /hooks/use-cookies</h1>
{hasCookie ? (
<h2 id="has-cookie">Has use-cookies cookie</h2>
) : (
<h2 id="does-not-have-cookie">Does not have use-cookies cookie</h2>
)}
</>
)
}
@@ -0,0 +1,8 @@
import { useHeaders } from 'next/dist/client/components/hooks-server'

export default function Page() {
// This should throw an error.
useHeaders()

return null
}
22 changes: 22 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-headers/page.server.js
@@ -0,0 +1,22 @@
import { useHeaders } from 'next/dist/client/components/hooks-server'

export default function Page() {
const headers = useHeaders()

const hasHeader =
'x-use-headers' in headers && headers['x-use-headers'] === 'value'

return (
<>
<h1 id="text">hello from /hooks/use-headers</h1>
{hasHeader ? (
<h2 id="has-header">Has x-use-headers header</h2>
) : (
<h2 id="does-not-have-header">Does not have x-use-headers header</h2>
)}
{'referer' in headers && headers['referer'] && (
<h3 id="has-referer">Has referer header</h3>
)}
</>
)
}
@@ -0,0 +1,8 @@
import { useLayoutSegments } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
useLayoutSegments()

return null
}
@@ -0,0 +1,8 @@
import { useParams } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
useParams()

return null
}
13 changes: 13 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-pathname/page.client.js
@@ -0,0 +1,13 @@
import { usePathname } from 'next/dist/client/components/hooks-client'

export default function Page() {
const pathname = usePathname()

return (
<>
<h1 id="pathname" data-pathname={pathname}>
hello from /hooks/use-pathname
</h1>
</>
)
}
@@ -0,0 +1,8 @@
import { usePathname } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
usePathname()

return null
}
@@ -0,0 +1,8 @@
import { usePreviewData } from 'next/dist/client/components/hooks-server'

export default function Page() {
// This should throw an error.
usePreviewData()

return null
}
18 changes: 18 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-preview-data/page.server.js
@@ -0,0 +1,18 @@
import { usePreviewData } from 'next/dist/client/components/hooks-server'

export default function Page() {
const data = usePreviewData()

const hasData = !!data && data.key === 'value'

return (
<>
<h1>hello from /hooks/use-preview-data</h1>
{hasData ? (
<h2 id="has-preview-data">Has preview data</h2>
) : (
<h2 id="does-not-have-preview-data">Does not have preview data</h2>
)}
</>
)
}
17 changes: 17 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-router/page.client.js
@@ -0,0 +1,17 @@
import { useRouter } from 'next/dist/client/components/hooks-client'

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

return (
<>
<h1 id="router">hello from /hooks/use-router</h1>
<button
id="button-push"
onClick={() => router.push('/hooks/use-router/sub-page')}
>
Router Push
</button>
</>
)
}
@@ -0,0 +1,8 @@
import { useRouter } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
useRouter()

return null
}
@@ -0,0 +1,3 @@
export default function Page() {
return <h1 id="router-sub-page">hello from /hooks/use-router/sub-page</h1>
}
19 changes: 19 additions & 0 deletions test/e2e/app-dir/app/app/hooks/use-search-params/page.client.js
@@ -0,0 +1,19 @@
import { useSearchParams } from 'next/dist/client/components/hooks-client'

export default function Page() {
const params = useSearchParams()

return (
<>
<h1
id="params"
data-param-first={params.first ?? 'N/A'}
data-param-second={params.second ?? 'N/A'}
data-param-third={params.third ?? 'N/A'}
data-param-not-real={params.notReal ?? 'N/A'}
>
hello from /hooks/use-search-params
</h1>
</>
)
}
@@ -0,0 +1,8 @@
import { useSearchParams } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
useSearchParams()

return null
}
@@ -0,0 +1,8 @@
import { useSelectedLayoutSegment } from 'next/dist/client/components/hooks-client'

export default function Page() {
// This should throw an error.
useSelectedLayoutSegment()

return null
}
9 changes: 9 additions & 0 deletions test/e2e/app-dir/app/app/link-hard-push/page.server.js
@@ -0,0 +1,9 @@
import Link from 'next/link'

export default function Page() {
return (
<Link href="/with-id">
<a id="link">With ID</a>
</Link>
)
}
16 changes: 16 additions & 0 deletions test/e2e/app-dir/app/app/link-hard-replace/page.server.js
@@ -0,0 +1,16 @@
import { nanoid } from 'nanoid'
import Link from 'next/link'

export default function Page() {
return (
<>
<h1 id="render-id">{nanoid()}</h1>
<Link href="/link-hard-replace" replace>
<a id="self-link">Self Link</a>
</Link>
<Link href="/link-hard-replace/subpage" replace>
<a id="subpage-link">Subpage</a>
</Link>
</>
)
}
@@ -0,0 +1,9 @@
import Link from 'next/link'

export default function Page() {
return (
<Link href="/link-hard-replace" replace>
<a id="back-link">Self Link</a>
</Link>
)
}
9 changes: 9 additions & 0 deletions test/e2e/app-dir/app/app/link-soft-push/page.server.js
@@ -0,0 +1,9 @@
import Link from 'next/link'

export default function Page() {
return (
<Link href="/with-id" soft>
<a id="link">With ID</a>
</Link>
)
}

0 comments on commit 3430ac1

Please sign in to comment.