Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Router Tests #38390

Merged
merged 17 commits into from Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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>
)
}