|
1 | 1 | /* eslint-disable no-console */ |
2 | 2 | import { spawn } from 'child_process'; |
3 | 3 | import * as dotenv from 'dotenv'; |
4 | | -import { mkdtemp, rm } from 'fs/promises'; |
| 4 | +import { mkdtemp, readFile, rm } from 'fs/promises'; |
5 | 5 | import { sync as globSync } from 'glob'; |
6 | 6 | import { tmpdir } from 'os'; |
7 | 7 | import { join, resolve } from 'path'; |
8 | 8 | import { copyToTemp } from './lib/copyToTemp'; |
9 | 9 | import { registrySetup } from './registrySetup'; |
10 | 10 |
|
| 11 | +interface SentryTestVariant { |
| 12 | + 'build-command': string; |
| 13 | + label: string; |
| 14 | +} |
| 15 | + |
| 16 | +interface PackageJson { |
| 17 | + sentryTest?: { |
| 18 | + variants?: SentryTestVariant[]; |
| 19 | + optionalVariants?: SentryTestVariant[]; |
| 20 | + }; |
| 21 | +} |
| 22 | + |
11 | 23 | const DEFAULT_DSN = 'https://username@domain/123'; |
12 | 24 | const DEFAULT_SENTRY_ORG_SLUG = 'sentry-javascript-sdks'; |
13 | 25 | const DEFAULT_SENTRY_PROJECT = 'sentry-javascript-e2e-tests'; |
@@ -58,14 +70,84 @@ function asyncExec( |
58 | 70 | }); |
59 | 71 | } |
60 | 72 |
|
| 73 | +function findMatchingVariant(variants: SentryTestVariant[], variantLabel: string): SentryTestVariant | undefined { |
| 74 | + const variantLabelLower = variantLabel.toLowerCase(); |
| 75 | + |
| 76 | + return variants.find(variant => variant.label.toLowerCase().includes(variantLabelLower)); |
| 77 | +} |
| 78 | + |
| 79 | +async function getVariantBuildCommand( |
| 80 | + packageJsonPath: string, |
| 81 | + variantLabel: string, |
| 82 | + testAppPath: string, |
| 83 | +): Promise<{ buildCommand: string; testLabel: string; matchedVariantLabel?: string }> { |
| 84 | + try { |
| 85 | + const packageJsonContent = await readFile(packageJsonPath, 'utf-8'); |
| 86 | + const packageJson: PackageJson = JSON.parse(packageJsonContent); |
| 87 | + |
| 88 | + const allVariants = [ |
| 89 | + ...(packageJson.sentryTest?.variants || []), |
| 90 | + ...(packageJson.sentryTest?.optionalVariants || []), |
| 91 | + ]; |
| 92 | + |
| 93 | + const matchingVariant = findMatchingVariant(allVariants, variantLabel); |
| 94 | + |
| 95 | + if (matchingVariant) { |
| 96 | + return { |
| 97 | + buildCommand: `volta run ${matchingVariant['build-command']}`, |
| 98 | + testLabel: matchingVariant.label, |
| 99 | + matchedVariantLabel: matchingVariant.label, |
| 100 | + }; |
| 101 | + } |
| 102 | + |
| 103 | + console.log(`No matching variant found for "${variantLabel}" in ${testAppPath}, using default build`); |
| 104 | + } catch (error) { |
| 105 | + console.log(`Could not read variants from package.json for ${testAppPath}, using default build`); |
| 106 | + } |
| 107 | + |
| 108 | + return { |
| 109 | + buildCommand: 'volta run pnpm test:build', |
| 110 | + testLabel: testAppPath, |
| 111 | + }; |
| 112 | +} |
| 113 | + |
61 | 114 | async function run(): Promise<void> { |
62 | 115 | // Load environment variables from .env file locally |
63 | 116 | dotenv.config(); |
64 | 117 |
|
65 | 118 | // Allow to run a single app only via `yarn test:run <app-name>` |
66 | 119 | const appName = process.argv[2] || ''; |
67 | 120 | // Forward any additional flags to the test command |
68 | | - const testFlags = process.argv.slice(3); |
| 121 | + const allTestFlags = process.argv.slice(3); |
| 122 | + |
| 123 | + // Check for --variant flag |
| 124 | + let variantLabel: string | undefined; |
| 125 | + let skipNextFlag = false; |
| 126 | + |
| 127 | + const testFlags = allTestFlags.filter((flag, index) => { |
| 128 | + // Skip this flag if it was marked to skip (variant value after --variant) |
| 129 | + if (skipNextFlag) { |
| 130 | + skipNextFlag = false; |
| 131 | + return false; |
| 132 | + } |
| 133 | + |
| 134 | + // Handle --variant=<value> format |
| 135 | + if (flag.startsWith('--variant=')) { |
| 136 | + variantLabel = flag.split('=')[1]; |
| 137 | + return false; // Remove this flag from testFlags |
| 138 | + } |
| 139 | + |
| 140 | + // Handle --variant <value> format |
| 141 | + if (flag === '--variant') { |
| 142 | + if (index + 1 < allTestFlags.length) { |
| 143 | + variantLabel = allTestFlags[index + 1]; |
| 144 | + skipNextFlag = true; // Mark next flag to be skipped |
| 145 | + } |
| 146 | + return false; |
| 147 | + } |
| 148 | + |
| 149 | + return true; |
| 150 | + }); |
69 | 151 |
|
70 | 152 | const dsn = process.env.E2E_TEST_DSN || DEFAULT_DSN; |
71 | 153 |
|
@@ -107,11 +189,20 @@ async function run(): Promise<void> { |
107 | 189 |
|
108 | 190 | await copyToTemp(originalPath, tmpDirPath); |
109 | 191 | const cwd = tmpDirPath; |
| 192 | + // Resolve variant if needed |
| 193 | + const { buildCommand, testLabel, matchedVariantLabel } = variantLabel |
| 194 | + ? await getVariantBuildCommand(join(tmpDirPath, 'package.json'), variantLabel, testAppPath) |
| 195 | + : { buildCommand: 'volta run pnpm test:build', testLabel: testAppPath }; |
| 196 | + |
| 197 | + // Print which variant we're using if found |
| 198 | + if (matchedVariantLabel) { |
| 199 | + console.log(`Using variant: "${matchedVariantLabel}"`); |
| 200 | + } |
110 | 201 |
|
111 | | - console.log(`Building ${testAppPath} in ${tmpDirPath}...`); |
112 | | - await asyncExec('volta run pnpm test:build', { env, cwd }); |
| 202 | + console.log(`Building ${testLabel} in ${tmpDirPath}...`); |
| 203 | + await asyncExec(buildCommand, { env, cwd }); |
113 | 204 |
|
114 | | - console.log(`Testing ${testAppPath}...`); |
| 205 | + console.log(`Testing ${testLabel}...`); |
115 | 206 | // Pass command and arguments as an array to prevent command injection |
116 | 207 | const testCommand = ['volta', 'run', 'pnpm', 'test:assert', ...testFlags]; |
117 | 208 | await asyncExec(testCommand, { env, cwd }); |
|
0 commit comments