Skip to content

ci: Streamline browser & node unit tests #13307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/new-sdk-release-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ differ slightly for other SDKs depending on how they are structured and how they

- [ ] Make sure `build.yml` CI script is correctly set up to cover tests for the new package

- [ ] Ensure dependent packages are correctly set for “Determine changed packages”
- [ ] Ensure unit tests run correctly
- [ ] If it is a browser SDK, add it to `BROWSER_TEST_PACKAGES` in `scripts/ci-unit-tests.ts`

- [ ] Make sure the file paths in the
["Upload Artifacts" job](https://github.com/getsentry/sentry-javascript/blob/e5c1486eed236b878f2c49d6a04be86093816ac9/.github/workflows/build.yml#L314-L349)
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
"test:unit": "lerna run --ignore \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\" test:unit",
"test:update-snapshots": "lerna run test:update-snapshots",
"test:pr": "nx affected -t test --exclude \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\"",
"test:pr:browser": "yarn test:pr --exclude \"@sentry/{core,utils,opentelemetry,bun,deno,node,profiling-node,aws-serverless,google-cloud-serverless,nextjs,nestjs,astro,cloudflare,solidstart,nuxt,remix,gatsby,sveltekit,vercel-edge}\"",
"test:pr:node": "ts-node ./scripts/node-unit-tests.ts --affected",
"test:ci:browser": "lerna run test --ignore \"@sentry/{core,utils,opentelemetry,bun,deno,node,profiling-node,aws-serverless,google-cloud-serverless,nextjs,nestjs,astro,cloudflare,solidstart,nuxt,remix,gatsby,sveltekit,vercel-edge}\" --ignore \"@sentry-internal/{browser-integration-tests,e2e-tests,integration-shims,node-integration-tests,overhead-metrics}\"",
"test:ci:node": "ts-node ./scripts/node-unit-tests.ts",
"test:pr:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts --affected",
"test:pr:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts --affected",
"test:ci:browser": "UNIT_TEST_ENV=browser ts-node ./scripts/ci-unit-tests.ts",
"test:ci:node": "UNIT_TEST_ENV=node ts-node ./scripts/ci-unit-tests.ts",
"test:ci:bun": "lerna run test --scope @sentry/bun",
"yalc:publish": "lerna run yalc:publish"
},
Expand Down
92 changes: 65 additions & 27 deletions scripts/node-unit-tests.ts → scripts/ci-unit-tests.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as path from 'path';

type NodeVersion = '14' | '16' | '18' | '20' | '21';

interface VersionConfig {
ignoredPackages: Array<`@${'sentry' | 'sentry-internal'}/${string}`>;
}

const UNIT_TEST_ENV = process.env.UNIT_TEST_ENV as 'node' | 'browser' | undefined;

const CURRENT_NODE_VERSION = process.version.replace('v', '').split('.')[0] as NodeVersion;

const RUN_AFFECTED = process.argv.includes('--affected');

