123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /* eslint-env node */
- /* eslint import/no-nodejs-modules:0 */
- import path from 'path';
- import process from 'process';
- import type {Config} from '@jest/types';
- import babelConfig from './babel.config';
- const {
- CI,
- JEST_TESTS,
- JEST_TEST_BALANCER,
- CI_NODE_TOTAL,
- CI_NODE_INDEX,
- GITHUB_PR_SHA,
- GITHUB_PR_REF,
- GITHUB_RUN_ID,
- GITHUB_RUN_ATTEMPT,
- } = process.env;
- /**
- * In CI we may need to shard our jest tests so that we can parellize the test runs
- *
- * `JEST_TESTS` is a list of all tests that will run, captured by `jest --listTests`
- * Then we split up the tests based on the total number of CI instances that will
- * be running the tests.
- */
- let testMatch: string[] | undefined;
- const BALANCE_RESULTS_PATH = path.resolve(
- __dirname,
- 'tests',
- 'js',
- 'test-balancer',
- 'jest-balance.json'
- );
- /**
- * Given a Map of <testName, testRunTime> and a number of total groups, split the
- * tests into n groups whose total test run times should be roughly equal
- *
- * The source results should be sorted with the slowest tests first. We insert
- * the test into the smallest group on each iteration. This isn't perfect, but
- * should be good enough.
- *
- * Returns a map of <testName, groupIndex>
- */
- function balancer(
- allTests: string[],
- source: Record<string, number>,
- numberGroups: number
- ) {
- const results = new Map<string, number>();
- const totalRunTimes = Array(numberGroups).fill(0);
- /**
- * Find the index of the smallest group (totalRunTimes)
- */
- function findSmallestGroup() {
- let index = 0;
- let smallestRunTime = null;
- for (let i = 0; i < totalRunTimes.length; i++) {
- const runTime = totalRunTimes[i];
- if (!smallestRunTime || runTime <= smallestRunTime) {
- smallestRunTime = totalRunTimes[i];
- index = i;
- }
- if (runTime === 0) {
- break;
- }
- }
- return index;
- }
- /**
- * We may not have a duration for all tests (e.g. a test that was just added)
- * as the `source` needs to be generated
- */
- for (const test of allTests) {
- const index = findSmallestGroup();
- results.set(test, index);
- if (source[test] !== undefined) {
- totalRunTimes[index] = totalRunTimes[index] + source[test];
- }
- }
- return results;
- }
- if (
- JEST_TESTS &&
- typeof CI_NODE_TOTAL !== 'undefined' &&
- typeof CI_NODE_INDEX !== 'undefined'
- ) {
- let balance: null | Record<string, number> = null;
- try {
- balance = require(BALANCE_RESULTS_PATH);
- } catch (err) {
- // Just ignore if balance results doesn't exist
- }
- // Taken from https://github.com/facebook/jest/issues/6270#issue-326653779
- const envTestList = JSON.parse(JEST_TESTS).map(file =>
- file.replace(__dirname, '')
- ) as string[];
- const tests = envTestList.sort((a, b) => b.localeCompare(a));
- const nodeTotal = Number(CI_NODE_TOTAL);
- const nodeIndex = Number(CI_NODE_INDEX);
- if (balance) {
- const results = balancer(envTestList, balance, nodeTotal);
- testMatch = [
- // First, we only want the tests that we have test durations for and belong
- // to the current node's index
- ...Object.entries(Object.fromEntries(results))
- .filter(([, index]) => index === nodeIndex)
- .map(([test]) => `${path.join(__dirname, test)}`),
- ];
- } else {
- const length = tests.length;
- const size = Math.floor(length / nodeTotal);
- const remainder = length % nodeTotal;
- const offset = Math.min(nodeIndex, remainder) + nodeIndex * size;
- const chunk = size + (nodeIndex < remainder ? 1 : 0);
- testMatch = tests.slice(offset, offset + chunk);
- }
- }
- /**
- * For performance we don't want to try and compile everything in the
- * node_modules, but some packages which use ES6 syntax only NEED to be
- * transformed.
- */
- const ESM_NODE_MODULES = ['copy-text-to-clipboard'];
- const config: Config.InitialOptions = {
- verbose: false,
- collectCoverageFrom: [
- 'tests/js/spec/**/*.{js,jsx,tsx}',
- 'static/app/**/*.{js,jsx,ts,tsx}',
- ],
- coverageReporters: ['html', 'cobertura'],
- coverageDirectory: '.artifacts/coverage',
- moduleNameMapper: {
- '^sentry/(.*)': '<rootDir>/static/app/$1',
- '^sentry-test/(.*)': '<rootDir>/tests/js/sentry-test/$1',
- '^sentry-locale/(.*)': '<rootDir>/src/sentry/locale/$1',
- '\\.(css|less|png|jpg|mp4)$': '<rootDir>/tests/js/sentry-test/importStyleMock.js',
- '\\.(svg)$': '<rootDir>/tests/js/sentry-test/svgMock.js',
- 'integration-docs-platforms': '<rootDir>/fixtures/integration-docs/_platforms.json',
- // Disable echarts in test, since they're very slow and take time to
- // transform
- '^echarts/(.*)': '<rootDir>/tests/js/sentry-test/echartsMock.js',
- '^zrender/(.*)': '<rootDir>/tests/js/sentry-test/echartsMock.js',
- },
- setupFiles: [
- '<rootDir>/static/app/utils/silence-react-unsafe-warnings.ts',
- 'jest-canvas-mock',
- ],
- setupFilesAfterEnv: [
- '<rootDir>/tests/js/setup.ts',
- '<rootDir>/tests/js/setupFramework.ts',
- '@testing-library/jest-dom/extend-expect',
- ],
- testMatch: testMatch || [
- '<rootDir>/static/**/?(*.)+(spec|test).[jt]s?(x)',
- '<rootDir>/tests/js/**/*(*.)@(spec|test).(js|ts)?(x)',
- ],
- testPathIgnorePatterns: ['<rootDir>/tests/sentry/lang/javascript/'],
- unmockedModulePathPatterns: [
- '<rootDir>/node_modules/react',
- '<rootDir>/node_modules/reflux',
- ],
- transform: {
- '^.+\\.jsx?$': ['babel-jest', babelConfig as any],
- '^.+\\.tsx?$': ['babel-jest', babelConfig as any],
- '^.+\\.pegjs?$': '<rootDir>/tests/js/jest-pegjs-transform.js',
- },
- transformIgnorePatterns: [`/node_modules/(?!${ESM_NODE_MODULES.join('|')})`],
- moduleFileExtensions: ['js', 'ts', 'jsx', 'tsx'],
- globals: {},
- reporters: [
- 'default',
- [
- 'jest-junit',
- {
- outputDirectory: '.artifacts',
- outputName: 'jest.junit.xml',
- },
- ],
- [
- '<rootDir>/tests/js/test-balancer',
- {
- enabled: !!JEST_TEST_BALANCER,
- resultsPath: BALANCE_RESULTS_PATH,
- },
- ],
- ],
- testEnvironment: '<rootDir>/tests/js/instrumentedEnv',
- testEnvironmentOptions: {
- sentryConfig: {
- init: {
- // jest project under Sentry organization (dev productivity team)
- dsn: 'https://3fe1dce93e3a4267979ebad67f3de327@sentry.io/4857230',
- environment: CI ? 'ci' : 'local',
- tracesSampleRate: 1,
- profilesSampleRate: 1,
- },
- transactionOptions: {
- tags: {
- branch: GITHUB_PR_REF,
- commit: GITHUB_PR_SHA,
- github_run_attempt: GITHUB_RUN_ATTEMPT,
- github_actions_run: `https://github.com/getsentry/sentry/actions/runs/${GITHUB_RUN_ID}`,
- },
- },
- },
- output: path.resolve(__dirname, '.artifacts', 'visual-snapshots', 'jest'),
- },
- };
- export default config;
|