Skip to content

Commit b8be05c

Browse files
authored
fix e2e deployment test action (#66721)
[Test Run](https://github.com/vercel/next.js/actions/runs/9471783416/job/26095882422) Changes: - Add a setup step that clears the project so it doesn't happen in each runner - Run when a release is published rather than on cron - Notify via Slack when a failure occurs - Leverage build_reusable for the test runner to match the build_and_test workflow - Fixes to `next-deploy` script: not properly logging/catching errors - Adds manifest to ignore known issues - Split into 6 runners with 2 concurrency (12 deploys at a time) - Adds some logging so we know what's happening - Disable Playwright trace mode (it kept failing to find a trace file and cluttering the output. Don't think we need it here anyway) <details> - <summary>Removed noisy output</summary> ![CleanShot 2024-06-10 at 14 08 05@2x](https://github.com/vercel/next.js/assets/1939140/f227e71c-95b4-4859-90de-a23c88c55ea8) </details> <!-- 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: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Adding or Updating Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->
1 parent 65fd44b commit b8be05c

File tree

7 files changed

+213
-124
lines changed

7 files changed

+213
-124
lines changed

.github/workflows/build_reusable.yml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ on:
4949
required: true
5050
description: 'name of the step, to be used for the upload artifact unique key '
5151
type: string
52+
timeout_minutes:
53+
description: 'Timeout in minutes'
54+
required: false
55+
type: number
56+
default: 30
57+
runs_on_labels:
58+
description: 'List of runner labels'
59+
required: false
60+
type: string
61+
default: '["self-hosted", "linux", "x64", "metal"]'
5262

5363
env:
5464
NAPI_CLI_VERSION: 2.14.7
@@ -69,15 +79,13 @@ env:
6979
DD_ENV: 'ci'
7080
TEST_TIMINGS_TOKEN: ${{ secrets.TEST_TIMINGS_TOKEN }}
7181
NEXT_TEST_JOB: 1
82+
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
83+
VERCEL_TEST_TEAM: vtest314-next-e2e-tests
7284

7385
jobs:
7486
build:
75-
timeout-minutes: 30
76-
runs-on:
77-
- 'self-hosted'
78-
- 'linux'
79-
- 'x64'
80-
- 'metal'
87+
timeout-minutes: ${{ inputs.timeout_minutes }}
88+
runs-on: ${{ fromJson(inputs.runs_on_labels) }}
8189

8290
outputs:
8391
input_step_key: ${{ steps.var.outputs.input_step_key }}
@@ -90,7 +98,12 @@ jobs:
9098
script: |
9199
core.setOutput('input_step_key', '${{ inputs.stepName }}'.toLowerCase().replaceAll(/[/.]/g, '-').trim('-'));
92100
93-
- run: fnm use --install-if-missing ${{ inputs.nodeVersion || env.NODE_LTS_VERSION }}
101+
- name: Setup Node.js
102+
uses: actions/setup-node@v4
103+
with:
104+
node-version: ${{ inputs.nodeVersion || env.NODE_LTS_VERSION }}
105+
check-latest: true
106+
94107
- run: node -v
95108
- run: corepack enable
96109
- run: pwd
@@ -175,7 +188,7 @@ jobs:
175188
- run: turbo run get-test-timings -- --build ${{ github.sha }}
176189

177190
- run: /bin/bash -c "${{ inputs.afterBuild }}"
178-
timeout-minutes: 30
191+
timeout-minutes: ${{ inputs.timeout_minutes }}
179192

180193
- name: Upload artifact
181194
uses: actions/upload-artifact@v4
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Test E2E (Vercel Deploy), scheduled
2+
3+
on:
4+
# run on every release/prerelease
5+
release:
6+
types: [published]
7+
# allow triggering manually as well
8+
workflow_dispatch:
9+
10+
env:
11+
VERCEL_TEST_TEAM: vtest314-next-e2e-tests
12+
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
13+
SLACK_WEBHOOK_URL: ${{ secrets.BROKEN_DEPLOY_SLACK_WEBHOOK_URL }}
14+
DATADOG_API_KEY: ${{ secrets.DATA_DOG_API_KEY }}
15+
DD_ENV: 'ci'
16+
17+
jobs:
18+
setup:
19+
runs-on: ubuntu-latest
20+
if: github.repository_owner == 'vercel'
21+
steps:
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: ${{ env.NODE_LTS_VERSION }}
26+
check-latest: true
27+
28+
- name: Setup pnpm
29+
run: corepack enable
30+
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 25
35+
36+
- name: Setup test project
37+
run: |
38+
pnpm install
39+
pnpm run build
40+
node scripts/run-e2e-test-project-reset.mjs
41+
42+
test-deploy:
43+
name: test deploy
44+
needs: setup
45+
uses: ./.github/workflows/build_reusable.yml
46+
secrets: inherit
47+
strategy:
48+
fail-fast: true
49+
matrix:
50+
group: [1/5, 2/5, 3/5, 4/5, 5/5, 6/6]
51+
with:
52+
afterBuild: NEXT_TEST_MODE=deploy NEXT_EXTERNAL_TESTS_FILTERS="test/deploy-tests-manifest.json" node run-tests.js --timings -g ${{ matrix.group }} -c 2 --type e2e
53+
skipNativeBuild: 'yes'
54+
stepName: 'test-deploy-${{ matrix.group }}'
55+
timeout_minutes: 180
56+
runs_on_labels: '["ubuntu-latest"]'
57+
58+
report-test-results-to-datadog:
59+
needs: test-deploy
60+
if: ${{ always() }}
61+
62+
runs-on: ubuntu-latest
63+
name: report test results to datadog
64+
steps:
65+
- name: Download test report artifacts
66+
id: download-test-reports
67+
uses: actions/download-artifact@v4
68+
with:
69+
pattern: test-reports-*
70+
path: test
71+
merge-multiple: true
72+
73+
- name: Upload test report to datadog
74+
run: |
75+
if [ -d ./test/test-junit-report ]; then
76+
DD_ENV=ci npx @datadog/[email protected] junit upload --tags test.type:deploy --service nextjs ./test/test-junit-report
77+
fi
78+
79+
report-failure:
80+
name: report failure to slack
81+
needs: test-deploy
82+
if: needs.test-deploy.conclusion == 'failure'
83+
runs-on: ubuntu-latest
84+
steps:
85+
- name: send webhook
86+
uses: slackapi/[email protected]
87+
with:
88+
payload: |
89+
{
90+
"commit_title": ${{ toJSON(github.event.workflow_run.display_title) }},
91+
"commit_url": "github.com/${{ github.repository }}/commit/${{ github.event.workflow_run.head_sha }}",
92+
"workflow_run_url": "github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}/attempts/${{ github.event.workflow_run.run_attempt }}"
93+
}
94+
env:
95+
SLACK_WEBHOOK_URL: ${{ env.SLACK_WEBHOOK_URL }}

.github/workflows/test_e2e_deploy_scheduled.yml

Lines changed: 0 additions & 87 deletions
This file was deleted.

run-tests.js

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,12 @@ async function main() {
227227
}
228228
}
229229

230-
console.log('Running tests with concurrency:', options.concurrency)
230+
console.log(
231+
'Running tests with concurrency:',
232+
options.concurrency,
233+
'in test mode',
234+
process.env.NEXT_TEST_MODE
235+
)
231236

232237
/** @type TestFile[] */
233238
let tests = argv._.filter((arg) =>
@@ -470,7 +475,8 @@ ${ENDGROUP}`)
470475
RECORD_REPLAY: shouldRecordTestWithReplay,
471476
// run tests in headless mode by default
472477
HEADLESS: 'true',
473-
TRACE_PLAYWRIGHT: 'true',
478+
TRACE_PLAYWRIGHT:
479+
process.env.NEXT_TEST_MODE === 'deploy' ? undefined : 'true',
474480
NEXT_TELEMETRY_DISABLED: '1',
475481
// unset CI env so CI behavior is only explicitly
476482
// tested when enabled
@@ -691,32 +697,6 @@ ${ENDGROUP}`)
691697
}
692698
}
693699

