Skip to content

Commit 7049b93

Browse files
authored
chore(CI): Split trailing-slashes suite cases into smaller suites, port to more modern e2e framework (vercel#78890)
Same basic idea as vercel#78787 This test suite has a lot of timeouts with rspack, which causes it to take a long time to run (though not quite long enough that it breaks the job). In general, large test suites are good to break up, because they benefit from parallelism. --- In addition to breaking this test suite up, I also ported it to the new framework, as the way it was patching `next.config.js` was causing problems, since the old integration tests are not run in isolated directories.
1 parent 75658b8 commit 7049b93

File tree

14 files changed

+323
-369
lines changed

14 files changed

+323
-369
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* eslint-env jest */
2+
3+
import {
4+
testShouldRedirect,
5+
testLinkShouldRewriteTo,
6+
} from './shared-tests.util'
7+
import { nextTestSetup, isNextDev } from 'e2e-utils'
8+
9+
// we don't need to exhaustively test this, just do some basic sanity checks
10+
// for use in combiantion with basePath
11+
;(isNextDev ? describe : describe.skip)(
12+
'Trailing slashes in development mode, with basepath, trailingSlash: true',
13+
() => {
14+
const { next } = nextTestSetup({
15+
files: __dirname,
16+
nextConfig: {
17+
trailingSlash: true,
18+
basePath: '/docs',
19+
},
20+
})
21+
22+
testShouldRedirect(next, [
23+
['/docs/about', '/docs/about/'],
24+
['/docs', '/docs/'],
25+
['/docs/catch-all/hello/world', '/docs/catch-all/hello/world/'],
26+
['/docs/catch-all/hello.world/', '/docs/catch-all/hello.world'],
27+
])
28+
29+
testLinkShouldRewriteTo(next, [
30+
['/docs/linker?href=/about', '/docs/about/'],
31+
['/docs/linker?href=/', '/docs/'],
32+
])
33+
}
34+
)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* eslint-env jest */
2+
3+
// These tests are defined here and used in `app-dir.test.ts` and
4+
// `pages-dir.test.ts` so that both test suites can be run in parallel.
5+
6+
import type { Playwright } from 'next-webdriver'
7+
8+
import cheerio from 'cheerio'
9+
import type { NextInstance } from 'e2e-utils'
10+
11+
export function testShouldRedirect(
12+
next: NextInstance,
13+
expectations: [string, string][]
14+
) {
15+
it.each(expectations)(
16+
'%s should redirect to %s',
17+
async (route, expectedLocation) => {
18+
const res = await next.fetch(route, { redirect: 'manual' })
19+
expect(res.status).toBe(308)
20+
const { pathname } = new URL(res.headers.get('location'))
21+
expect(pathname).toBe(expectedLocation)
22+
}
23+
)
24+
}
25+
26+
export function testShouldResolve(
27+
next: NextInstance,
28+
expectations: [string, string, string][]
29+
) {
30+
it.each(expectations)(
31+
'%s should resolve to %s, with router path %s',
32+
async (route, expectedPage, expectedRouterPath) => {
33+
const res = await next.fetch(route, { redirect: 'error' })
34+
expect(res.status).toBe(200)
35+
const $ = cheerio.load(await res.text())
36+
expect($('#page-marker').text()).toBe(expectedPage)
37+
expect($('#router-pathname').text()).toBe(expectedRouterPath)
38+
}
39+
)
40+
41+
it.each(expectations)(
42+
'%s should client side render %s, with router path %s',
43+
async (route, expectedPage, expectedRouterPath) => {
44+
let browser: Playwright | undefined
45+
try {
46+
browser = await next.browser(route)
47+
48+
await browser.waitForElementByCss('#hydration-marker')
49+
const text = await browser.elementByCss('#page-marker').text()
50+
expect(text).toBe(expectedPage)
51+
const routerPathname = await browser
52+
.elementByCss('#router-pathname')
53+
.text()
54+
expect(routerPathname).toBe(expectedRouterPath)
55+
} finally {
56+
if (browser) await browser.close()
57+
}
58+
}
59+
)
60+
}
61+
62+
export function testExternalLinkShouldRewriteTo(
63+
next: NextInstance,
64+
expectations: [string, string][]
65+
) {
66+
it.each(expectations)(
67+
'%s should have href %s',
68+
async (linkPage, expectedHref) => {
69+
const $ = await next.render$(linkPage)
70+
expect($('#link').attr('href')).toBe(expectedHref)
71+
}
72+
)
73+
}
74+
75+
export function testLinkShouldRewriteTo(
76+
next: NextInstance,
77+
expectations: [string, string][]
78+
) {
79+
it.each(expectations)(
80+
'%s should have href %s',
81+
async (linkPage, expectedHref) => {
82+
const $ = await next.render$(linkPage)
83+
expect($('#link').attr('href')).toBe(expectedHref)
84+
}
85+
)
86+
87+
it.each(expectations)(
88+
'%s should navigate to %s',
89+
async (linkPage, expectedHref) => {
90+
let browser: Playwright | undefined
91+
try {
92+
browser = await next.browser(linkPage)
93+
await browser.elementByCss('#link').click()
94+
95+
await browser.waitForElementByCss('#hydration-marker')
96+
const url = new URL(await browser.eval('window.location.href'))
97+
const pathname = url.href.slice(url.origin.length)
98+
expect(pathname).toBe(expectedHref)
99+
} finally {
100+
if (browser) await browser.close()
101+
}
102+
}
103+
)
104+
105+
it.each(expectations)(
106+
'%s should push route to %s',
107+
async (linkPage, expectedHref) => {
108+
let browser: Playwright | undefined
109+
try {
110+
browser = await next.browser(linkPage)
111+
await browser.elementByCss('#route-pusher').click()
112+
113+
await browser.waitForElementByCss('#hydration-marker')
114+
const url = new URL(await browser.eval('window.location.href'))
115+
const pathname = url.href.slice(url.origin.length)
116+
expect(pathname).toBe(expectedHref)
117+
} finally {
118+
if (browser) await browser.close()
119+
}
120+
}
121+
)
122+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-env jest */
2+
/* eslint-disable jest/no-standalone-expect */
3+
4+
import {
5+
testShouldRedirect,
6+
testLinkShouldRewriteTo,
7+
testShouldResolve,
8+
testExternalLinkShouldRewriteTo,
9+
} from './shared-tests.util'
10+
import { nextTestSetup } from 'e2e-utils'
11+
import { join } from 'path'
12+
13+
describe('Trailing slashes with trailingSlash: true', () => {
14+
const { next, isNextStart } = nextTestSetup({
15+
files: __dirname,
16+
nextConfig: {
17+
trailingSlash: true,
18+
},
19+
})
20+
21+
testShouldRedirect(next, [
22+
['/about', '/about/'],
23+
['/catch-all/hello/world', '/catch-all/hello/world/'],
24+
['/catch-all/hello.world/', '/catch-all/hello.world'],
25+
])
26+
27+
testShouldResolve(next, [
28+
// visited url, expected page, expected router path
29+
['/', '/index.js', '/'],
30+
['/about/', '/about.js', '/about'],
31+
[
32+
'/catch-all/hello/world/',
33+
'/catch-all/[...slug].js',
34+
'/catch-all/[...slug]',
35+
],
36+
['/about/?hello=world', '/about.js', '/about'],
37+
])
38+
39+
testLinkShouldRewriteTo(next, [
40+
['/linker?href=/', '/'],
41+
['/linker?href=/about', '/about/'],
42+
['/linker?href=/about/', '/about/'],
43+
['/linker?href=/about?hello=world', '/about/?hello=world'],
44+
['/linker?href=/about/?hello=world', '/about/?hello=world'],
45+
['/linker?href=/catch-all/hello/', '/catch-all/hello/'],
46+
['/linker?href=/catch-all/hello.world/', '/catch-all/hello.world'],
47+
])
48+
49+
testExternalLinkShouldRewriteTo(next, [
50+
[
51+
`/external-linker?href=${encodeURI('https://nextjs.org')}`,
52+
'https://nextjs.org',
53+
],
54+
[
55+
`/external-linker?href=${encodeURI('https://nextjs.org/')}`,
56+
'https://nextjs.org/',
57+
],
58+
])
59+
60+
// only prod builds have a manifest
61+
;(isNextStart ? it : it.skip)(
62+
'should have a trailing redirect in the routesmanifest',
63+
async () => {
64+
const manifest = await next.readJSON(
65+
join('.next', 'routes-manifest.json')
66+
)
67+
expect(manifest).toEqual(
68+
expect.objectContaining({
69+
redirects: expect.arrayContaining([
70+
expect.objectContaining({
71+
source:
72+
'/:file((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+)/',
73+
destination: '/:file',
74+
statusCode: 308,
75+
}),
76+
expect.objectContaining({
77+
source: '/:notfile((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+)',
78+
destination: '/:notfile/',
79+
statusCode: 308,
80+
}),
81+
]),
82+
})
83+
)
84+
}
85+
)
86+
})

0 commit comments

Comments
 (0)