From fb315a649cd5d01b357113ecd93c0efc2d9f11fb Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 14 Oct 2026 16:57:58 +0200 Subject: [PATCH 1/2] ci(e2e): Run E2E tests without restoring the monorepo's node_modules E2E jobs restored the ~860 MB root dependency cache and the full build output only to run a few tsx scripts and to resolve the linked test-utils package. The scripts are now plain .mjs files without dependencies, and test-utils is installed from a tarball like the SDK packages. Co-Authored-By: Claude Opus 5.5 --- .github/actions/install-pnpm/action.yml | 2 +- .github/workflows/build.yml | 21 +-- dev-packages/e2e-tests/ciCopyToTemp.mjs | 20 +++ dev-packages/e2e-tests/ciCopyToTemp.ts | 26 --- dev-packages/e2e-tests/ciPnpmOverrides.mjs | 12 ++ dev-packages/e2e-tests/ciPnpmOverrides.ts | 20 --- .../lib/{copyToTemp.ts => copyToTemp.mjs} | 36 ++-- .../e2e-tests/lib/packedTarballUtils.mjs | 83 +++++++++ .../e2e-tests/lib/packedTarballUtils.ts | 64 ------- .../{pnpmOverrides.ts => pnpmOverrides.mjs} | 64 ++++--- .../lib/{runtimeFiles.ts => runtimeFiles.mjs} | 9 +- .../lib/syncPackedTarballSymlinks.mjs | 38 ++++ .../lib/syncPackedTarballSymlinks.ts | 65 ------- dev-packages/e2e-tests/package.json | 8 +- dev-packages/e2e-tests/prepare.mjs | 4 + dev-packages/e2e-tests/prepare.ts | 15 -- dev-packages/e2e-tests/run.ts | 8 +- dev-packages/e2e-tests/tsconfig.json | 4 +- .../validate-packed-tarball-setup.mjs | 39 +++++ .../validate-packed-tarball-setup.ts | 42 ----- ...malize-e2e-test-dump-transaction-events.js | 162 +++++++++--------- 21 files changed, 366 insertions(+), 376 deletions(-) create mode 100644 dev-packages/e2e-tests/ciCopyToTemp.mjs delete mode 100644 dev-packages/e2e-tests/ciCopyToTemp.ts create mode 100644 dev-packages/e2e-tests/ciPnpmOverrides.mjs delete mode 100644 dev-packages/e2e-tests/ciPnpmOverrides.ts rename dev-packages/e2e-tests/lib/{copyToTemp.ts => copyToTemp.mjs} (69%) create mode 100644 dev-packages/e2e-tests/lib/packedTarballUtils.mjs delete mode 100644 dev-packages/e2e-tests/lib/packedTarballUtils.ts rename dev-packages/e2e-tests/lib/{pnpmOverrides.ts => pnpmOverrides.mjs} (70%) rename dev-packages/e2e-tests/lib/{runtimeFiles.ts => runtimeFiles.mjs} (81%) create mode 100644 dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.mjs delete mode 100644 dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.ts create mode 100644 dev-packages/e2e-tests/prepare.mjs delete mode 100644 dev-packages/e2e-tests/prepare.ts create mode 100644 dev-packages/e2e-tests/validate-packed-tarball-setup.mjs delete mode 100644 dev-packages/e2e-tests/validate-packed-tarball-setup.ts diff --git a/.github/actions/install-pnpm/action.yml b/.github/actions/install-pnpm/action.yml index d2d28a09dbb4..a23f372a8f9b 100644 --- a/.github/actions/install-pnpm/action.yml +++ b/.github/actions/install-pnpm/action.yml @@ -13,7 +13,7 @@ runs: shell: bash env: PACKAGE_JSON: ${{ inputs.package-json }} - # Keep in sync with `getPnpmMajor` in `dev-packages/e2e-tests/lib/pnpmOverrides.ts`. It writes the overrides in + # Keep in sync with `getPnpmMajor` in `dev-packages/e2e-tests/lib/pnpmOverrides.mjs`. It writes the overrides in # the format of the version it finds, so a different lookup breaks the install. run: | package_json="$PACKAGE_JSON" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aecb25032c9a..81d5b1882f17 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1095,11 +1095,6 @@ jobs: uses: denoland/setup-deno@v2.0.5 with: deno-version: ${{ matrix.deno-version || 'v2.8.3' }} - - name: Restore caches - uses: ./.github/actions/restore-cache - with: - dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Restore tarball artifacts uses: actions/download-artifact@v8 with: @@ -1119,6 +1114,13 @@ jobs: name: build-layer-output path: ${{ env.BUILD_LAYER_PATH }} + # The Lambda functions install the built workspace packages directly (see `src/stack.ts`). + - name: Restore build artifacts + uses: actions/download-artifact@v8 + if: matrix.test-application == 'aws-serverless' + with: + name: build-output + # Installs Playwright while the app builds. # Started after the artifact downloads: starting next to them made `download-artifact` fail to read the event file. - name: Install Playwright @@ -1175,7 +1177,7 @@ jobs: - name: Pre-process E2E Test Dumps if: failure() run: | - node ./scripts/normalize-e2e-test-dump-transaction-events.js + node ./scripts/normalize-e2e-test-dump-transaction-events.js ${{ runner.temp }}/test-application/event-dumps - name: Upload E2E Test Event Dumps uses: actions/upload-artifact@v7 @@ -1248,11 +1250,6 @@ jobs: uses: denoland/setup-deno@v2.0.5 with: deno-version: ${{ matrix.deno-version || 'v2.8.3' }} - - name: Restore caches - uses: ./.github/actions/restore-cache - with: - dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Restore tarball artifacts uses: actions/download-artifact@v8 with: @@ -1308,7 +1305,7 @@ jobs: - name: Pre-process E2E Test Dumps if: failure() run: | - node ./scripts/normalize-e2e-test-dump-transaction-events.js + node ./scripts/normalize-e2e-test-dump-transaction-events.js ${{ runner.temp }}/test-application/event-dumps - name: Upload E2E Test Event Dumps uses: actions/upload-artifact@v7 diff --git a/dev-packages/e2e-tests/ciCopyToTemp.mjs b/dev-packages/e2e-tests/ciCopyToTemp.mjs new file mode 100644 index 000000000000..f257e00d12a7 --- /dev/null +++ b/dev-packages/e2e-tests/ciCopyToTemp.mjs @@ -0,0 +1,20 @@ +// @ts-check +/* eslint-disable no-console */ + +import { copyToTemp } from './lib/copyToTemp.mjs'; +import { applyRuntimeFiles } from './lib/runtimeFiles.mjs'; + +const originalPath = process.argv[2]; +const tmpDirPath = process.argv[3]; + +if (!originalPath || !tmpDirPath) { + throw new Error('Original path and tmp dir path are required'); +} + +console.log(`Copying ${originalPath} to ${tmpDirPath}...`); + +await copyToTemp(originalPath, tmpDirPath); + +if (process.env.RUNTIME) { + applyRuntimeFiles(tmpDirPath, process.env.RUNTIME); +} diff --git a/dev-packages/e2e-tests/ciCopyToTemp.ts b/dev-packages/e2e-tests/ciCopyToTemp.ts deleted file mode 100644 index 649fe01fed3f..000000000000 --- a/dev-packages/e2e-tests/ciCopyToTemp.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable no-console */ - -import { copyToTemp } from './lib/copyToTemp'; -import { applyRuntimeFiles } from './lib/runtimeFiles'; - -async function run(): Promise { - const originalPath = process.argv[2]; - const tmpDirPath = process.argv[3]; - - if (!originalPath || !tmpDirPath) { - throw new Error('Original path and tmp dir path are required'); - } - - console.log(`Copying ${originalPath} to ${tmpDirPath}...`); - - await copyToTemp(originalPath, tmpDirPath); - - if (process.env.RUNTIME) { - applyRuntimeFiles(tmpDirPath, process.env.RUNTIME); - } -} - -run().catch(error => { - console.error(error); - process.exit(1); -}); diff --git a/dev-packages/e2e-tests/ciPnpmOverrides.mjs b/dev-packages/e2e-tests/ciPnpmOverrides.mjs new file mode 100644 index 000000000000..a3d6d643c6fa --- /dev/null +++ b/dev-packages/e2e-tests/ciPnpmOverrides.mjs @@ -0,0 +1,12 @@ +// @ts-check +import * as path from 'node:path'; +import { addPnpmOverrides } from './lib/pnpmOverrides.mjs'; + +const tmpDirPath = process.argv[2]; +const packedDirPath = process.argv[3]; + +if (!tmpDirPath || !packedDirPath) { + throw new Error('Tmp dir path and packed dir path are required'); +} + +await addPnpmOverrides(path.resolve(tmpDirPath), path.resolve(packedDirPath)); diff --git a/dev-packages/e2e-tests/ciPnpmOverrides.ts b/dev-packages/e2e-tests/ciPnpmOverrides.ts deleted file mode 100644 index 909a59fa2e9d..000000000000 --- a/dev-packages/e2e-tests/ciPnpmOverrides.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable no-console */ - -import { addPnpmOverrides } from './lib/pnpmOverrides'; -import * as path from 'path'; - -async function run(): Promise { - const tmpDirPath = process.argv[2]; - const packedDirPath = process.argv[3]; - - if (!tmpDirPath || !packedDirPath) { - throw new Error('Tmp dir path and packed dir path are required'); - } - - await addPnpmOverrides(path.resolve(tmpDirPath), path.resolve(packedDirPath)); -} - -run().catch(error => { - console.error(error); - process.exit(1); -}); diff --git a/dev-packages/e2e-tests/lib/copyToTemp.ts b/dev-packages/e2e-tests/lib/copyToTemp.mjs similarity index 69% rename from dev-packages/e2e-tests/lib/copyToTemp.ts rename to dev-packages/e2e-tests/lib/copyToTemp.mjs index c45a5793e2fc..ae7f5e04d5fe 100644 --- a/dev-packages/e2e-tests/lib/copyToTemp.ts +++ b/dev-packages/e2e-tests/lib/copyToTemp.mjs @@ -1,22 +1,31 @@ +// @ts-check /* eslint-disable no-console */ -import { readFileSync, writeFileSync } from 'fs'; -import { cp } from 'fs/promises'; -import { isAbsolute, join, resolve } from 'path'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { cp } from 'node:fs/promises'; +import { dirname, isAbsolute, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -export async function copyToTemp(originalPath: string, tmpDirPath: string): Promise { +const __dirname = dirname(fileURLToPath(import.meta.url)); + +/** + * @param {string} originalPath + * @param {string} tmpDirPath + * @returns {Promise} + */ +export async function copyToTemp(originalPath, tmpDirPath) { // copy files to tmp dir await cp(originalPath, tmpDirPath, { recursive: true }); fixPackageJson(tmpDirPath); } -function fixPackageJson(cwd: string): void { +/** + * @param {string} cwd + */ +function fixPackageJson(cwd) { const packageJsonPath = join(cwd, 'package.json'); - const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { - dependencies?: Record; - devDependencies?: Record; - volta?: Record; - }; + /** @type {{ dependencies?: Record; devDependencies?: Record; volta?: Record }} */ + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); // 1. Fix file dependencies if (packageJson.dependencies) { @@ -45,8 +54,11 @@ function fixPackageJson(cwd: string): void { writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); } -// Exported for pnpmOverrides as well -export function fixFileLinkDependencies(dependencyObj: Record): void { +/** + * Exported for pnpmOverrides as well + * @param {Record} dependencyObj + */ +export function fixFileLinkDependencies(dependencyObj) { for (const [key, value] of Object.entries(dependencyObj)) { const prefix = value.startsWith('link:') ? 'link:' : value.startsWith('file:') ? 'file:' : null; if (!prefix) { diff --git a/dev-packages/e2e-tests/lib/packedTarballUtils.mjs b/dev-packages/e2e-tests/lib/packedTarballUtils.mjs new file mode 100644 index 000000000000..c46a94ff9578 --- /dev/null +++ b/dev-packages/e2e-tests/lib/packedTarballUtils.mjs @@ -0,0 +1,83 @@ +// @ts-check +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const E2E_TESTS_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const REPOSITORY_ROOT = path.resolve(E2E_TESTS_ROOT, '../..'); + +// test-utils is not published, but test apps install it from its tarball too: with a `link:`, its dependencies would +// resolve from the monorepo's root `node_modules` instead of the app's. +const TARBALL_PACKAGE_DIRS = [ + ...fs.readdirSync(path.join(REPOSITORY_ROOT, 'packages')).map(dir => path.join(REPOSITORY_ROOT, 'packages', dir)), + path.join(REPOSITORY_ROOT, 'dev-packages', 'test-utils'), +]; + +/** + * Workspace @sentry and @sentry-internal packages that have a built tarball for the E2E version. + * @returns {{ name: string; tarballPath: string }[]} The package names and their tarball paths, sorted by name. + */ +export function getPackedTarballs() { + const version = getE2eTestsPackageVersion(); + const tarballs = []; + + for (const packageDir of TARBALL_PACKAGE_DIRS) { + const packageJsonPath = path.join(packageDir, 'package.json'); + if (!fs.existsSync(packageJsonPath)) { + continue; + } + + const name = readJson(packageJsonPath).name; + if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) { + continue; + } + + const tarballPath = path.join(packageDir, versionedTarballFilename(name, version)); + if (fs.existsSync(tarballPath)) { + tarballs.push({ name, tarballPath }); + } + } + + return tarballs.sort((a, b) => a.name.localeCompare(b.name)); +} + +/** + * Stable symlink name in `packed/` (no version segment). + * @param {string} packageName + * @returns {string} + */ +export function packedSymlinkFilename(packageName) { + return `${npmPackBasename(packageName)}-packed.tgz`; +} + +/** + * Versioned tarball filename produced by `npm pack` in a package directory. + * @param {string} packageName + * @param {string} version + * @returns {string} + */ +function versionedTarballFilename(packageName, version) { + return `${npmPackBasename(packageName)}-${version}.tgz`; +} + +/** + * npm pack tarball basename (without version and .tgz), e.g. `@sentry/core` -> `sentry-core`. + * @param {string} packageName + * @returns {string} + */ +function npmPackBasename(packageName) { + return packageName.replace(/^@/, '').replace(/\//g, '-'); +} + +/** + * @param {string} filePath + * @returns {any} + */ +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +/** @returns {string} */ +export function getE2eTestsPackageVersion() { + return readJson(path.join(E2E_TESTS_ROOT, 'package.json')).version; +} diff --git a/dev-packages/e2e-tests/lib/packedTarballUtils.ts b/dev-packages/e2e-tests/lib/packedTarballUtils.ts deleted file mode 100644 index d7bbeefcb8e7..000000000000 --- a/dev-packages/e2e-tests/lib/packedTarballUtils.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; -import { sync as globSync } from 'glob'; - -const E2E_TESTS_ROOT = path.resolve(__dirname, '..'); -const REPOSITORY_ROOT = path.resolve(E2E_TESTS_ROOT, '../..'); - -// test-utils is not published, but test apps install it from its tarball too: with a `link:`, its dependencies would -// resolve from the monorepo's root `node_modules` instead of the app's. -export const TARBALL_PACKAGE_JSON_GLOB = '{packages/*,dev-packages/test-utils}/package.json'; - -/** - * Workspace @sentry and @sentry-internal packages that have a built tarball for the E2E version. - * @returns The names of the Sentry tarball packages. - */ -export function getPublishedSentryTarballPackageNames(): string[] { - const version = getE2eTestsPackageVersion(); - const names: string[] = []; - - for (const packageJsonPath of globSync(TARBALL_PACKAGE_JSON_GLOB, { - cwd: REPOSITORY_ROOT, - absolute: true, - })) { - const pkg = readJson<{ name?: string }>(packageJsonPath); - const name = pkg.name; - if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) { - continue; - } - const packageDir = path.dirname(packageJsonPath); - const tarball = path.join(packageDir, versionedTarballFilename(name, version)); - if (fs.existsSync(tarball)) { - names.push(name); - } - } - - return names.sort(); -} - -/** Stable symlink name in `packed/` (no version segment). */ -export function packedSymlinkFilename(packageName: string): string { - return `${npmPackBasename(packageName)}-packed.tgz`; -} - -/** - * Versioned tarball filename produced by `npm pack` in a package directory. - */ -export function versionedTarballFilename(packageName: string, version: string): string { - return `${npmPackBasename(packageName)}-${version}.tgz`; -} - -/** - * npm pack tarball basename (without version and .tgz), e.g. `@sentry/core` -> `sentry-core`. - */ -function npmPackBasename(packageName: string): string { - return packageName.replace(/^@/, '').replace(/\//g, '-'); -} - -function readJson(filePath: string): T { - return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T; -} - -function getE2eTestsPackageVersion(): string { - return readJson<{ version: string }>(path.join(E2E_TESTS_ROOT, 'package.json')).version; -} diff --git a/dev-packages/e2e-tests/lib/pnpmOverrides.ts b/dev-packages/e2e-tests/lib/pnpmOverrides.mjs similarity index 70% rename from dev-packages/e2e-tests/lib/pnpmOverrides.ts rename to dev-packages/e2e-tests/lib/pnpmOverrides.mjs index e9f79d05f71e..680d7b9240fb 100644 --- a/dev-packages/e2e-tests/lib/pnpmOverrides.ts +++ b/dev-packages/e2e-tests/lib/pnpmOverrides.mjs @@ -1,7 +1,10 @@ -import { readFile, writeFile } from 'fs/promises'; -import * as path from 'path'; -import { getPublishedSentryTarballPackageNames, packedSymlinkFilename } from './packedTarballUtils'; -import { fixFileLinkDependencies } from './copyToTemp'; +// @ts-check +import { readFile, writeFile } from 'node:fs/promises'; +import * as path from 'node:path'; +import { fixFileLinkDependencies } from './copyToTemp.mjs'; +import { getPackedTarballs, packedSymlinkFilename } from './packedTarballUtils.mjs'; + +/** @typedef {{ pnpm?: { overrides?: Record }; volta?: { extends?: string; pnpm?: string } }} PackageJson */ /** * For a given temp test application directory, add pnpm overrides to pin internal Sentry dependencies to their packed tarballs. @@ -11,18 +14,16 @@ import { fixFileLinkDependencies } from './copyToTemp'; * package.json. A fixture's existing overrides take precedence in both cases. * https://pnpm.io/settings/dependency-resolution#overrides * - * @param tmpDirPath - The temporary directory path of the test application. - * @param packedDirPath - The path to the packed tarballs. - * @param packageNames - The names of the internal Sentry packages to pin to the packed tarballs. + * @param {string} tmpDirPath - The temporary directory path of the test application. + * @param {string} packedDirPath - The path to the packed tarballs. + * @returns {Promise} */ -export async function addPnpmOverrides(tmpDirPath: string, packedDirPath: string): Promise { +export async function addPnpmOverrides(tmpDirPath, packedDirPath) { const packageJsonPath = path.join(tmpDirPath, 'package.json'); - const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as { - pnpm?: { overrides?: Record }; - volta?: { extends?: string; pnpm?: string }; - }; + /** @type {PackageJson} */ + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); - const packageNames = getPublishedSentryTarballPackageNames(); + const packageNames = getPackedTarballs().map(({ name }) => name); const overrides = Object.fromEntries( packageNames.map(packageName => [packageName, `file:${packedDirPath}/${packedSymlinkFilename(packageName)}`]), ); @@ -57,11 +58,13 @@ export async function addPnpmOverrides(tmpDirPath: string, packedDirPath: string console.log(`Added ${packageNames.length} internal Sentry package overrides`); } -// Keep in sync with `.github/actions/install-pnpm`, which installs the version this finds in CI. -async function getPnpmMajor( - packageJsonPath: string, - packageJson: { volta?: { extends?: string; pnpm?: string } }, -): Promise { +/** + * Keep in sync with `.github/actions/install-pnpm`, which installs the version this finds in CI. + * @param {string} packageJsonPath + * @param {PackageJson} packageJson + * @returns {Promise} + */ +async function getPnpmMajor(packageJsonPath, packageJson) { const pnpmVersion = packageJson.volta?.pnpm; if (pnpmVersion) { const major = /^(?\d+)(?:\.|$)/.exec(pnpmVersion)?.groups?.major; @@ -75,16 +78,19 @@ async function getPnpmMajor( const voltaExtends = packageJson.volta?.extends; if (voltaExtends) { const extendedPackageJsonPath = path.resolve(path.dirname(packageJsonPath), voltaExtends); - const extendedPackageJson = JSON.parse(await readFile(extendedPackageJsonPath, 'utf8')) as { - volta?: { extends?: string; pnpm?: string }; - }; + /** @type {PackageJson} */ + const extendedPackageJson = JSON.parse(await readFile(extendedPackageJsonPath, 'utf8')); return getPnpmMajor(extendedPackageJsonPath, extendedPackageJson); } throw new Error(`No Volta pnpm version found for ${packageJsonPath}`); } -function parseWorkspaceOverrides(workspace: string): Record { +/** + * @param {string} workspace + * @returns {Record} + */ +function parseWorkspaceOverrides(workspace) { const overrides = /^overrides:\n((?:[ \t]+.*(?:\n|$))*)/m.exec(workspace)?.[1]; if (!overrides) { return {}; @@ -100,16 +106,24 @@ function parseWorkspaceOverrides(workspace: string): Record { throw new Error(`Unsupported pnpm workspace override: ${line.trim()}`); } - return [JSON.parse(match[1]) as string, JSON.parse(match[2]) as string]; + return [JSON.parse(match[1]), JSON.parse(match[2])]; }), ); } -function removeWorkspaceOverrides(workspace: string): string { +/** + * @param {string} workspace + * @returns {string} + */ +function removeWorkspaceOverrides(workspace) { return workspace.replace(/^overrides:\n(?:[ \t]+.*(?:\n|$))*/m, ''); } -function formatWorkspaceOverrides(overrides: Record): string { +/** + * @param {Record} overrides + * @returns {string} + */ +function formatWorkspaceOverrides(overrides) { return Object.entries(overrides) .map(([packageName, target]) => ` ${JSON.stringify(packageName)}: ${JSON.stringify(target)}`) .join('\n'); diff --git a/dev-packages/e2e-tests/lib/runtimeFiles.ts b/dev-packages/e2e-tests/lib/runtimeFiles.mjs similarity index 81% rename from dev-packages/e2e-tests/lib/runtimeFiles.ts rename to dev-packages/e2e-tests/lib/runtimeFiles.mjs index a29c0bc890d3..505d7309847b 100644 --- a/dev-packages/e2e-tests/lib/runtimeFiles.ts +++ b/dev-packages/e2e-tests/lib/runtimeFiles.mjs @@ -1,12 +1,15 @@ +// @ts-check /* eslint-disable no-console */ -import { copyFileSync, existsSync, readdirSync } from 'fs'; -import { join } from 'path'; +import { copyFileSync, existsSync, readdirSync } from 'node:fs'; +import { join } from 'node:path'; /** * Copies each file in `dir` that has `runtime` as a part of its name over the existing file without that part, for * example `app/entry.server.cloudflare.tsx` over `app/entry.server.tsx`. + * @param {string} dir + * @param {string} runtime */ -export function applyRuntimeFiles(dir: string, runtime: string): void { +export function applyRuntimeFiles(dir, runtime) { for (const entry of readdirSync(dir, { withFileTypes: true })) { if (entry.name === 'node_modules' || entry.name.startsWith('.')) { continue; diff --git a/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.mjs b/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.mjs new file mode 100644 index 000000000000..f74ef9488f75 --- /dev/null +++ b/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.mjs @@ -0,0 +1,38 @@ +// @ts-check +/* eslint-disable no-console */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { getE2eTestsPackageVersion, getPackedTarballs, packedSymlinkFilename } from './packedTarballUtils.mjs'; + +const e2eTestsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const repositoryRoot = path.resolve(e2eTestsRoot, '../..'); +const packedDir = path.join(e2eTestsRoot, 'packed'); + +/** + * Ensures `packed/-packed.tgz` symlinks point at the current versioned tarballs under `packages/*`. + * Run after `yarn build:tarball` at the repo root (or from CI after restoring the tarball cache). + */ +export function syncPackedTarballSymlinks() { + fs.mkdirSync(packedDir, { recursive: true }); + + for (const entry of fs.readdirSync(packedDir, { withFileTypes: true })) { + if (!entry.name.endsWith('-packed.tgz')) { + continue; + } + fs.rmSync(path.join(packedDir, entry.name), { recursive: true, force: true }); + } + + const tarballs = getPackedTarballs(); + if (tarballs.length === 0) { + throw new Error( + `No packed tarballs found for version ${getE2eTestsPackageVersion()} under packages/*/. Run "yarn build:tarball" at the repository root.`, + ); + } + + for (const { name, tarballPath } of tarballs) { + fs.symlinkSync(tarballPath, path.join(packedDir, packedSymlinkFilename(name))); + } + + console.log(`Linked ${tarballs.length} tarball symlinks in ${path.relative(repositoryRoot, packedDir) || 'packed'}.`); +} diff --git a/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.ts b/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.ts deleted file mode 100644 index cdc42832a979..000000000000 --- a/dev-packages/e2e-tests/lib/syncPackedTarballSymlinks.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable no-console */ -import * as fs from 'fs'; -import * as path from 'path'; -import { sync as globSync } from 'glob'; -import { packedSymlinkFilename, TARBALL_PACKAGE_JSON_GLOB, versionedTarballFilename } from './packedTarballUtils'; - -const e2eTestsRoot = path.resolve(__dirname, '..'); -const repositoryRoot = path.resolve(e2eTestsRoot, '../..'); -const packedDir = path.join(e2eTestsRoot, 'packed'); - -function readJson(filePath: string): T { - return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T; -} - -/** - * Ensures `packed/-packed.tgz` symlinks point at the current versioned tarballs. - * Run after `yarn build:tarball` at the repo root (or from CI after restoring the tarball cache). - */ -export function syncPackedTarballSymlinks(): void { - const { version } = readJson<{ version: string }>(path.join(e2eTestsRoot, 'package.json')); - - fs.mkdirSync(packedDir, { recursive: true }); - - for (const entry of fs.readdirSync(packedDir, { withFileTypes: true })) { - if (!entry.name.endsWith('-packed.tgz')) { - continue; - } - fs.rmSync(path.join(packedDir, entry.name), { recursive: true, force: true }); - } - - const packageJsonPaths = globSync(TARBALL_PACKAGE_JSON_GLOB, { - cwd: repositoryRoot, - absolute: true, - }); - - let linked = 0; - for (const packageJsonPath of packageJsonPaths) { - const pkg = readJson<{ name?: string }>(packageJsonPath); - const name = pkg.name; - if (!name || (!name.startsWith('@sentry/') && !name.startsWith('@sentry-internal/'))) { - continue; - } - - const packageDir = path.dirname(packageJsonPath); - const expectedTarball = path.join(packageDir, versionedTarballFilename(name, version)); - - if (!fs.existsSync(expectedTarball)) { - continue; - } - - const linkName = packedSymlinkFilename(name); - const linkPath = path.join(packedDir, linkName); - - fs.symlinkSync(expectedTarball, linkPath); - linked++; - } - - if (linked === 0) { - throw new Error( - `No packed tarballs found for version ${version}. Run "yarn build:tarball" at the repository root.`, - ); - } - - console.log(`Linked ${linked} tarball symlinks in ${path.relative(repositoryRoot, packedDir) || 'packed'}.`); -} diff --git a/dev-packages/e2e-tests/package.json b/dev-packages/e2e-tests/package.json index a92e96a4d64c..6ac9c05d4f18 100644 --- a/dev-packages/e2e-tests/package.json +++ b/dev-packages/e2e-tests/package.json @@ -9,13 +9,13 @@ "lint:ts": "tsc --noEmit", "test:e2e": "run-s test:prepare test:validate test:run", "test:run": "tsx run.ts", - "test:prepare": "tsx prepare.ts", - "test:validate": "tsx validate-packed-tarball-setup.ts", + "test:prepare": "node prepare.mjs", + "test:validate": "node validate-packed-tarball-setup.mjs", "clean": "rimraf tmp node_modules packed && yarn clean:test-applications && yarn clean:pnpm", "ci:build-matrix": "node ./lib/getTestMatrix.mjs", "ci:build-matrix-optional": "node ./lib/getTestMatrix.mjs --optional=true", - "ci:copy-to-temp": "tsx ./ciCopyToTemp.ts", - "ci:pnpm-overrides": "tsx ./ciPnpmOverrides.ts", + "ci:copy-to-temp": "node ./ciCopyToTemp.mjs", + "ci:pnpm-overrides": "node ./ciPnpmOverrides.mjs", "clean:test-applications": "rimraf --glob test-applications/**/{node_modules,dist,build,.next,.nuxt,.sveltekit,.react-router,.astro,.output,pnpm-lock.yaml,.last-run.json,test-results,.angular,event-dumps}", "clean:pnpm": "pnpm store prune" }, diff --git a/dev-packages/e2e-tests/prepare.mjs b/dev-packages/e2e-tests/prepare.mjs new file mode 100644 index 000000000000..bcaea94b2895 --- /dev/null +++ b/dev-packages/e2e-tests/prepare.mjs @@ -0,0 +1,4 @@ +// @ts-check +import { syncPackedTarballSymlinks } from './lib/syncPackedTarballSymlinks.mjs'; + +syncPackedTarballSymlinks(); diff --git a/dev-packages/e2e-tests/prepare.ts b/dev-packages/e2e-tests/prepare.ts deleted file mode 100644 index 049b727b1b21..000000000000 --- a/dev-packages/e2e-tests/prepare.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable no-console */ -import * as dotenv from 'dotenv'; -import { syncPackedTarballSymlinks } from './lib/syncPackedTarballSymlinks'; - -async function run(): Promise { - // Load environment variables from .env file locally - dotenv.config(); - - syncPackedTarballSymlinks(); -} - -run().catch(error => { - console.error(error); - process.exit(1); -}); diff --git a/dev-packages/e2e-tests/run.ts b/dev-packages/e2e-tests/run.ts index f3a7f115925e..38f84ba5cf95 100644 --- a/dev-packages/e2e-tests/run.ts +++ b/dev-packages/e2e-tests/run.ts @@ -5,10 +5,10 @@ import { mkdir, mkdtemp, readFile, rm } from 'fs/promises'; import { sync as globSync } from 'glob'; import { tmpdir } from 'os'; import { join, resolve } from 'path'; -import { copyToTemp } from './lib/copyToTemp'; -import { applyRuntimeFiles } from './lib/runtimeFiles'; -import { syncPackedTarballSymlinks } from './lib/syncPackedTarballSymlinks'; -import { addPnpmOverrides } from './lib/pnpmOverrides'; +import { copyToTemp } from './lib/copyToTemp.mjs'; +import { applyRuntimeFiles } from './lib/runtimeFiles.mjs'; +import { syncPackedTarballSymlinks } from './lib/syncPackedTarballSymlinks.mjs'; +import { addPnpmOverrides } from './lib/pnpmOverrides.mjs'; interface SentryTestVariant { 'build-command': string; diff --git a/dev-packages/e2e-tests/tsconfig.json b/dev-packages/e2e-tests/tsconfig.json index 026669f596c0..f3ef44daf268 100644 --- a/dev-packages/e2e-tests/tsconfig.json +++ b/dev-packages/e2e-tests/tsconfig.json @@ -2,6 +2,8 @@ "extends": "../../tsconfig.json", "exclude": ["node_modules", "test-applications"], "compilerOptions": { - "types": ["node"] + "types": ["node"], + "allowJs": true, + "noEmit": true } } diff --git a/dev-packages/e2e-tests/validate-packed-tarball-setup.mjs b/dev-packages/e2e-tests/validate-packed-tarball-setup.mjs new file mode 100644 index 000000000000..d35627adaa2d --- /dev/null +++ b/dev-packages/e2e-tests/validate-packed-tarball-setup.mjs @@ -0,0 +1,39 @@ +// @ts-check +import * as assert from 'node:assert'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { getE2eTestsPackageVersion, getPackedTarballs } from './lib/packedTarballUtils.mjs'; + +const tarballs = getPackedTarballs(); + +assert.ok( + tarballs.length > 0, + `No tarballs found for version ${getE2eTestsPackageVersion()}. Run "yarn build:tarball" at the repository root.`, +); + +const packedDir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'packed'); +const symlinkPaths = fs.existsSync(packedDir) + ? fs + .readdirSync(packedDir) + .filter(name => name.endsWith('-packed.tgz')) + .map(name => path.join(packedDir, name)) + : []; + +assert.ok( + symlinkPaths.length > 0, + 'No packed tarball symlinks found. Run "yarn test:prepare" in dev-packages/e2e-tests.', +); + +assert.strictEqual( + symlinkPaths.length, + tarballs.length, + `Tarball count (${tarballs.length}) does not match packed symlink count (${symlinkPaths.length}). Re-run "yarn test:prepare".`, +); + +for (const symlinkPath of symlinkPaths) { + const st = fs.lstatSync(symlinkPath); + assert.ok(st.isSymbolicLink(), `Expected ${symlinkPath} to be a symlink.`); + const target = path.resolve(path.dirname(symlinkPath), fs.readlinkSync(symlinkPath)); + assert.ok(fs.existsSync(target), `Symlink ${symlinkPath} points to missing file: ${target}`); +} diff --git a/dev-packages/e2e-tests/validate-packed-tarball-setup.ts b/dev-packages/e2e-tests/validate-packed-tarball-setup.ts deleted file mode 100644 index 18a3545f7a1a..000000000000 --- a/dev-packages/e2e-tests/validate-packed-tarball-setup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as assert from 'assert'; -import * as fs from 'fs'; -import { sync as globSync } from 'glob'; -import * as path from 'path'; - -const repositoryRoot = path.resolve(__dirname, '../..'); - -const e2ePkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')) as { version: string }; -const version = e2ePkg.version; - -const tarballPaths = globSync(`{packages/*,dev-packages/test-utils}/sentry-*-${version}.tgz`, { - cwd: repositoryRoot, - absolute: true, -}); - -assert.ok( - tarballPaths.length > 0, - `No tarballs found for version ${version}. Run "yarn build:tarball" at the repository root.`, -); - -const symlinkPaths = globSync('packed/*-packed.tgz', { - cwd: __dirname, - absolute: true, -}); - -assert.ok( - symlinkPaths.length > 0, - 'No packed tarball symlinks found. Run "yarn test:prepare" in dev-packages/e2e-tests.', -); - -assert.strictEqual( - symlinkPaths.length, - tarballPaths.length, - `Tarball count (${tarballPaths.length}) does not match packed symlink count (${symlinkPaths.length}). Re-run "yarn sync:packed-tarballs".`, -); - -for (const symlinkPath of symlinkPaths) { - const st = fs.lstatSync(symlinkPath); - assert.ok(st.isSymbolicLink(), `Expected ${symlinkPath} to be a symlink.`); - const target = path.resolve(path.dirname(symlinkPath), fs.readlinkSync(symlinkPath)); - assert.ok(fs.existsSync(target), `Symlink ${symlinkPath} points to missing file: ${target}`); -} diff --git a/scripts/normalize-e2e-test-dump-transaction-events.js b/scripts/normalize-e2e-test-dump-transaction-events.js index e3459d52621d..376b86d2b413 100644 --- a/scripts/normalize-e2e-test-dump-transaction-events.js +++ b/scripts/normalize-e2e-test-dump-transaction-events.js @@ -3,93 +3,91 @@ const fs = require('fs'); const path = require('path'); -const glob = require('glob'); - -glob.glob( - '../dev-packages/e2e-tests/test-applications/*/event-dumps/*.dump', - { - cwd: __dirname, - absolute: true, - }, - (err, dumpPaths) => { - if (err) { - throw err; + +const dumpDir = process.argv[2]; +if (!dumpDir) { + throw new Error('Usage: node normalize-e2e-test-dump-transaction-events.js '); +} + +const dumpPaths = fs.existsSync(dumpDir) + ? fs + .readdirSync(dumpDir) + .filter(name => name.endsWith('.dump')) + .map(name => path.join(dumpDir, name)) + : []; + +dumpPaths.forEach(dumpPath => { + const fileContents = fs.readFileSync(dumpPath, 'utf8'); + + const transactionNodes = []; + + fileContents.split('\n').forEach(serializedEnvelope => { + let envelope; + try { + envelope = JSON.parse(serializedEnvelope); + } catch { + return; + // noop } - dumpPaths.forEach(dumpPath => { - const fileContents = fs.readFileSync(dumpPath, 'utf8'); - - const transactionNodes = []; - - fileContents.split('\n').forEach(serializedEnvelope => { - let envelope; - try { - envelope = JSON.parse(serializedEnvelope); - } catch { - return; - // noop - } - - const envelopeItems = envelope[1]; - - envelopeItems.forEach(([envelopeItemHeader, transaction]) => { - if (envelopeItemHeader.type === 'transaction') { - const rootNode = { - runtime: transaction.contexts.runtime?.name, - op: transaction.contexts.trace.op, - name: transaction.transaction, - children: [], - }; - - const spanMap = new Map(); - spanMap.set(transaction.contexts.trace.span_id, rootNode); - - transaction.spans.forEach(span => { - const node = { - op: span.data['sentry.op'], - name: span.description, - parent_span_id: span.parent_span_id, - children: [], - }; - spanMap.set(span.span_id, node); - }); - - transaction.spans.forEach(span => { - const node = spanMap.get(span.span_id); - if (node?.parent_span_id) { - const parentNode = spanMap.get(node.parent_span_id); - parentNode.children.push(node); - } - }); - - transactionNodes.push(rootNode); - } + const envelopeItems = envelope[1]; + + envelopeItems.forEach(([envelopeItemHeader, transaction]) => { + if (envelopeItemHeader.type === 'transaction') { + const rootNode = { + runtime: transaction.contexts.runtime?.name, + op: transaction.contexts.trace.op, + name: transaction.transaction, + children: [], + }; + + const spanMap = new Map(); + spanMap.set(transaction.contexts.trace.span_id, rootNode); + + transaction.spans.forEach(span => { + const node = { + op: span.data['sentry.op'], + name: span.description, + parent_span_id: span.parent_span_id, + children: [], + }; + spanMap.set(span.span_id, node); }); - }); - - const output = transactionNodes - .sort((a, b) => { - const aSerialized = serializeNode(a); - const bSerialized = serializeNode(b); - if (aSerialized < bSerialized) { - return -1; - } else if (aSerialized > bSerialized) { - return 1; - } else { - return 0; + + transaction.spans.forEach(span => { + const node = spanMap.get(span.span_id); + if (node?.parent_span_id) { + const parentNode = spanMap.get(node.parent_span_id); + parentNode.children.push(node); } - }) - .map(node => buildDeterministicStringFromNode(node)) - .join('\n\n-----------------------\n\n'); - - fs.writeFileSync( - path.join(path.dirname(dumpPath), `normalized-transactions-${path.basename(dumpPath, '.dump')}.txt`), - output, - 'utf-8', - ); + }); + + transactionNodes.push(rootNode); + } }); - }, -); + }); + + const output = transactionNodes + .sort((a, b) => { + const aSerialized = serializeNode(a); + const bSerialized = serializeNode(b); + if (aSerialized < bSerialized) { + return -1; + } else if (aSerialized > bSerialized) { + return 1; + } else { + return 0; + } + }) + .map(node => buildDeterministicStringFromNode(node)) + .join('\n\n-----------------------\n\n'); + + fs.writeFileSync( + path.join(path.dirname(dumpPath), `normalized-transactions-${path.basename(dumpPath, '.dump')}.txt`), + output, + 'utf-8', + ); +}); // ------- utility fns ---------- From 64925fbd6c9ac10d507fc67ec77d3abc653508fb Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 14 Oct 2026 17:09:16 +0200 Subject: [PATCH 2/2] ref(e2e): Drop TypeScript and unused dependencies from e2e-tests With all scripts as plain .mjs files, the local runner no longer needs tsx, dotenv or glob. esbuild was unused. Type checking of this package was never run in CI, so it no longer has a tsconfig; the JSDoc types are kept for editors. Co-Authored-By: Claude Opus 5.5 --- dev-packages/e2e-tests/package.json | 10 +-- dev-packages/e2e-tests/{run.ts => run.mjs} | 95 ++++++++++++---------- dev-packages/e2e-tests/tsconfig.json | 9 -- yarn.lock | 10 +-- 4 files changed, 58 insertions(+), 66 deletions(-) rename dev-packages/e2e-tests/{run.ts => run.mjs} (80%) delete mode 100644 dev-packages/e2e-tests/tsconfig.json diff --git a/dev-packages/e2e-tests/package.json b/dev-packages/e2e-tests/package.json index 6ac9c05d4f18..7abbb49fd143 100644 --- a/dev-packages/e2e-tests/package.json +++ b/dev-packages/e2e-tests/package.json @@ -6,9 +6,8 @@ "scripts": { "lint:fix": "oxlint . --fix --type-aware", "lint": "oxlint . --type-aware", - "lint:ts": "tsc --noEmit", "test:e2e": "run-s test:prepare test:validate test:run", - "test:run": "tsx run.ts", + "test:run": "node run.mjs", "test:prepare": "node prepare.mjs", "test:validate": "node validate-packed-tarball-setup.mjs", "clean": "rimraf tmp node_modules packed && yarn clean:test-applications && yarn clean:pnpm", @@ -20,13 +19,8 @@ "clean:pnpm": "pnpm store prune" }, "devDependencies": { - "@types/node": "^18.19.1", - "dotenv": "17.4.2", - "esbuild": "0.28.1", "eslint-plugin-regexp": "^3.1.0", - "glob": "^13.0.6", - "rimraf": "^6.1.3", - "tsx": "^4.23.0" + "rimraf": "^6.1.3" }, "volta": { "extends": "../../package.json" diff --git a/dev-packages/e2e-tests/run.ts b/dev-packages/e2e-tests/run.mjs similarity index 80% rename from dev-packages/e2e-tests/run.ts rename to dev-packages/e2e-tests/run.mjs index 38f84ba5cf95..677880d5537c 100644 --- a/dev-packages/e2e-tests/run.ts +++ b/dev-packages/e2e-tests/run.mjs @@ -1,43 +1,41 @@ +// @ts-check /* eslint-disable no-console */ -import { spawn } from 'child_process'; -import * as dotenv from 'dotenv'; -import { mkdir, mkdtemp, readFile, rm } from 'fs/promises'; -import { sync as globSync } from 'glob'; -import { tmpdir } from 'os'; -import { join, resolve } from 'path'; +import { spawn } from 'node:child_process'; +import { existsSync, readdirSync } from 'node:fs'; +import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { copyToTemp } from './lib/copyToTemp.mjs'; +import { addPnpmOverrides } from './lib/pnpmOverrides.mjs'; import { applyRuntimeFiles } from './lib/runtimeFiles.mjs'; import { syncPackedTarballSymlinks } from './lib/syncPackedTarballSymlinks.mjs'; -import { addPnpmOverrides } from './lib/pnpmOverrides.mjs'; -interface SentryTestVariant { - 'build-command': string; - 'assert-command'?: string; - label?: string; - skip?: boolean; - /** Runtime of the variant (`bun`, `deno` or `cloudflare`). Sets `RUNTIME` and selects the runtime-specific files. */ - runtime?: string; -} +const __dirname = dirname(fileURLToPath(import.meta.url)); -interface PackageJson { - sentryTest?: { - variants?: SentryTestVariant[]; - optionalVariants?: SentryTestVariant[]; - }; -} +/** + * `runtime` is the runtime of the variant (`bun`, `deno` or `cloudflare`). It sets `RUNTIME` and selects the + * runtime-specific files. + * @typedef {{ 'build-command': string; 'assert-command'?: string; label?: string; skip?: boolean; runtime?: string }} SentryTestVariant + */ + +/** @typedef {{ sentryTest?: { variants?: SentryTestVariant[]; optionalVariants?: SentryTestVariant[] } }} PackageJson */ const DEFAULT_DSN = 'https://username@domain/123'; const DEFAULT_SENTRY_ORG_SLUG = 'sentry-javascript-sdks'; const DEFAULT_SENTRY_PROJECT = 'sentry-javascript-e2e-tests'; -function asyncExec( - command: string | string[], - options: { env: Record; cwd: string }, -): Promise { +/** + * @param {string | string[]} command + * @param {{ env: Record; cwd: string }} options + * @returns {Promise} + */ +function asyncExec(command, options) { return new Promise((resolve, reject) => { // If command is an array, use spawn with separate command and args (safer) // If command is a string, maintain backward compatibility with shell: true - let process: ReturnType; + /** @type {ReturnType} */ + let process; if (typeof command === 'string') { process = spawn(command, { ...options, shell: true }); } else { @@ -76,27 +74,28 @@ function asyncExec( }); } -function findMatchingVariant(variants: SentryTestVariant[], variantLabel: string): SentryTestVariant | undefined { +/** + * @param {SentryTestVariant[]} variants + * @param {string} variantLabel + * @returns {SentryTestVariant | undefined} + */ +function findMatchingVariant(variants, variantLabel) { const variantLabelLower = variantLabel.toLowerCase(); return variants.find(variant => variant.label?.toLowerCase().includes(variantLabelLower)); } -async function getVariantBuildCommand( - packageJsonPath: string, - variantLabel: string, - testAppPath: string, -): Promise<{ - buildCommand: string; - assertCommand: string; - testLabel: string; - matchedVariantLabel?: string; - skip?: boolean; - runtime?: string; -}> { +/** + * @param {string} packageJsonPath + * @param {string} variantLabel + * @param {string} testAppPath + * @returns {Promise<{ buildCommand: string; assertCommand: string; testLabel: string; matchedVariantLabel?: string; skip?: boolean; runtime?: string }>} + */ +async function getVariantBuildCommand(packageJsonPath, variantLabel, testAppPath) { try { const packageJsonContent = await readFile(packageJsonPath, 'utf-8'); - const packageJson: PackageJson = JSON.parse(packageJsonContent); + /** @type {PackageJson} */ + const packageJson = JSON.parse(packageJsonContent); const allVariants = [ ...(packageJson.sentryTest?.variants || []), @@ -128,9 +127,12 @@ async function getVariantBuildCommand( }; } -async function run(): Promise { +async function run() { // Load environment variables from .env file locally - dotenv.config(); + const envFile = join(__dirname, '.env'); + if (existsSync(envFile)) { + process.loadEnvFile(envFile); + } // Allow to run a single app only via `yarn test:run ` const appName = process.argv[2] || ''; @@ -138,7 +140,8 @@ async function run(): Promise { const allTestFlags = process.argv.slice(3); // Check for --variant flag - let variantLabel: string | undefined; + /** @type {string | undefined} */ + let variantLabel; let skipNextFlag = false; const testFlags = allTestFlags.filter((flag, index) => { @@ -216,7 +219,11 @@ async function run(): Promise { await asyncExec('pnpm clean:test-applications', { env, cwd: __dirname }); await asyncExec('pnpm cache delete "@sentry/*"', { env, cwd: __dirname }); - const testAppPaths = appName ? [appName.trim()] : globSync('*', { cwd: `${__dirname}/test-applications/` }); + const testAppPaths = appName + ? [appName.trim()] + : readdirSync(join(__dirname, 'test-applications'), { withFileTypes: true }) + .filter(entry => entry.isDirectory() && !entry.name.startsWith('.')) + .map(entry => entry.name); console.log(`Runnings tests for: ${testAppPaths.join(', ')}`); console.log(''); diff --git a/dev-packages/e2e-tests/tsconfig.json b/dev-packages/e2e-tests/tsconfig.json deleted file mode 100644 index f3ef44daf268..000000000000 --- a/dev-packages/e2e-tests/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "exclude": ["node_modules", "test-applications"], - "compilerOptions": { - "types": ["node"], - "allowJs": true, - "noEmit": true - } -} diff --git a/yarn.lock b/yarn.lock index 6d53cd37b12a..f572b86b6aa8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14137,16 +14137,16 @@ dotenv@16.4.7: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== -dotenv@17.4.2, dotenv@^17.3.1, dotenv@^17.4.2: - version "17.4.2" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.4.2.tgz#c07e54a746e11eba021dd9e1047ced5afdc1c034" - integrity sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw== - dotenv@^16.4.5, dotenv@^16.6.1: version "16.6.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== +dotenv@^17.3.1, dotenv@^17.4.2: + version "17.4.2" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.4.2.tgz#c07e54a746e11eba021dd9e1047ced5afdc1c034" + integrity sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw== + dset@^3.1.3, dset@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248"