rsnext/test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts
Tim Neutkens db2e9b2870
Add tests for parallel routes / interception and handle router state patch merging client-side (#45615)
Added tests:
- Add tests for interception+parallel and interception
- Add test for  parallel route tab bar
- Add test for back/forward navigation on parallel routes

Core changes:
- Updated handling of parallel route matcher `@` to produce the correct
router tree
- Fixed global-error resolving, it was resolving from the `page.js` on
each level. It should only live next to the root layout only, so now it
resolves when it finds the root layout.
- `applyRouterStatePatchToTree` now merges the levels of the original
tree and the patch. This ensures parallel routes that are not affected
by the response from the server are not removed from the tree.
- Ensure cache nodes are not removed when they're not affected by tree
patch, this ensures parallel route cache nodes will not be removed when
navigating.

Other changes:
- Added launch app-dir build to launch.json for vscode debugger


<!--
Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:
-->

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ]
[e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm build && pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-02-13 16:12:44 +01:00

243 lines
8 KiB
TypeScript

import { createNextDescribe } from 'e2e-utils'
// TODO-APP: remove when parallel routes and interception are implemented
const skipped = true
if (skipped) {
it.skip('skips parallel routes and interception as it is not implemented yet', () => {})
} else {
createNextDescribe(
'parallel-routes-and-interception',
{
files: __dirname,
},
({ next, isNextDeploy }) => {
describe('parallel routes', () => {
if (!isNextDeploy) {
it('should match parallel routes', async () => {
const html = await next.render('/parallel/nested')
expect(html).toContain('parallel/layout')
expect(html).toContain('parallel/@foo/nested/layout')
expect(html).toContain('parallel/@foo/nested/@a/page')
expect(html).toContain('parallel/@foo/nested/@b/page')
expect(html).toContain('parallel/@bar/nested/layout')
expect(html).toContain('parallel/@bar/nested/@a/page')
expect(html).toContain('parallel/@bar/nested/@b/page')
expect(html).toContain('parallel/nested/page')
})
}
it('should match parallel routes in route groups', async () => {
const html = await next.render('/parallel/nested-2')
expect(html).toContain('parallel/layout')
expect(html).toContain('parallel/(new)/layout')
expect(html).toContain('parallel/(new)/@baz/nested/page')
})
it('should support parallel route tab bars', async () => {
const browser = await next.browser('/parallel-tab-bar')
const hasHome = async () => {
const text = await browser.waitForElementByCss('#home').text()
expect(text).toBe('Tab bar page (@children)')
}
const hasViewsHome = async () => {
const text = await browser.waitForElementByCss('#views-home').text()
expect(text).toBe('Views home')
}
const hasViewDuration = async () => {
const text = await browser
.waitForElementByCss('#view-duration')
.text()
expect(text).toBe('View duration')
}
const hasImpressions = async () => {
const text = await browser
.waitForElementByCss('#impressions')
.text()
expect(text).toBe('Impressions')
}
const hasAudienceHome = async () => {
const text = await browser
.waitForElementByCss('#audience-home')
.text()
expect(text).toBe('Audience home')
}
const hasDemographics = async () => {
const text = await browser
.waitForElementByCss('#demographics')
.text()
expect(text).toBe('Demographics')
}
const hasSubscribers = async () => {
const text = await browser
.waitForElementByCss('#subscribers')
.text()
expect(text).toBe('Subscribers')
}
const checkUrlPath = async (path: string) => {
expect(await browser.url()).toBe(
`${next.url}/parallel-tab-bar${path}`
)
}
// Initial page
const step1 = async () => {
await hasHome()
await hasViewsHome()
await hasAudienceHome()
await checkUrlPath('')
}
await step1()
// Navigate to /views/duration
await browser.elementByCss('#view-duration-link').click()
const step2 = async () => {
await hasHome()
await hasViewDuration()
await hasAudienceHome()
await checkUrlPath('/view-duration')
}
await step2()
// Navigate to /views/impressions
await browser.elementByCss('#impressions-link').click()
const step3 = async () => {
await hasHome()
await hasImpressions()
await hasAudienceHome()
await checkUrlPath('/impressions')
}
await step3()
// Navigate to /audience/demographics
await browser.elementByCss('#demographics-link').click()
const step4 = async () => {
await hasHome()
await hasImpressions()
await hasDemographics()
await checkUrlPath('/demographics')
}
await step4()
// Navigate to /audience/subscribers
await browser.elementByCss('#subscribers-link').click()
const step5 = async () => {
await hasHome()
await hasImpressions()
await hasSubscribers()
await checkUrlPath('/subscribers')
}
await step5()
// Navigate to /
await browser.elementByCss('#home-link-audience').click()
// TODO: home link behavior
await step1()
// Test that back navigation works as intended
await browser.back()
await step5()
await browser.back()
await step4()
await browser.back()
await step3()
await browser.back()
await step2()
await browser.back()
await step1()
// Test that forward navigation works as intended
await browser.forward()
await step2()
await browser.forward()
await step3()
await browser.forward()
await step4()
await browser.forward()
await step5()
})
})
describe('route intercepting', () => {
it('should render intercepted route', async () => {
const browser = await next.browser('/intercepting-routes/feed')
// Check if navigation to modal route works.
expect(
await browser
.elementByCss('[href="/intercepting-routes/photos/1"]')
.click()
.waitForElementByCss('#photo-intercepted-1')
.text()
).toBe('Photo INTERCEPTED 1')
// Check if intercepted route was rendered while existing page content was removed.
// Content would only be preserved when combined with parallel routes.
expect(await browser.elementByCss('#feed-page').text()).not.toBe(
'Feed'
)
// Check if url matches even though it was intercepted.
expect(await browser.url()).toBe(
next.url + '/intercepting-routes/photos/1'
)
// Trigger a refresh, this should load the normal page, not the modal.
expect(
await browser.refresh().waitForElementByCss('#photo-page-1').text()
).toBe('Photo PAGE 1')
// Check if the url matches still.
expect(await browser.url()).toBe(
next.url + '/intercepting-routes/photos/1'
)
})
it('should render modal when paired with parallel routes', async () => {
const browser = await next.browser(
'/intercepting-parallel-modal/vercel'
)
// Check if navigation to modal route works.
expect(
await browser
.elementByCss('[href="/intercepting-parallel-modal/photos/1"]')
.click()
.waitForElementByCss('#photo-modal-1')
.text()
).toBe('Photo MODAL 1')
// Check if modal was rendered while existing page content is preserved.
expect(await browser.elementByCss('#user-page').text()).toBe(
'Feed for vercel'
)
// Check if url matches even though it was intercepted.
expect(await browser.url()).toBe(
next.url + '/intercepting-parallel-modal/photos/1'
)
// Trigger a refresh, this should load the normal page, not the modal.
expect(
await browser.refresh().waitForElementByCss('#photo-page-1').text()
).toBe('Photo PAGE 1')
// Check if the url matches still.
expect(await browser.url()).toBe(
next.url + '/intercepting-parallel-modal/photos/1'
)
})
})
}
)
}