diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 07f3eb069..74d8ab61f 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -60,7 +60,9 @@ jobs: cache-dependency-path: '**/package-lock.json' - uses: oven-sh/setup-bun@v1 - name: setup pnpm/yarn - run: corepack enable + run: | + npm install -g corepack + corepack enable shell: bash - name: Install Deno uses: denoland/setup-deno@v1 @@ -127,8 +129,18 @@ jobs: node-version: '18.x' cache: 'npm' cache-dependency-path: '**/package-lock.json' + - name: Prefer npm global on windows + if: runner.os == 'Windows' + # On Windows by default PATH prefers corepack bundled with Node.js + # This prepends npm global to PATH to ensure that npm installed global corepack is used instead + run: | + echo "$(npm config get prefix)" >> "$GITHUB_PATH" + shell: bash - name: setup pnpm/yarn - run: corepack enable + run: | + # global corepack installation requires --force on Windows, otherwise EEXIST errors occur + npm install -g corepack --force + corepack enable shell: bash - name: Install Deno uses: denoland/setup-deno@v1 diff --git a/tests/integration/turborepo.test.ts b/tests/integration/turborepo.test.ts deleted file mode 100644 index 442a5f001..000000000 --- a/tests/integration/turborepo.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { getLogger } from 'lambda-local' -import { existsSync } from 'node:fs' -import { rm } from 'node:fs/promises' -import { join } from 'node:path' -import { v4 } from 'uuid' -import { beforeEach, expect, test, vi } from 'vitest' -import { type FixtureTestContext } from '../utils/contexts.js' -import { createFixture, runPlugin } from '../utils/fixture.js' -import { generateRandomObjectID, startMockBlobStore } from '../utils/helpers.js' - -// Disable the verbose logging of the lambda-local runtime -getLogger().level = 'alert' - -beforeEach(async (ctx) => { - // set for each test a new deployID and siteID - ctx.deployID = generateRandomObjectID() - ctx.siteID = v4() - vi.stubEnv('SITE_ID', ctx.siteID) - vi.stubEnv('DEPLOY_ID', ctx.deployID) - vi.stubEnv('NETLIFY_PURGE_API_TOKEN', 'fake-token') - - await startMockBlobStore(ctx) -}) - -// monorepo test uses process.chdir which is not working inside vite workers -// so I'm disabling that test for now will revisit later in a follow up PR. -// we have at least a e2e test that tests the monorepo functionality -test.skip('should create the files in the correct directories', async (ctx) => { - await createFixture('turborepo-npm', ctx) - await runPlugin(ctx, { PACKAGE_PATH: 'apps/web' }) - - // test if the files got generated in the correct locations - expect( - existsSync(join(ctx.cwd, '.netlify')), - 'should not have a .netlify folder in the repository root', - ).toBeFalsy() - - expect(existsSync(join(ctx.cwd, 'apps/web/.netlify'))).toBeTruthy() - - await rm(join(ctx.cwd, 'apps/web/.netlify'), { recursive: true, force: true }) - await runPlugin(ctx, { PACKAGE_PATH: 'apps/page-router' }) - - const staticPageInitial = await invokeFunction(ctx, { url: '/static/revalidate-manual' }) - console.log(staticPageInitial.body) - expect(staticPageInitial.statusCode < 400).toBeTruthy() -}) diff --git a/tests/prepare.mjs b/tests/prepare.mjs index 5bc35c6f1..3316fd238 100644 --- a/tests/prepare.mjs +++ b/tests/prepare.mjs @@ -18,12 +18,30 @@ const NEXT_VERSION = process.env.NEXT_VERSION ?? 'latest' const fixturesDir = fileURLToPath(new URL(`./fixtures`, import.meta.url)) const fixtureFilter = argv[2] ?? '' +// E2E tests run next builds, so we don't need to prepare those ahead of time for integration tests +const e2eOnlyFixtures = new Set([ + 'after', + 'cli-before-regional-blobs-support', + 'dist-dir', + // There is also a bug on Windows on Node.js 18.20.6, that cause build failures on this fixture + // see https://github.com/opennextjs/opennextjs-netlify/actions/runs/13268839161/job/37043172448?pr=2749#step:12:78 + 'middleware-og', + 'middleware-single-matcher', + 'nx-integrated', + 'turborepo', + 'turborepo-npm', + 'unstable-cache', +]) + const limit = pLimit(Math.max(2, cpus().length / 2)) const fixtures = readdirSync(fixturesDir) // Ignoring things like `.DS_Store`. .filter((fixture) => !fixture.startsWith('.')) // Applying the filter, if one is set. .filter((fixture) => !fixtureFilter || fixture.startsWith(fixtureFilter)) + // Filter out fixtures that are only needed for E2E tests + .filter((fixture) => !e2eOnlyFixtures.has(fixture)) + console.log(`๐Ÿงช Preparing fixtures: ${fixtures.join(', ')}`) const fixtureList = new Set(fixtures) const fixtureCount = fixtures.length @@ -62,7 +80,15 @@ const promises = fixtures.map((fixture) => this.push(chunk.toString().replace(/\n/gm, `\n[${fixture}] `)) callback() }, + flush(callback) { + // final transform might create non-terminated line with a prefix + // so this is just to make sure we end with a newline so further writes + // to same destination stream start on a new line for better readability + this.push('\n') + callback() + }, }) + console.log(`[${fixture}] Running \`${cmd}\`...`) const output = execaCommand(cmd, { cwd, @@ -80,6 +106,11 @@ const promises = fixtures.map((fixture) => operation: 'revert', }) } + if (output.exitCode !== 0) { + const errorMessage = `[${fixture}] ๐Ÿšจ Failed to install dependencies or build a fixture` + console.error(errorMessage) + throw new Error(errorMessage) + } fixtureList.delete(fixture) }) }).finally(() => { @@ -91,5 +122,22 @@ const promises = fixtures.map((fixture) => } }), ) -await Promise.allSettled(promises) +const prepareFixturesResults = await Promise.allSettled(promises) +const failedFixturesErrors = prepareFixturesResults + .map((promise) => { + if (promise.status === 'rejected') { + return promise.reason + } + return null + }) + .filter(Boolean) + +if (failedFixturesErrors.length > 0) { + console.error('Some fixtures failed to prepare:') + for (const error of failedFixturesErrors) { + console.error(error.message) + } + process.exit(1) +} + console.log('๐ŸŽ‰ All fixtures prepared')