diff --git a/.gitignore b/.gitignore index 184b8ef1b4c..75085618a5b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ site/src/**/*.md .verdaccio-storage .eslintcache _test_out/** +tests/unit/utils/tmp *.crt *.key diff --git a/src/utils/telemetry/report-error.ts b/src/utils/telemetry/report-error.ts index c14b03ee1cc..a77f2f2a524 100644 --- a/src/utils/telemetry/report-error.ts +++ b/src/utils/telemetry/report-error.ts @@ -22,7 +22,7 @@ const dirPath = dirname(fileURLToPath(import.meta.url)) */ // @ts-expect-error TS(7006) FIXME: Parameter 'error' implicitly has an 'any' type. export const reportError = async function (error, config = {}) { - if (isCI) { + if (isCI || process.env.CI) { return } // convert a NotifiableError to an error class diff --git a/tests/integration/commands/dev/dev.test.ts b/tests/integration/commands/dev/dev.test.ts index c1ca169d281..1f1c9ddecaf 100644 --- a/tests/integration/commands/dev/dev.test.ts +++ b/tests/integration/commands/dev/dev.test.ts @@ -382,14 +382,15 @@ describe.concurrent('command/dev', () => { t.expect(nodeVer).toBeGreaterThanOrEqual(18) await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() const externalServer = startExternalServer({ host: '127.0.0.1', - port: 4567, + port: targetPort, }) await builder.build() await withDevServer( - { cwd: builder.directory, command: 'node', framework: '#custom', targetPort: 4567, skipWaitPort: true }, + { cwd: builder.directory, command: 'node', framework: '#custom', targetPort, skipWaitPort: true }, async (server) => { const response = await fetch(`${server.url}/test`) t.expect(response.status).toBe(200) @@ -828,13 +829,15 @@ describe.concurrent('command/dev', () => { test('deploy environment variables injected by onDev plugin hooks are injected into functions', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() + await builder .withNetlifyToml({ config: { plugins: [{ package: './plugins/plugin' }], dev: { command: 'node index.mjs', - targetPort: 4445, + targetPort, }, }, }) @@ -889,7 +892,7 @@ describe.concurrent('command/dev', () => { res.end(); }) - server.listen(4445) + server.listen(${targetPort.toString()}) `, }) .build() diff --git a/tests/integration/commands/dev/redirects.test.ts b/tests/integration/commands/dev/redirects.test.ts index 19b8d48d511..93233f3e9ab 100644 --- a/tests/integration/commands/dev/redirects.test.ts +++ b/tests/integration/commands/dev/redirects.test.ts @@ -1,3 +1,6 @@ +import { readFile, writeFile } from 'fs/promises' +import { join } from 'path' + import getPort from 'get-port' import fetch from 'node-fetch' import { describe, expect, test } from 'vitest' @@ -32,27 +35,50 @@ describe('redirects', async () => { }) }) - await setupFixtureTests('next-app', { devServer: { env: { NETLIFY_DEV_SERVER_CHECK_SSG_ENDPOINTS: 1 } } }, () => { - test('should prefer local files instead of redirect when not forced', async ({ devServer }) => { - const response = await fetch(`http://localhost:${devServer!.port}/test.txt`, {}) - - expect(response.status).toBe(200) - - const result = await response.text() - expect(result.trim()).toEqual('hello world') - }) - - test('should check for the dynamic page existence before doing redirect', async ({ - devServer, - }) => { - const response = await fetch(`http://localhost:${devServer!.port}/`, {}) - - expect(response.status).toBe(200) - - const result = await response.text() - expect(result.toLowerCase()).not.toContain('netlify') - }) - }) + await setupFixtureTests( + 'next-app', + { + devServer: { env: { NETLIFY_DEV_SERVER_CHECK_SSG_ENDPOINTS: 1 } }, + setup: async ({ fixture }) => { + const targetPort = await getPort() + const packageJsonPath = join(fixture.directory, 'package.json') + const netlifyTomlPath = join(fixture.directory, 'netlify.toml') + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as { scripts: { dev: string } } + + packageJson.scripts.dev = `next dev -p ${targetPort.toString()}` + await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`) + await writeFile( + netlifyTomlPath, + ( + await readFile(netlifyTomlPath, 'utf8') + ).replace('targetPort = 6123', `targetPort = ${targetPort.toString()}`), + ) + }, + }, + () => { + test('should prefer local files instead of redirect when not forced', async ({ + devServer, + }) => { + const response = await fetch(`http://localhost:${devServer!.port}/test.txt`, {}) + + expect(response.status).toBe(200) + + const result = await response.text() + expect(result.trim()).toEqual('hello world') + }) + + test('should check for the dynamic page existence before doing redirect', async ({ + devServer, + }) => { + const response = await fetch(`http://localhost:${devServer!.port}/`, {}) + + expect(response.status).toBe(200) + + const result = await response.text() + expect(result.toLowerCase()).not.toContain('netlify') + }) + }, + ) test('should not check the endpoint existence for hidden proxies', async (t) => { await withSiteBuilder(t, async (builder) => { diff --git a/tests/integration/commands/functions-serve/functions-serve.test.ts b/tests/integration/commands/functions-serve/functions-serve.test.ts index 09a8c1ae326..404d615e486 100644 --- a/tests/integration/commands/functions-serve/functions-serve.test.ts +++ b/tests/integration/commands/functions-serve/functions-serve.test.ts @@ -17,19 +17,18 @@ import { createAIGatewayTestData, } from '../../utils/ai-gateway-helpers.js' -const DEFAULT_PORT = 9999 const SERVE_TIMEOUT = 180_000 const withFunctionsServer = async ( { args = [], builder, - port = DEFAULT_PORT, + port, env = {}, }: { args?: string[] builder: SiteBuilder - port?: number + port: number env?: NodeJS.ProcessEnv }, testHandler: () => Promise, @@ -74,8 +73,9 @@ describe.concurrent('functions:serve command', () => { }) .build() - await withFunctionsServer({ builder }, async () => { - const response = await fetch(`http://localhost:9999/.netlify/functions/ping`) + const port = await getPort() + await withFunctionsServer({ builder, args: ['--port', port.toString()], port }, async () => { + const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/ping`) t.expect(await response.text()).toEqual('ping') }) }) diff --git a/tests/integration/framework-detection.test.ts b/tests/integration/framework-detection.test.ts index fe32530e507..31965162554 100644 --- a/tests/integration/framework-detection.test.ts +++ b/tests/integration/framework-detection.test.ts @@ -1,4 +1,5 @@ import execa from 'execa' +import getPort from 'get-port' import fetch from 'node-fetch' import { describe, test } from 'vitest' @@ -89,6 +90,7 @@ describe.concurrent('frameworks/framework-detection', () => { test('should warn if using static server and `targetPort` is configured', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder .withContentFile({ path: 'public/index.html', @@ -97,7 +99,7 @@ describe.concurrent('frameworks/framework-detection', () => { .build() await withDevServer( - { cwd: builder.directory, args: ['--dir', 'public', '--target-port', '3000'] }, + { cwd: builder.directory, args: ['--dir', 'public', '--target-port', targetPort.toString()] }, async ({ output, url }) => { const response = await fetch(url) const responseContent = await response.text() @@ -111,11 +113,12 @@ describe.concurrent('frameworks/framework-detection', () => { test('should run `command` when both `command` and `targetPort` are configured', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder.withNetlifyToml({ config: { build: { publish: 'public' } } }).build() try { await withDevServer( - { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', '3000'] }, + { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', targetPort.toString()] }, async () => {}, true, ) @@ -185,10 +188,15 @@ describe.concurrent('frameworks/framework-detection', () => { test('should throw if framework=#custom but command is missing', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder.withNetlifyToml({ config: { dev: { framework: '#custom' } } }).build() try { - await withDevServer({ cwd: builder.directory, args: ['--target-port', '3000'] }, async () => {}, true) + await withDevServer( + { cwd: builder.directory, args: ['--target-port', targetPort.toString()] }, + async () => {}, + true, + ) t.expect.unreachable() } catch (err) { t.expect(err).toHaveProperty('stdout') @@ -217,11 +225,12 @@ describe.concurrent('frameworks/framework-detection', () => { test('should start custom command if framework=#custom, command and targetPort are configured', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder.withNetlifyToml({ config: { dev: { framework: '#custom', publish: 'public' } } }).build() try { await withDevServer( - { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', '3000'] }, + { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', targetPort.toString()] }, async () => {}, true, ) @@ -237,6 +246,7 @@ describe.concurrent('frameworks/framework-detection', () => { test(`should print specific error when command doesn't exist`, async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder.build() try { @@ -247,7 +257,7 @@ describe.concurrent('frameworks/framework-detection', () => { '--command', 'oops-i-did-it-again forgot-to-use-a-valid-command', '--target-port', - '3000', + targetPort.toString(), '--framework', '#custom', ], @@ -345,11 +355,12 @@ describe.concurrent('frameworks/framework-detection', () => { test('should not run framework detection if command and targetPort are configured', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() await builder.withContentFile({ path: 'config.toml', content: '' }).build() try { await withDevServer( - { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', '3000'] }, + { cwd: builder.directory, args: ['--command', 'echo hello', '--target-port', targetPort.toString()] }, async () => {}, true, ) diff --git a/tests/unit/utils/copy-template-dir/copy-template-dir.test.ts b/tests/unit/utils/copy-template-dir/copy-template-dir.test.ts index 9d4a1056167..572034da31d 100644 --- a/tests/unit/utils/copy-template-dir/copy-template-dir.test.ts +++ b/tests/unit/utils/copy-template-dir/copy-template-dir.test.ts @@ -3,14 +3,19 @@ import path from 'path' import { fileURLToPath } from 'url' import { readdirpPromise } from 'readdirp' -import { describe, expect, test } from 'vitest' +import { afterEach, describe, expect, test } from 'vitest' import { copyTemplateDir } from '../../../../src/utils/copy-template-dir/copy-template-dir.js' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) +const outDir = path.join(__dirname, '../tmp') describe('copyTemplateDir', () => { + afterEach(() => { + fs.rmSync(outDir, { recursive: true, force: true }) + }) + test('should write a bunch of files', async () => { const checkCreatedFileNames = (names: string[]) => { expect(names).toContain('.a') @@ -25,7 +30,6 @@ describe('copyTemplateDir', () => { } const inDir = path.join(__dirname, 'fixtures') - const outDir = path.join(__dirname, '../tmp') const createdFiles = await copyTemplateDir(inDir, outDir, {}) @@ -38,45 +42,30 @@ describe('copyTemplateDir', () => { // Checks that the files were created in the file system const files = await readdirpPromise(outDir) checkCreatedFileNames(files.map((file) => file.path)) - - // Cleanup - fs.rmdirSync(outDir, { recursive: true }) }) test('should inject context variables strings', async () => { const inDir = path.join(__dirname, 'fixtures') - const outDir = path.join(__dirname, '../tmp') await copyTemplateDir(inDir, outDir, { foo: 'bar' }) const fileContent = fs.readFileSync(path.join(outDir, '1.txt'), 'utf-8').trim() expect(fileContent).toBe('hello bar sama') - - // Cleanup - fs.rmdirSync(outDir, { recursive: true }) }) test('should inject context variables strings into filenames', async () => { const inDir = path.join(__dirname, 'fixtures') - const outDir = path.join(__dirname, '../tmp') await copyTemplateDir(inDir, outDir, { foo: 'bar' }) expect(fs.existsSync(path.join(outDir, 'bar.txt'))).toBe(true) - - // Cleanup - fs.rmdirSync(outDir, { recursive: true }) }) test('should inject context variables strings into directory names', async () => { const inDir = path.join(__dirname, 'fixtures') - const outDir = path.join(__dirname, '../tmp') await copyTemplateDir(inDir, outDir, { foo: 'bar' }) expect(fs.existsSync(path.join(outDir, 'bar'))).toBe(true) - - // Cleanup - fs.rmdirSync(outDir, { recursive: true }) }) })