const DEFAULT_SKIP_TESTS_PACKAGES = [
'@sentry-internal/eslint-plugin-sdk',
// These packages are tested separately in CI, so no need to run them here
const DEFAULT_SKIP_PACKAGES = ['@sentry/profiling-node', '@sentry/bun', '@sentry/deno'];

// All other packages are run for multiple node versions
const BROWSER_TEST_PACKAGES = [
'@sentry/ember',
'@sentry/browser',
'@sentry/vue',
Expand All @@ -26,10 +33,9 @@ const DEFAULT_SKIP_TESTS_PACKAGES = [
'@sentry-internal/replay-worker',
'@sentry-internal/feedback',
'@sentry/wasm',
'@sentry/bun',
'@sentry/deno',
];

// These are Node-version specific tests that need to be skipped because of support
const SKIP_TEST_PACKAGES: Record<NodeVersion, VersionConfig> = {
'14': {
ignoredPackages: [
Expand All @@ -40,6 +46,7 @@ const SKIP_TEST_PACKAGES: Record<NodeVersion, VersionConfig> = {
'@sentry/astro',
'@sentry/nuxt',
'@sentry/nestjs',
'@sentry-internal/eslint-plugin-sdk',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A micro optimization here is to change eslint-plugin-sdk to only run test for whatever the node version of the local env is.

We can effectively treat it as a browser test then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I guess we should technically run this in multiple node versions, as this is published? 🤔 and actually probably bump the min. node version of this to 16+ as it does not seem to work on 14... 😅 it's internal so I wouild not care about this too much 🤔 WDYT?

],
},
'16': {
Expand All @@ -56,6 +63,50 @@ const SKIP_TEST_PACKAGES: Record<NodeVersion, VersionConfig> = {
},
};

function getAllPackages(): string[] {
const { workspaces }: { workspaces: string[] } = JSON.parse(
fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'),
);

return workspaces.map(workspacePath => {
const { name }: { name: string } = JSON.parse(
fs.readFileSync(path.join(process.cwd(), workspacePath, 'package.json'), 'utf-8'),
);
return name;
});
}

/**
* Run the tests, accounting for compatibility problems in older versions of Node.
*/
function runTests(): void {
const ignores = new Set<string>(DEFAULT_SKIP_PACKAGES);

const packages = getAllPackages();

if (UNIT_TEST_ENV === 'browser') {
// Since we cannot "include" for affected mode, we instead exclude all other packages
packages.forEach(pkg => {
if (!BROWSER_TEST_PACKAGES.includes(pkg)) {
ignores.add(pkg);
}
});
} else if (UNIT_TEST_ENV === 'node') {
BROWSER_TEST_PACKAGES.forEach(pkg => ignores.add(pkg));
}

const versionConfig = SKIP_TEST_PACKAGES[CURRENT_NODE_VERSION];
if (versionConfig) {
versionConfig.ignoredPackages.forEach(dep => ignores.add(dep));
}

if (RUN_AFFECTED) {
runAffectedTests(ignores);
} else {
runAllTests(ignores);
}
}

/**
* Run the given shell command, piping the shell process's `stdin`, `stdout`, and `stderr` to that of the current
* process. Returns contents of `stdout`.
Expand All @@ -67,41 +118,28 @@ function run(cmd: string, options?: childProcess.ExecSyncOptions): void {
/**
* Run tests, ignoring the given packages
*/
function runWithIgnores(skipPackages: string[] = []): void {
const ignoreFlags = skipPackages.map(dep => `--ignore="${dep}"`).join(' ');
function runAllTests(ignorePackages: Set<string>): void {
const ignoreFlags = Array.from(ignorePackages)
.map(dep => `--ignore="${dep}"`)
.join(' ');

run(`yarn test ${ignoreFlags}`);
}

/**
* Run affected tests, ignoring the given packages
*/
function runAffectedWithIgnores(skipPackages: string[] = []): void {
function runAffectedTests(ignorePackages: Set<string>): void {
const additionalArgs = process.argv
.slice(2)
.filter(arg => arg !== '--affected')
.join(' ');
const ignoreFlags = skipPackages.map(dep => `--exclude="${dep}"`).join(' ');
run(`yarn test:pr ${ignoreFlags} ${additionalArgs}`);
}

/**
* Run the tests, accounting for compatibility problems in older versions of Node.
*/
function runTests(): void {
const ignores = new Set<string>();

DEFAULT_SKIP_TESTS_PACKAGES.forEach(pkg => ignores.add(pkg));

const versionConfig = SKIP_TEST_PACKAGES[CURRENT_NODE_VERSION];
if (versionConfig) {
versionConfig.ignoredPackages.forEach(dep => ignores.add(dep));
}
const excludeFlags = Array.from(ignorePackages)
.map(dep => `--exclude="${dep}"`)
.join(' ');

if (RUN_AFFECTED) {
runAffectedWithIgnores(Array.from(ignores));
} else {
runWithIgnores(Array.from(ignores));
}
run(`yarn test:pr ${excludeFlags} ${additionalArgs}`);
}

runTests();
Loading