From 111967cc13f8524eb7e3726e1815801ccc5e0133 Mon Sep 17 00:00:00 2001 From: Lukas Holzer Date: Mon, 15 Jul 2024 19:59:57 +0200 Subject: [PATCH] fix: use heuristics for build and deploy command as well (#6729) * fix: use heuristics for build and deploy command as well * chore: fix case where no plugins recommended are in the settings * chore: fix comment * chore: add integration tests for build and deploy * chore: prepare test fixture on ci * chore: update min node version for next.js --- .github/workflows/integration-tests.yml | 6 +- package-lock.json | 112 +++++ package.json | 2 + src/commands/build/build.ts | 9 +- src/commands/deploy/deploy.ts | 6 +- src/lib/build.ts | 3 + src/utils/build-info.ts | 29 ++ src/utils/deploy/deploy-site.ts | 4 +- src/utils/deploy/hash-fns.ts | 4 +- src/utils/feature-flags.ts | 3 +- .../next-app-without-config/.gitignore | 36 ++ .../next-app-without-config/app/favicon.ico | Bin 0 -> 25931 bytes .../next-app-without-config/app/globals.css | 107 +++++ .../next-app-without-config/app/layout.js | 17 + .../next-app-without-config/app/page.js | 79 ++++ .../app/page.module.css | 230 ++++++++++ .../next-app-without-config/jsconfig.json | 7 + .../next-app-without-config/next.config.mjs | 4 + .../next-app-without-config/package-lock.json | 399 ++++++++++++++++++ .../next-app-without-config/package.json | 16 + .../next-app-without-config/public/next.svg | 1 + .../next-app-without-config/public/vercel.svg | 1 + .../build/{build.test.js => build.test.ts} | 29 +- .../deploy/{deploy.test.js => deploy.test.ts} | 97 +++-- 24 files changed, 1149 insertions(+), 52 deletions(-) create mode 100644 tests/integration/__fixtures__/next-app-without-config/.gitignore create mode 100644 tests/integration/__fixtures__/next-app-without-config/app/favicon.ico create mode 100644 tests/integration/__fixtures__/next-app-without-config/app/globals.css create mode 100644 tests/integration/__fixtures__/next-app-without-config/app/layout.js create mode 100644 tests/integration/__fixtures__/next-app-without-config/app/page.js create mode 100644 tests/integration/__fixtures__/next-app-without-config/app/page.module.css create mode 100644 tests/integration/__fixtures__/next-app-without-config/jsconfig.json create mode 100644 tests/integration/__fixtures__/next-app-without-config/next.config.mjs create mode 100644 tests/integration/__fixtures__/next-app-without-config/package-lock.json create mode 100644 tests/integration/__fixtures__/next-app-without-config/package.json create mode 100644 tests/integration/__fixtures__/next-app-without-config/public/next.svg create mode 100644 tests/integration/__fixtures__/next-app-without-config/public/vercel.svg rename tests/integration/commands/build/{build.test.js => build.test.ts} (88%) rename tests/integration/commands/deploy/{deploy.test.js => deploy.test.ts} (92%) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 6cb176fcc86..113db5601e7 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -15,14 +15,14 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] # Pinning 20.x version as a temporary workaround due to this https://github.com/nodejs/node/issues/52884 - node-version: ['18.14.0', '20.12.2', '22'] + node-version: ['18.17.0', '20.12.2', '22'] shard: ['1/4', '2/4', '3/4', '4/4'] exclude: - os: macOS-latest - node-version: '18.14.0' + node-version: '18.17.0' - os: windows-latest - node-version: '18.14.0' + node-version: '18.17.0' - os: windows-latest node-version: '22' fail-fast: false diff --git a/package-lock.json b/package-lock.json index c4fd91d8839..83fd153e863 100644 --- a/package-lock.json +++ b/package-lock.json @@ -145,6 +145,7 @@ "@types/ws": "8.5.10", "@vitest/coverage-v8": "1.6.0", "c8": "9.1.0", + "cheerio": "^1.0.0-rc.12", "eslint-plugin-sort-destructure-keys": "2.0.0", "eslint-plugin-workspace": "file:./tools/lint-rules", "fast-glob": "3.3.2", @@ -8847,6 +8848,44 @@ "node": "*" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -18382,6 +18421,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -29444,6 +29508,35 @@ "get-func-name": "^2.0.2" } }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, "chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -36271,6 +36364,25 @@ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==" }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", diff --git a/package.json b/package.json index 3cd07a3503a..206f8c7a337 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "test:init:cli-help": "npm run start -- --help", "test:init:eleventy-deps": "cd tests/integration/__fixtures__/eleventy-site && pnpm install --frozen-lockfile", "test:init:hugo-deps": "npm ci --prefix tests/integration/__fixtures__/hugo-site --no-audit", + "test:init:next-deps": "npm ci --prefix tests/integration/__fixtures__/next-app-without-config --no-audit", "test:dev:vitest": "vitest run tests/unit/ && vitest run tests/integration", "test:ci:vitest:unit": "vitest run --coverage tests/unit/", "test:ci:vitest:integration": "vitest run --coverage tests/integration/", @@ -201,6 +202,7 @@ "@types/ws": "8.5.10", "@vitest/coverage-v8": "1.6.0", "c8": "9.1.0", + "cheerio": "^1.0.0-rc.12", "eslint-plugin-sort-destructure-keys": "2.0.0", "eslint-plugin-workspace": "file:./tools/lint-rules", "fast-glob": "3.3.2", diff --git a/src/commands/build/build.ts b/src/commands/build/build.ts index f833a4aabea..7151a67e226 100644 --- a/src/commands/build/build.ts +++ b/src/commands/build/build.ts @@ -1,7 +1,7 @@ import { OptionValues } from 'commander' import { getBuildOptions, runBuild } from '../../lib/build.js' -import { detectFrameworkSettings } from '../../utils/build-info.js' +import { detectFrameworkSettings, getDefaultConfig } from '../../utils/build-info.js' import { error, exit, getToken } from '../../utils/command-helpers.js' import { getEnvelopeEnv } from '../../utils/env/index.js' import BaseCommand from '../base-command.js' @@ -31,14 +31,9 @@ export const build = async (options: OptionValues, command: BaseCommand) => { const [token] = await getToken() const settings = await detectFrameworkSettings(command, 'build') - // override the build command with the detection result if no command is specified through the config - if (!cachedConfig.config.build.command) { - cachedConfig.config.build.command = settings?.buildCommand - cachedConfig.config.build.commandOrigin = 'heuristics' - } - const buildOptions = await getBuildOptions({ cachedConfig, + defaultConfig: getDefaultConfig(settings), packagePath: command.workspacePackage, currentDir: command.workingDir, token, diff --git a/src/commands/deploy/deploy.ts b/src/commands/deploy/deploy.ts index 24c51fffb11..99130558e98 100644 --- a/src/commands/deploy/deploy.ts +++ b/src/commands/deploy/deploy.ts @@ -18,6 +18,7 @@ import { featureFlags as edgeFunctionsFeatureFlags } from '../../lib/edge-functi import { normalizeFunctionsConfig } from '../../lib/functions/config.js' import { BACKGROUND_FUNCTIONS_WARNING } from '../../lib/log.js' import { startSpinner, stopSpinner } from '../../lib/spinner.js' +import { detectFrameworkSettings, getDefaultConfig } from '../../utils/build-info.js' import { NETLIFYDEV, NETLIFYDEVERR, @@ -558,7 +559,7 @@ const runDeploy = async ({ * @returns */ // @ts-expect-error TS(7031) FIXME: Binding element 'cachedConfig' implicitly has an '... Remove this comment to see the full error message -const handleBuild = async ({ cachedConfig, currentDir, deployHandler, options, packagePath }) => { +const handleBuild = async ({ cachedConfig, currentDir, defaultConfig, deployHandler, options, packagePath }) => { if (!options.build) { return {} } @@ -566,6 +567,7 @@ const handleBuild = async ({ cachedConfig, currentDir, deployHandler, options, p const [token] = await getToken() const resolvedOptions = await getBuildOptions({ cachedConfig, + defaultConfig, packagePath, token, options, @@ -784,6 +786,7 @@ export const deploy = async (options: OptionValues, command: BaseCommand) => { const { workingDir } = command const { api, site, siteInfo } = command.netlify const alias = options.alias || options.branch + const settings = await detectFrameworkSettings(command, 'build') command.setAnalyticsPayload({ open: options.open, prod: options.prod, json: options.json, alias: Boolean(alias) }) @@ -847,6 +850,7 @@ export const deploy = async (options: OptionValues, command: BaseCommand) => { await handleBuild({ packagePath: command.workspacePackage, cachedConfig: command.netlify.cachedConfig, + defaultConfig: getDefaultConfig(settings), currentDir: command.workingDir, options, // @ts-expect-error TS(7031) FIXME: Binding element 'netlifyConfig' implicitly has an ... Remove this comment to see the full error message diff --git a/src/lib/build.ts b/src/lib/build.ts index ade68bac9d7..fd73f3ce746 100644 --- a/src/lib/build.ts +++ b/src/lib/build.ts @@ -35,6 +35,8 @@ export const getBuildOptions = async ({ cachedConfig, // @ts-expect-error TS(7031) FIXME: Binding element 'currentDir' implicitly has an 'an... Remove this comment to see the full error message currentDir, + // @ts-expect-error TS(7031) FIXME: Binding element 'defaultConfig' implicitly has an '... Remove this comment to see the full error message + defaultConfig, // @ts-expect-error TS(7031) FIXME: Binding element 'deployHandler' implicitly has an ... Remove this comment to see the full error message deployHandler, // @ts-expect-error TS(7031) FIXME: Binding element 'context' implicitly has an 'any' ... Remove this comment to see the full error message @@ -71,6 +73,7 @@ export const getBuildOptions = async ({ return { cachedConfig, + defaultConfig, siteId: cachedConfig.siteInfo.id, packagePath, token, diff --git a/src/utils/build-info.ts b/src/utils/build-info.ts index deb9d62d6f4..32aef3900c2 100644 --- a/src/utils/build-info.ts +++ b/src/utils/build-info.ts @@ -4,6 +4,7 @@ import fuzzy from 'fuzzy' import inquirer from 'inquirer' import BaseCommand from '../commands/base-command.js' +import { $TSFixMe } from '../commands/types.js' import { chalk, log } from './command-helpers.js' @@ -122,3 +123,31 @@ command = "${chosenSettings.devCommand}" return chosenSettings } } + +/** + * Generates a defaultConfig for @netlify/build based on the settings from the heuristics + * Returns the defaultConfig in the format that @netlify/build expects (json version of toml) + * @param settings The settings from the heuristics + */ +export const getDefaultConfig = (settings?: Settings): $TSFixMe | undefined => { + if (!settings) { + return undefined + } + + // TODO: We need proper types for the netlify configuration + const config: $TSFixMe = { build: {} } + + if (settings.buildCommand) { + config.build.command = settings.buildCommand + config.build.commandOrigin = 'default' + } + + if (settings.dist) { + config.build.publish = settings.dist + config.build.publishOrigin = 'default' + } + + config.plugins = settings.plugins_recommended?.map((plugin) => ({ package: plugin })) || [] + + return config +} diff --git a/src/utils/deploy/deploy-site.ts b/src/utils/deploy/deploy-site.ts index 2ea964a8f84..5cb12efca61 100644 --- a/src/utils/deploy/deploy-site.ts +++ b/src/utils/deploy/deploy-site.ts @@ -139,7 +139,9 @@ export const deploySite = async ( } if (functionsWithNativeModules.length !== 0) { - const functionsWithNativeModulesMessage = functionsWithNativeModules.map(({ name }) => `- ${name}`).join('\n') + const functionsWithNativeModulesMessage = functionsWithNativeModules + .map(({ name }: { name: string }) => `- ${name}`) + .join('\n') warn(`Modules with native dependencies\n ${functionsWithNativeModulesMessage} diff --git a/src/utils/deploy/hash-fns.ts b/src/utils/deploy/hash-fns.ts index ce4b115ebc9..86f61db627b 100644 --- a/src/utils/deploy/hash-fns.ts +++ b/src/utils/deploy/hash-fns.ts @@ -125,7 +125,7 @@ const hashFns = async ( statusCb: $TSFixMe tmpDir: $TSFixMe }, -) => { +): Promise<$TSFixMe> => { const { assetType = 'function', concurrentHash, @@ -166,8 +166,8 @@ const hashFns = async ( priority, runtime, runtimeVersion, - trafficRules, timeout, + trafficRules, }) => ({ filepath: functionPath, root: tmpDir, diff --git a/src/utils/feature-flags.ts b/src/utils/feature-flags.ts index 63de0367500..3813072dc25 100644 --- a/src/utils/feature-flags.ts +++ b/src/utils/feature-flags.ts @@ -20,10 +20,11 @@ export const isFeatureFlagEnabled = (flagName: string, siteInfo): boolean => export const getFeatureFlagsFromSiteInfo = (siteInfo: { feature_flags?: Record }): FeatureFlags => ({ - ...(siteInfo.feature_flags || {}), + ...siteInfo.feature_flags, // see https://github.com/netlify/pod-dev-foundations/issues/581#issuecomment-1731022753 zisi_golang_use_al2: isFeatureFlagEnabled('cli_golang_use_al2', siteInfo), netlify_build_frameworks_api: true, + project_ceruledge_ui: true, }) export type FeatureFlags = Record diff --git a/tests/integration/__fixtures__/next-app-without-config/.gitignore b/tests/integration/__fixtures__/next-app-without-config/.gitignore new file mode 100644 index 00000000000..fd3dbb571a1 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/tests/integration/__fixtures__/next-app-without-config/app/favicon.ico b/tests/integration/__fixtures__/next-app-without-config/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/tests/integration/__fixtures__/next-app-without-config/app/globals.css b/tests/integration/__fixtures__/next-app-without-config/app/globals.css new file mode 100644 index 00000000000..f4bd77c0cca --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/app/globals.css @@ -0,0 +1,107 @@ +:root { + --max-width: 1100px; + --border-radius: 12px; + --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", + "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", + "Fira Mono", "Droid Sans Mono", "Courier New", monospace; + + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; + + --primary-glow: conic-gradient( + from 180deg at 50% 50%, + #16abff33 0deg, + #0885ff33 55deg, + #54d6ff33 120deg, + #0071ff33 160deg, + transparent 360deg + ); + --secondary-glow: radial-gradient( + rgba(255, 255, 255, 1), + rgba(255, 255, 255, 0) + ); + + --tile-start-rgb: 239, 245, 249; + --tile-end-rgb: 228, 232, 233; + --tile-border: conic-gradient( + #00000080, + #00000040, + #00000030, + #00000020, + #00000010, + #00000010, + #00000080 + ); + + --callout-rgb: 238, 240, 241; + --callout-border-rgb: 172, 175, 176; + --card-rgb: 180, 185, 188; + --card-border-rgb: 131, 134, 135; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + + --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); + --secondary-glow: linear-gradient( + to bottom right, + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0.3) + ); + + --tile-start-rgb: 2, 13, 46; + --tile-end-rgb: 2, 5, 19; + --tile-border: conic-gradient( + #ffffff80, + #ffffff40, + #ffffff30, + #ffffff20, + #ffffff10, + #ffffff10, + #ffffff80 + ); + + --callout-rgb: 20, 20, 20; + --callout-border-rgb: 108, 108, 108; + --card-rgb: 100, 100, 100; + --card-border-rgb: 200, 200, 200; + } +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + color: rgb(var(--foreground-rgb)); + background: linear-gradient( + to bottom, + transparent, + rgb(var(--background-end-rgb)) + ) + rgb(var(--background-start-rgb)); +} + +a { + color: inherit; + text-decoration: none; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } +} diff --git a/tests/integration/__fixtures__/next-app-without-config/app/layout.js b/tests/integration/__fixtures__/next-app-without-config/app/layout.js new file mode 100644 index 00000000000..821f7122830 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/app/layout.js @@ -0,0 +1,17 @@ +import { Inter } from 'next/font/google' +import './globals.css' + +const inter = Inter({ subsets: ['latin'] }) + +export const metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} diff --git a/tests/integration/__fixtures__/next-app-without-config/app/page.js b/tests/integration/__fixtures__/next-app-without-config/app/page.js new file mode 100644 index 00000000000..9b226e82e9f --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/app/page.js @@ -0,0 +1,79 @@ +import Image from 'next/image' +import styles from './page.module.css' + +export default function Home() { + return ( +
+
+

+ Get started by editing  + app/page.js +

+ +
+ +
+ Next.js Logo +
+ + +
+ ) +} diff --git a/tests/integration/__fixtures__/next-app-without-config/app/page.module.css b/tests/integration/__fixtures__/next-app-without-config/app/page.module.css new file mode 100644 index 00000000000..5c4b1e6a2c6 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/app/page.module.css @@ -0,0 +1,230 @@ +.main { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 6rem; + min-height: 100vh; +} + +.description { + display: inherit; + justify-content: inherit; + align-items: inherit; + font-size: 0.85rem; + max-width: var(--max-width); + width: 100%; + z-index: 2; + font-family: var(--font-mono); +} + +.description a { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; +} + +.description p { + position: relative; + margin: 0; + padding: 1rem; + background-color: rgba(var(--callout-rgb), 0.5); + border: 1px solid rgba(var(--callout-border-rgb), 0.3); + border-radius: var(--border-radius); +} + +.code { + font-weight: 700; + font-family: var(--font-mono); +} + +.grid { + display: grid; + grid-template-columns: repeat(4, minmax(25%, auto)); + max-width: 100%; + width: var(--max-width); +} + +.card { + padding: 1rem 1.2rem; + border-radius: var(--border-radius); + background: rgba(var(--card-rgb), 0); + border: 1px solid rgba(var(--card-border-rgb), 0); + transition: background 200ms, border 200ms; +} + +.card span { + display: inline-block; + transition: transform 200ms; +} + +.card h2 { + font-weight: 600; + margin-bottom: 0.7rem; +} + +.card p { + margin: 0; + opacity: 0.6; + font-size: 0.9rem; + line-height: 1.5; + max-width: 30ch; + text-wrap: balance; +} + +.center { + display: flex; + justify-content: center; + align-items: center; + position: relative; + padding: 4rem 0; +} + +.center::before { + background: var(--secondary-glow); + border-radius: 50%; + width: 480px; + height: 360px; + margin-left: -400px; +} + +.center::after { + background: var(--primary-glow); + width: 240px; + height: 180px; + z-index: -1; +} + +.center::before, +.center::after { + content: ""; + left: 50%; + position: absolute; + filter: blur(45px); + transform: translateZ(0); +} + +.logo { + position: relative; +} +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + .card:hover { + background: rgba(var(--card-rgb), 0.1); + border: 1px solid rgba(var(--card-border-rgb), 0.15); + } + + .card:hover span { + transform: translateX(4px); + } +} + +@media (prefers-reduced-motion) { + .card:hover span { + transform: none; + } +} + +/* Mobile */ +@media (max-width: 700px) { + .content { + padding: 4rem; + } + + .grid { + grid-template-columns: 1fr; + margin-bottom: 120px; + max-width: 320px; + text-align: center; + } + + .card { + padding: 1rem 2.5rem; + } + + .card h2 { + margin-bottom: 0.5rem; + } + + .center { + padding: 8rem 0 6rem; + } + + .center::before { + transform: none; + height: 300px; + } + + .description { + font-size: 0.8rem; + } + + .description a { + padding: 1rem; + } + + .description p, + .description div { + display: flex; + justify-content: center; + position: fixed; + width: 100%; + } + + .description p { + align-items: center; + inset: 0 0 auto; + padding: 2rem 1rem 1.4rem; + border-radius: 0; + border: none; + border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); + background: linear-gradient( + to bottom, + rgba(var(--background-start-rgb), 1), + rgba(var(--callout-rgb), 0.5) + ); + background-clip: padding-box; + backdrop-filter: blur(24px); + } + + .description div { + align-items: flex-end; + pointer-events: none; + inset: auto 0 0; + padding: 2rem; + height: 200px; + background: linear-gradient( + to bottom, + transparent 0%, + rgb(var(--background-end-rgb)) 40% + ); + z-index: 1; + } +} + +/* Tablet and Smaller Desktop */ +@media (min-width: 701px) and (max-width: 1120px) { + .grid { + grid-template-columns: repeat(2, 50%); + } +} + +@media (prefers-color-scheme: dark) { + .vercelLogo { + filter: invert(1); + } + + .logo { + filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); + } +} + +@keyframes rotate { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +} diff --git a/tests/integration/__fixtures__/next-app-without-config/jsconfig.json b/tests/integration/__fixtures__/next-app-without-config/jsconfig.json new file mode 100644 index 00000000000..2a2e4b3bf8b --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./*"] + } + } +} diff --git a/tests/integration/__fixtures__/next-app-without-config/next.config.mjs b/tests/integration/__fixtures__/next-app-without-config/next.config.mjs new file mode 100644 index 00000000000..1d6147825a3 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/next.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +export default nextConfig diff --git a/tests/integration/__fixtures__/next-app-without-config/package-lock.json b/tests/integration/__fixtures__/next-app-without-config/package-lock.json new file mode 100644 index 00000000000..9d1e401853d --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/package-lock.json @@ -0,0 +1,399 @@ +{ + "name": "next-app-without-config", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "next-app-without-config", + "version": "0.1.0", + "dependencies": { + "next": "14.2.5", + "react": "^18", + "react-dom": "^18" + } + }, + "node_modules/@next/env": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", + "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, + "node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", + "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", + "dependencies": { + "@next/env": "14.2.5", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.5", + "@next/swc-darwin-x64": "14.2.5", + "@next/swc-linux-arm64-gnu": "14.2.5", + "@next/swc-linux-arm64-musl": "14.2.5", + "@next/swc-linux-x64-gnu": "14.2.5", + "@next/swc-linux-x64-musl": "14.2.5", + "@next/swc-win32-arm64-msvc": "14.2.5", + "@next/swc-win32-ia32-msvc": "14.2.5", + "@next/swc-win32-x64-msvc": "14.2.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } +} diff --git a/tests/integration/__fixtures__/next-app-without-config/package.json b/tests/integration/__fixtures__/next-app-without-config/package.json new file mode 100644 index 00000000000..02772137f49 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/package.json @@ -0,0 +1,16 @@ +{ + "name": "next-app-without-config", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "react": "^18", + "react-dom": "^18", + "next": "14.2.5" + } +} diff --git a/tests/integration/__fixtures__/next-app-without-config/public/next.svg b/tests/integration/__fixtures__/next-app-without-config/public/next.svg new file mode 100644 index 00000000000..5174b28c565 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/integration/__fixtures__/next-app-without-config/public/vercel.svg b/tests/integration/__fixtures__/next-app-without-config/public/vercel.svg new file mode 100644 index 00000000000..d2f84222734 --- /dev/null +++ b/tests/integration/__fixtures__/next-app-without-config/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/integration/commands/build/build.test.js b/tests/integration/commands/build/build.test.ts similarity index 88% rename from tests/integration/commands/build/build.test.js rename to tests/integration/commands/build/build.test.ts index ebc9c2fb707..2604dd8867b 100644 --- a/tests/integration/commands/build/build.test.js +++ b/tests/integration/commands/build/build.test.ts @@ -2,9 +2,11 @@ import path from 'path' import process from 'process' import execa from 'execa' -import { describe, test } from 'vitest' +import { describe, test, expect } from 'vitest' +import { callCli } from '../../utils/call-cli.js' import { cliPath } from '../../utils/cli-path.js' +import { FixtureTestContext, setupFixtureTests } from '../../utils/fixture.ts' import { withMockApi } from '../../utils/mock-api.js' import { withSiteBuilder } from '../../utils/site-builder.ts' @@ -19,8 +21,15 @@ const defaultEnvs = { const runBuildCommand = async function ( t, cwd, - { apiUrl, env = defaultEnvs, exitCode: expectedExitCode = 0, flags = [], output: outputs } = {}, + options: Partial<{ + exitCode: number + flags: string[] + output: any + env: Record + apiUrl: string + }> = {}, ) { + let { apiUrl, env = defaultEnvs, exitCode: expectedExitCode = 0, flags = [], output: outputs } = options const { all, exitCode } = await execa(cliPath, ['build', ...flags], { reject: false, cwd, @@ -42,7 +51,7 @@ const runBuildCommand = async function ( if (output instanceof RegExp) { t.expect(all).toMatch(output) } else { - t.expect(all.includes(output), `Output of build command does not include '${output}'`).toBe(true) + t.expect(all?.includes(output), `Output of build command does not include '${output}'`).toBe(true) } }) t.expect(exitCode).toBe(expectedExitCode) @@ -313,4 +322,18 @@ describe.concurrent('command/build', () => { }) }) }) + + setupFixtureTests('next-app-without-config', () => { + test('should run build without any netlify specific configuration and install auto detected plugins', async ({ + fixture, + }) => { + const output = await callCli(['build', '--offline'], { cwd: fixture.directory }) + + // expect on the output that it installed the next runtime (auto detected the plugin + the build command and therefore had functions to bundle) + expect(output).toMatch(/❯ Using Next.js Runtime -/) + expect(output).toMatch(/\$ npm run build/) + expect(output).toMatch(/Functions bundling completed/) + expect(output).toMatch(/Edge Functions bundling completed/) + }) + }) }) diff --git a/tests/integration/commands/deploy/deploy.test.js b/tests/integration/commands/deploy/deploy.test.ts similarity index 92% rename from tests/integration/commands/deploy/deploy.test.js rename to tests/integration/commands/deploy/deploy.test.ts index 839fe0700f6..05e05e4cf27 100644 --- a/tests/integration/commands/deploy/deploy.test.js +++ b/tests/integration/commands/deploy/deploy.test.ts @@ -2,12 +2,14 @@ import path from 'path' import process from 'process' import { fileURLToPath } from 'url' +import { load } from 'cheerio' import execa from 'execa' import fetch from 'node-fetch' -import { afterAll, beforeAll, describe, test } from 'vitest' +import { afterAll, beforeAll, describe, expect, test } from 'vitest' import { callCli } from '../../utils/call-cli.js' import { createLiveTestSite, generateSiteName } from '../../utils/create-live-test-site.js' +import { FixtureTestContext, setupFixtureTests } from '../../utils/fixture.js' import { pause } from '../../utils/pause.js' import { withSiteBuilder } from '../../utils/site-builder.ts' @@ -16,29 +18,41 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) const SITE_NAME = generateSiteName('netlify-test-deploy-') -// eslint-disable-next-line no-shadow -const validateContent = async ({ content, path, siteUrl, t }) => { - const response = await fetch(`${siteUrl}${path}`) +const validateContent = async ({ content, path: pathname, siteUrl }) => { + const response = await fetch(`${siteUrl}${pathname}`) const body = await response.text() if (content === undefined) { - t.expect(response.status).toBe(404) + expect(response.status).toBe(404) return } - t.expect(response.status, `status should be 200. request id: ${response.headers.get('x-nf-request-id')}`).toBe(200) - t.expect(body, `body should be as expected. request id: ${response.headers.get('x-nf-request-id')}`).toEqual(content) + expect(response.status, `status should be 200. request id: ${response.headers.get('x-nf-request-id')}`).toBe(200) + expect(body, `body should be as expected. request id: ${response.headers.get('x-nf-request-id')}`).toEqual(content) } -const validateDeploy = async ({ content, contentMessage, deploy, siteName, t }) => { - t.expect(deploy.site_name).toBeTruthy() - t.expect(deploy.deploy_url).toBeTruthy() - t.expect(deploy.deploy_id).toBeTruthy() - t.expect(deploy.logs).toBeTruthy() - t.expect(deploy.site_name, contentMessage).toEqual(siteName) - - await validateContent({ siteUrl: deploy.deploy_url, path: '', content, t }) +const validateDeploy = async ({ + content, + contentMessage, + deploy, + siteName, +}: { + contentMessage?: string + siteName: string + content?: string + deploy: { site_name: string; deploy_url: string; deploy_id: string; logs: string } +}) => { + expect(deploy.site_name).toBeTruthy() + expect(deploy.deploy_url).toBeTruthy() + expect(deploy.deploy_id).toBeTruthy() + expect(deploy.logs).toBeTruthy() + expect(deploy.site_name, contentMessage).toEqual(siteName) + + await validateContent({ siteUrl: deploy.deploy_url, path: '', content }) } -const context = {} +const context: { account: unknown; siteId: string } = { + siteId: '', + account: undefined, +} describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('commands/deploy', () => { beforeAll(async () => { @@ -68,7 +82,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content, t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content }) }) }) @@ -92,7 +106,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co cwd: builder.directory, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content, t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content }) }) }) @@ -117,7 +131,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content, t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content }) }) }) @@ -158,7 +172,6 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co siteName: SITE_NAME, content: 'Edge Function works', contentMessage: 'Edge function did not execute correctly or was not deployed correctly', - t, }) }) }) @@ -205,7 +218,6 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co siteName: SITE_NAME, content: 'Edge Function works', contentMessage: 'Edge function did not execute correctly or was not deployed correctly', - t, }) }) }) @@ -228,7 +240,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co name: 'log-env', plugin: { async onSuccess() { - // eslint-disable-next-line n/global-require, no-undef + // eslint-disable-next-line n/global-require, @typescript-eslint/no-var-requires const { DEPLOY_ID, DEPLOY_URL } = require('process').env console.log(`DEPLOY_ID: ${DEPLOY_ID}`) console.log(`DEPLOY_URL: ${DEPLOY_URL}`) @@ -310,24 +322,21 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index', t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index' }) await validateContent({ siteUrl: deploy.deploy_url, content: undefined, path: '/.hidden-file', - t, }) await validateContent({ siteUrl: deploy.deploy_url, content: undefined, path: '/.hidden-dir', - t, }) await validateContent({ siteUrl: deploy.deploy_url, content: undefined, path: '/__MACOSX', - t, }) }) }) @@ -358,12 +367,11 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index', t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index' }) await validateContent({ siteUrl: deploy.deploy_url, content: undefined, path: '/node_modules/package.json', - t, }) }) }) @@ -394,12 +402,11 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index', t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content: 'index' }) await validateContent({ siteUrl: deploy.deploy_url, content: '{}', path: '/node_modules/package.json', - t, }) }) }) @@ -414,7 +421,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co env: { NETLIFY_SITE_ID: context.siteId }, }) } catch (error) { - t.expect(error.stderr.includes('Error: No files or functions to deploy')).toBe(true) + expect(error.stderr.includes('Error: No files or functions to deploy')).toBe(true) } }) }) @@ -437,7 +444,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co name: 'mutator', plugin: { onPreBuild: async ({ netlifyConfig }) => { - // eslint-disable-next-line no-undef, n/global-require + // eslint-disable-next-line n/global-require, @typescript-eslint/no-var-requires const { mkdir, writeFile } = require('fs/promises') const generatedFunctionsDir = 'new_functions' @@ -690,7 +697,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co const redirectsMessage = fullDeploy.summary.messages.find(({ title }) => title === '3 redirect rules processed') t.expect(redirectsMessage.description).toEqual('All redirect rules deployed without errors.') - await validateDeploy({ deploy, siteName: SITE_NAME, content, t }) + await validateDeploy({ deploy, siteName: SITE_NAME, content }) const [pluginRedirectResponse, _redirectsResponse, netlifyTomResponse] = await Promise.all([ fetch(`${deploy.deploy_url}/other-api/hello`).then((res) => res.text()), @@ -762,7 +769,7 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co true, ) const response = await fetch(`${deployUrl}/.netlify/functions/bundled-function-1`).then((res) => res.text()) - t.expect(response).toEqual('Pre-bundled') + expect(response).toEqual('Pre-bundled') }) }) @@ -945,4 +952,26 @@ describe.skipIf(process.env.NETLIFY_TEST_DISABLE_LIVE === 'true').concurrent('co t.expect(response).toEqual('hello from the blob') }) }) + + setupFixtureTests('next-app-without-config', () => { + test('should run deploy with --build without any netlify specific configuration', async ({ + fixture, + }) => { + const { deploy_url: deployUrl } = await callCli( + ['deploy', '--build', '--json'], + { + cwd: fixture.directory, + env: { NETLIFY_SITE_ID: context.siteId }, + }, + true, + ) + + const html = await fetch(deployUrl).then((res) => res.text()) + // eslint-disable-next-line id-length + const $ = load(html) + + expect($('title').text()).toEqual('Create Next App') + expect($('img[alt="Next.js Logo"]').attr('src')).toBe('/next.svg') + }) + }) })