694-
// Emit test output if test failed or if we're continuing tests on error
695-
if ((!passed || shouldContinueTestsOnError) && isTestJob) {
696-
try {
697-
const testsOutput = await fsp.readFile(
698-
`${test.file}${RESULTS_EXT}`,
699-
'utf8'
700-
)
701-
const obj = JSON.parse(testsOutput)
702-
obj.processEnv = {
703-
NEXT_TEST_MODE: process.env.NEXT_TEST_MODE,
704-
HEADLESS: process.env.HEADLESS,
705-
}
706-
await outputSema.acquire()
707-
if (GROUP) console.log(`${GROUP}Result as JSON for tooling`)
708-
console.log(
709-
`--test output start--`,
710-
JSON.stringify(obj),
711-
`--test output end--`
712-
)
713-
if (ENDGROUP) console.log(ENDGROUP)
714-
outputSema.release()
715-
} catch (err) {
716-
console.log(`Failed to load test output`, err)
717-
}
718-
}
719-
720700
sema.release()
721701
if (dirSema) dirSema.release()
722702
})

test/deploy-tests-manifest.json

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"version": 2,
3+
"suites": {},
4+
"rules": {
5+
"include": [
6+
"test/e2e/**/*.test.{t,j}s{,x}",
7+
"test/production/**/*.test.{t,j}s{,x}"
8+
],
9+
"exclude": [
10+
"test/e2e/app-dir/app-client-cache/client-cache.original.test.ts",
11+
"test/e2e/app-dir/app-routes/app-custom-routes.test.ts",
12+
"test/e2e/app-dir/next-after-app/index.test.ts",
13+
"test/e2e/app-dir/scss/nm-module-nested/nm-module-nested.test.ts",
14+
"test/e2e/cancel-request/stream-cancel.test.ts",
15+
"test/e2e/edge-pages-support/edge-document.test.ts",
16+
"test/e2e/new-link-behavior/material-ui.test.ts",
17+
"test/e2e/react-dnd-compile/react-dnd-compile.test.ts",
18+
"test/e2e/next-test/next-test.test.ts",
19+
"test/e2e/skip-trailing-slash-redirect/index.test.ts",
20+
"test/e2e/tsconfig-module-preserve/index.test.ts",
21+
"test/e2e/app-dir/app-compilation/index.test.ts",
22+
"test/e2e/app-dir/parallel-route-not-found-params/parallel-route-not-found-params.test.ts",
23+
"test/e2e/app-dir/ppr-navigations/loading-tsx-no-partial-rendering/loading-tsx-no-partial-rendering.test.ts",
24+
"test/e2e/app-dir/ppr/ppr.test.ts",
25+
"test/e2e/app-dir/rsc-webpack-loader/rsc-webpack-loader.test.ts",
26+
"test/e2e/app-dir/scss/compilation-and-prefixing/compilation-and-prefixing.test.ts",
27+
"test/e2e/app-dir/typeof-window/typeof-window.test.ts",
28+
"test/e2e/app-dir/webpack-loader-conditions/webpack-loader-conditions.test.ts",
29+
"test/e2e/app-dir/x-forwarded-headers/x-forwarded-headers.test.ts",
30+
"test/e2e/edge-compiler-module-exports-preference/index.test.ts",
31+
"test/e2e/swc-warnings/index.test.ts",
32+
"test/e2e/third-parties/index.test.ts",
33+
"test/e2e/useselectedlayoutsegment-s-in-pages-router/useselectedlayoutsegment-s-in-pages-router.test.ts",
34+
"test/e2e/app-dir/app-prefetch-false-loading/app-prefetch-false-loading.test.ts",
35+
"test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts",
36+
"test/e2e/app-dir/app-routes-client-component/app-routes-client-component.test.ts",
37+
"test/e2e/app-dir/app-routes/app-custom-route-base-path.test.ts",
38+
"test/e2e/app-dir/mdx/mdx.test.ts",
39+
"test/e2e/app-dir/modularizeimports/modularizeimports.test.ts",
40+
"test/e2e/app-dir/navigation/navigation.test.ts",
41+
"test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts",
42+
"test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts",
43+
"test/e2e/app-dir/server-components-externals/index.test.ts",
44+
"test/e2e/app-dir/third-parties/basic.test.ts",
45+
"test/e2e/edge-can-read-request-body/index.test.ts",
46+
"test/e2e/esm-externals/esm-externals.test.ts",
47+
"test/e2e/i18n-data-route/i18n-data-route.test.ts",
48+
"test/e2e/next-phase/index.test.ts",
49+
"test/e2e/app-dir/actions-navigation/index.test.ts",
50+
"test/e2e/app-dir/app-static/app-static-custom-handler.test.ts",
51+
"test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts",
52+
"test/e2e/app-dir/interception-route-prefetch-cache/interception-route-prefetch-cache.test.ts",
53+
"test/e2e/app-dir/missing-suspense-with-csr-bailout/missing-suspense-with-csr-bailout.test.ts",
54+
"test/e2e/app-dir/options-request/options-request.test.ts",
55+
"test/e2e/app-dir/next-image/next-image-proxy.test.ts",
56+
"test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts",
57+
"test/e2e/app-dir/parallel-routes-revalidation/parallel-routes-revalidation.test.ts",
58+
"test/e2e/app-dir/revalidate-dynamic/revalidate-dynamic.test.ts",
59+
"test/e2e/app-dir/scss/npm-import-nested/npm-import-nested.test.ts",
60+
"test/e2e/app-dir/syntax-highlighter-crash/syntax-highlighter-crash.test.ts",
61+
"test/e2e/favicon-short-circuit/favicon-short-circuit.test.ts",
62+
"test/e2e/new-link-behavior/stitches.test.ts",
63+
"test/e2e/next-image-forward-ref/index.test.ts",
64+
"test/e2e/react-compiler/react-compiler.test.ts",
65+
"test/e2e/revalidate-reason/revalidate-reason.test.ts",
66+
"test/e2e/app-dir/app-static/app-static.test.ts",
67+
"test/e2e/app-dir/actions/app-action.test.ts",
68+
"test/e2e/app-dir/i18n-hybrid/i18n-hybrid.test.js",
69+
"test/e2e/app-dir/metadata/metadata.test.ts",
70+
"test/e2e/app-dir/rsc-basic/rsc-basic.test.ts",
71+
"test/e2e/app-dir/scss/nm-module/nm-module.test.ts",
72+
"test/e2e/app-dir/static-shell-debugging/static-shell-debugging.test.ts",
73+
"test/e2e/basepath.test.ts",
74+
"test/e2e/postcss-config-cjs/index.test.ts",
75+
"test/e2e/socket-io/index.test.js",
76+
"test/e2e/middleware-matcher/index.test.ts",
77+
"test/e2e/next-script/index.test.ts"
78+
]
79+
}
80+
}

test/get-test-filter.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ function getTestFilter() {
77
: null
88
if (!manifest) return null
99

10+
console.log(
11+
'Filtering tests using manifest:',
12+
process.env.NEXT_EXTERNAL_TESTS_FILTERS
13+
)
14+
1015
// For the legacy manifest without a version, we assume it's a complete list
1116
// of all the tests.
1217
if (!manifest.version || typeof manifest.version !== 'number') {

0 commit comments

Comments
 (0)