Skip to content

Commit 3dbee02

Browse files
authored
ci: run e2e on Next.js stable (#157)
* ci: run e2e on Next.js stable * Public repo * Fix patching * Typos in workflow * Use new output syntax * Skip skipped test suites
1 parent 1fa968a commit 3dbee02

File tree

6 files changed

+208
-19
lines changed

6 files changed

+208
-19
lines changed

.github/workflows/test-e2e.yml

+21-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
env:
1010
NODE_VERSION: 18.17.1
1111
PNPM_VERSION: 8.9.0
12-
NEXT_REPO: netlify/next.js
12+
NEXT_REPO: vercel/next.js
1313
NEXT_TEST_MODE: deploy
1414
NEXT_JUNIT_TEST_REPORT: true
1515
TEST_CONCURRENCY: 8
@@ -28,29 +28,29 @@ jobs:
2828
if:
2929
${{ github.event_name == ('workflow_dispatch' || 'workflow_call') ||
3030
contains(github.event.pull_request.labels.*.name, 'run-e2e-tests') }}
31-
name: Test group ${{ matrix.group }}/20
31+
name: Test group ${{ matrix.group }}/24
3232
runs-on: ubuntu-latest
3333
timeout-minutes: 120
3434
strategy:
3535
fail-fast: false
3636
matrix:
37-
group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
37+
group:
38+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
3839

3940
steps:
40-
- name: get github token
41-
uses: navikt/github-app-token-generator@v1
42-
id: token
43-
with:
44-
private-key: ${{ secrets.TOKENS_PRIVATE_KEY }}
45-
app-id: ${{ secrets.TOKENS_APP_ID }}
46-
repo: ${{ env.NEXT_REPO }}
41+
- name: Get Latest Next.js Release
42+
id: next-release
43+
run: |
44+
LATEST_RELEASE=$(curl -s https://api.github.com/repos/vercel/next.js/releases/latest | jq -r .tag_name)
45+
echo "Latest release tag is $LATEST_RELEASE"
46+
echo "tag=$LATEST_RELEASE" >> $GITHUB_OUTPUT
4747
48-
- name: checkout next.js repo
48+
- name: checkout Next.js repo
4949
uses: actions/checkout@v4
5050
with:
5151
repository: ${{ env.NEXT_REPO }}
52-
token: ${{ steps.token.outputs.token }}
5352
path: ${{ env.next-path }}
53+
ref: ${{ steps.next-release.outputs.tag }}
5454

5555
- name: checkout runtime repo
5656
uses: actions/checkout@v4
@@ -89,11 +89,17 @@ jobs:
8989
restore-keys: |
9090
node-cache-
9191
92-
- name: install next.js
92+
- name: patch Next.js
93+
run: |
94+
cp ../${{ env.runtime-path }}/tests/netlify-deploy.ts test/lib/next-modes/
95+
git apply ../${{ env.runtime-path }}/tests/e2e-utils.patch
96+
working-directory: ${{ env.next-path }}
97+
98+
- name: install Next.js
9399
run: pnpm install
94100
working-directory: ${{ env.next-path }}
95101

96-
- name: build next.js
102+
- name: build Next.js
97103
run: pnpm build
98104
working-directory: ${{ env.next-path }}
99105

@@ -126,7 +132,7 @@ jobs:
126132
env:
127133
NODE_ENV: production
128134
NEXT_EXTERNAL_TESTS_FILTERS: ../next-runtime-minimal/tests/netlify-e2e.json
129-
run: node run-tests.js -g ${{ matrix.group }}/20 -c ${TEST_CONCURRENCY} --type e2e
135+
run: node run-tests.js -g ${{ matrix.group }}/24 -c ${TEST_CONCURRENCY} --type e2e
130136
working-directory: ${{ env.next-path }}
131137

132138
- name: Upload Test Results

run-local-test.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/bin/sh
2-
set -e
32
# Print usage if nothing is passed
43
if [ -z "$1" ]; then
54
echo "Usage: $0 <test-pattern>"
@@ -13,5 +12,9 @@ fi
1312
export NEXT_TEST_CONTINUE_ON_ERROR=1
1413
export NETLIFY_SITE_ID=1d5a5c76-d445-4ae5-b694-b0d3f2e2c395
1514
export NEXT_TEST_MODE=deploy
15+
cp tests/netlify-deploy.ts ../next.js/test/lib/next-modes/netlify-deploy.ts
1616
cd ../next.js/
17+
git apply ../next-runtime-minimal/tests/e2e-utils.patch
1718
node run-tests.js --type e2e --debug --test-pattern $1
19+
git checkout -- test/lib/e2e-utils.ts
20+

tests/e2e-utils.patch

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
diff --git a/test/lib/e2e-utils.ts b/test/lib/e2e-utils.ts
2+
index ee43a460d6..9f9aa30d33 100644
3+
--- a/test/lib/e2e-utils.ts
4+
+++ b/test/lib/e2e-utils.ts
5+
@@ -7,3 +7,3 @@ import { NextDevInstance } from './next-modes/next-dev'
6+
import { NextStartInstance } from './next-modes/next-start'
7+
-import { NextDeployInstance } from './next-modes/next-deploy'
8+
+import { NextDeployInstance } from './next-modes/netlify-deploy'
9+
import { shouldRunTurboDevTest } from './next-test-utils'
10+

tests/netlify-deploy.ts

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// This is copied to the Next.js repo
2+
import execa from 'execa'
3+
import fs from 'fs-extra'
4+
import { Span } from 'next/src/trace'
5+
import path from 'path'
6+
import { NextInstance } from './base'
7+
8+
type NetlifyDeployResponse = {
9+
name: string
10+
site_id: string
11+
site_name: string
12+
deploy_id: string
13+
deploy_url: string
14+
logs: string
15+
}
16+
17+
export class NextDeployInstance extends NextInstance {
18+
private _cliOutput: string
19+
private _buildId: string
20+
private _deployId: string
21+
22+
public get buildId() {
23+
// get deployment ID via fetch since we can't access
24+
// build artifacts directly
25+
return this._buildId
26+
}
27+
28+
public async setup(parentSpan: Span) {
29+
// create the test site
30+
await super.createTestDir({ parentSpan, skipInstall: true })
31+
32+
// install dependencies
33+
await execa('npm', ['i'], {
34+
cwd: this.testDir,
35+
stdio: 'inherit',
36+
})
37+
38+
// use next runtime package installed by the test runner
39+
if (!fs.existsSync(path.join(this.testDir, 'netlify.toml'))) {
40+
const toml = /* toml */ `
41+
[build]
42+
command = "npm run build"
43+
publish = ".next"
44+
45+
[[plugins]]
46+
package = "${path.relative(this.testDir, `${process.cwd()}/../next-runtime-minimal`)}"
47+
`
48+
49+
await fs.writeFile(path.join(this.testDir, 'netlify.toml'), toml)
50+
}
51+
52+
// ensure netlify cli is installed
53+
try {
54+
const res = await execa('netlify', ['--version'])
55+
require('console').log(`Using Netlify CLI version:`, res.stdout)
56+
} catch (_) {
57+
require('console').log(`You need to have netlify-cli installed.
58+
59+
You can do this by running: "npm install -g netlify-cli@latest" or "yarn global add netlify-cli@latest"`)
60+
}
61+
62+
// ensure project is linked
63+
try {
64+
await execa('ntl', ['status', '--json'])
65+
} catch (err) {
66+
if (err.message.includes("You don't appear to be in a folder that is linked to a site")) {
67+
throw new Error(`Site is not linked. Please set "NETLIFY_AUTH_TOKEN" and "NETLIFY_SITE_ID"`)
68+
}
69+
throw err
70+
}
71+
72+
require('console').log(`Deploying project at ${this.testDir}`)
73+
74+
const testName =
75+
process.env.TEST_FILE_PATH && path.relative(process.cwd(), process.env.TEST_FILE_PATH)
76+
77+
const deployTitle = process.env.GITHUB_SHA
78+
? `${testName} - ${process.env.GITHUB_SHA}`
79+
: testName
80+
81+
if (fs.existsSync(path.join(this.testDir, 'cache-handler.js'))) {
82+
process.env.CUSTOM_CACHE_HANDLER = path.join(this.testDir, 'cache-handler.js')
83+
}
84+
85+
const deployRes = await execa(
86+
'ntl',
87+
['deploy', '--build', '--json', '--message', deployTitle ?? ''],
88+
{
89+
cwd: this.testDir,
90+
reject: false,
91+
},
92+
)
93+
94+
if (deployRes.exitCode !== 0) {
95+
throw new Error(
96+
`Failed to deploy project ${deployRes.stdout} ${deployRes.stderr} (${deployRes.exitCode})`,
97+
)
98+
}
99+
100+
try {
101+
const data: NetlifyDeployResponse = JSON.parse(deployRes.stdout)
102+
this._url = data.deploy_url
103+
this._parsedUrl = new URL(this._url)
104+
this._deployId = data.deploy_id
105+
require('console').log(`Deployment URL: ${this._url}`)
106+
} catch (err) {
107+
console.error(err)
108+
throw new Error(`Failed to parse deploy output: ${deployRes.stdout}`)
109+
}
110+
111+
this._buildId = (
112+
await fs.readFile(
113+
path.join(this.testDir, this.nextConfig?.distDir || '.next', 'BUILD_ID'),
114+
'utf8',
115+
)
116+
).trim()
117+
118+
require('console').log(`Got buildId: ${this._buildId}`)
119+
}
120+
121+
public get cliOutput() {
122+
return this._cliOutput || ''
123+
}
124+
125+
public async start() {
126+
// no-op as the deployment is created during setup()
127+
}
128+
129+
public async patchFile(filename: string, content: string): Promise<void> {
130+
throw new Error('patchFile is not available in deploy test mode')
131+
}
132+
public async readFile(filename: string): Promise<string> {
133+
throw new Error('readFile is not available in deploy test mode')
134+
}
135+
public async deleteFile(filename: string): Promise<void> {
136+
throw new Error('deleteFile is not available in deploy test mode')
137+
}
138+
public async renameFile(filename: string, newFilename: string): Promise<void> {
139+
throw new Error('renameFile is not available in deploy test mode')
140+
}
141+
}

tests/netlify-e2e.json

+31-2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
},
7474
"test/e2e/skip-trailing-slash-redirect/index.test.ts": {
7575
"flakey": [
76+
"skip-trailing-slash-redirect should merge cookies from middleware and API routes correctly",
7677
"skip-trailing-slash-redirect should merge cookies from middleware and edge API routes correctly",
7778
"skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-ssr",
7879
"skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-static",
@@ -101,7 +102,8 @@
101102
"app dir - metadata dynamic routes social image routes should render og image with twitter-image dynamic routes",
102103
"app dir - metadata dynamic routes icon image routes should render icon with dynamic routes",
103104
"app dir - metadata dynamic routes icon image routes should render apple icon with dynamic routes",
104-
"app dir - metadata dynamic routes should inject dynamic metadata properly to head"
105+
"app dir - metadata dynamic routes should inject dynamic metadata properly to head",
106+
"app dir - metadata dynamic routes should use localhost for local prod and fallback to deployment url when metadataBase is falsy"
105107
]
106108
},
107109
"test/e2e/app-dir/metadata/metadata.test.ts": {
@@ -116,6 +118,12 @@
116118
"basePath should not update URL for a 404",
117119
"basePath should handle 404 urls that start with basePath"
118120
]
121+
},
122+
"test/e2e/app-dir/app/index.test.ts": {
123+
"flakey": [
124+
"app dir - basic should return the `vary` header from edge runtime",
125+
"app dir - basic should return the `vary` header from pages for flight requests"
126+
]
119127
}
120128
},
121129
"rules": {
@@ -139,7 +147,28 @@
139147
"test/e2e/repeated-forward-slashes-error/repeated-forward-slashes-error.test.ts",
140148
"test/e2e/app-dir/with-exported-function-config/with-exported-function-config.test.ts",
141149
"test/e2e/app-dir/x-forwarded-headers/x-forwarded-headers.test.ts",
142-
"test/e2e/app-dir/third-parties/basic.test.ts"
150+
"test/e2e/app-dir/third-parties/basic.test.ts",
151+
"test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts",
152+
"test/e2e/404-page-router/index.test.ts",
153+
"test/e2e/app-dir/app-client-cache/client-cache.test.ts",
154+
"test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts",
155+
"test/e2e/app-dir/app/experimental-compile.test.ts",
156+
"test/e2e/app-dir/app/standalone-gsp.test.ts",
157+
"test/e2e/app-dir/app/standalone.test.ts",
158+
"test/e2e/app-dir/app/vercel-speed-insights.test.ts",
159+
"test/e2e/app-dir/build-size/index.test.ts",
160+
"test/e2e/app-dir/create-root-layout/create-root-layout.test.ts",
161+
"test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts",
162+
"test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts",
163+
"test/e2e/edge-compiler-can-import-blob-assets/index.test.ts",
164+
"test/e2e/i18n-data-fetching-redirect/index.test.ts",
165+
"test/e2e/manual-client-base-path/index.test.ts",
166+
"test/e2e/no-eslint-warn-with-no-eslint-config/index.test.ts",
167+
"test/e2e/switchable-runtime/index.test.ts",
168+
"test/e2e/trailingslash-with-rewrite/index.test.ts",
169+
"test/e2e/transpile-packages/index.test.ts",
170+
"test/e2e/typescript-version-no-warning/typescript-version-no-warning.test.ts",
171+
"test/e2e/typescript-version-warning/typescript-version-warning.test.ts"
143172
]
144173
}
145174
}

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
"forceConsistentCasingInFileNames": true
1111
},
1212
"include": ["src/**/*"],
13-
"exclude": ["tests/**/*", "src/**/*.test.ts", "edge-runtime/**"]
13+
"exclude": ["tests/**/*", "src/**/*.test.ts", "edge-runtime/**", "tests/netlify-deploy.ts"]
1414
}

0 commit comments

Comments
 (0)