From b957bc493603ba5711bd46425bdfd7cbc76f7cbe Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 21 Jun 2024 15:07:23 -0400 Subject: [PATCH] [ci] Improve parallelism of yarn test Changes the `ci` argument to be an enum instead so the tests use all available workers in GitHub actions. - When `ci === 'github'` also increase maxConcurrency to 10 - Increase timeout of ReactMultiChildText-test.js - Chunk test files ghstack-source-id: 6c9b2f8344fd7159a73acf7c199f56c0b48ab6a4 Pull Request resolved: https://github.com/facebook/react/pull/30033 --- .circleci/config.yml | 2 +- .github/workflows/runtime_test.yml | 106 +++++++++++++----- .../src/__tests__/ReactMultiChildText-test.js | 2 +- scripts/jest/jest-cli.js | 30 +++-- 4 files changed, 99 insertions(+), 41 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 894e52fab609d..d50f491ab5085 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -368,7 +368,7 @@ jobs: steps: - checkout - setup_node_modules - - run: yarn test <> --ci + - run: yarn test <> --ci=circleci yarn_test_build: docker: *docker diff --git a/.github/workflows/runtime_test.yml b/.github/workflows/runtime_test.yml index 1acce045217ee..7ef699a9f2148 100644 --- a/.github/workflows/runtime_test.yml +++ b/.github/workflows/runtime_test.yml @@ -8,36 +8,86 @@ on: - 'compiler/**' jobs: - test: - name: yarn test + # Define the various test parameters and parallelism for this workflow + build_test_params: + name: Build test params runs-on: ubuntu-latest + outputs: + params: ${{ steps.define-params.outputs.result }} + # How many chunks to group tests into + parallelism: 5 + steps: + - uses: actions/github-script@v7 + id: define-params + with: + script: | + return [ + "-r=stable --env=development", + "-r=stable --env=production", + "-r=experimental --env=development", + "-r=experimental --env=production", + "-r=www-classic --env=development --variant=false", + "-r=www-classic --env=production --variant=false", + "-r=www-classic --env=development --variant=true", + "-r=www-classic --env=production --variant=true", + "-r=www-modern --env=development --variant=false", + "-r=www-modern --env=production --variant=false", + "-r=www-modern --env=development --variant=true", + "-r=www-modern --env=production --variant=true", + "-r=xplat --env=development --variant=false", + "-r=xplat --env=development --variant=true", + "-r=xplat --env=production --variant=false", + "-r=xplat --env=production --variant=true", + // TODO: Test more persistent configurations? + "-r=stable --env=development --persistent", + "-r=experimental --env=development --persistent" + ]; + + # Chunk tests into groups for parallelism + chunk_tests: + name: Chunk tests + runs-on: ubuntu-latest + needs: build_test_params + strategy: + matrix: + params: ${{ fromJSON(needs.build_test_params.outputs.params) }} continue-on-error: true + outputs: + chunks: ${{ steps.chunks.outputs.chunks }} + chunk_ids: ${{ steps.chunk_ids.outputs.chunk_ids }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: "yarn" + cache-dependency-path: yarn.lock + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: "**/node_modules" + key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + - run: yarn install --frozen-lockfile + - id: chunks + name: Set chunks + run: echo "chunks=$(yarn --silent test ${{ matrix.params }} --listTests --json --ci=github | jq -cM '[_nwise(length / ${{ needs.build_test_params.outputs.parallelism }} | ceil)]')" >> $GITHUB_OUTPUT + - id: chunk_ids + name: Set chunk IDs + run: echo "chunk_ids=$(echo $CHUNKS | jq -cM 'to_entries | map(.key)')" >> $GITHUB_OUTPUT + env: + CHUNKS: ${{ steps.chunks.outputs.chunks }} + + # Spawn a job for each set of test param and number of chunks + test: + name: yarn test ${{ matrix.params }} (Chunk ${{ matrix.chunk_ids }}) + runs-on: ubuntu-latest + needs: [build_test_params, chunk_tests] strategy: matrix: - # Intentionally passing these as strings instead of creating a - # separate parameter per CLI argument, since it's easier to - # control/see which combinations we want to run. - params: [ - "-r=stable --env=development", - "-r=stable --env=production", - "-r=experimental --env=development", - "-r=experimental --env=production", - "-r=www-classic --env=development --variant=false", - "-r=www-classic --env=production --variant=false", - "-r=www-classic --env=development --variant=true", - "-r=www-classic --env=production --variant=true", - "-r=www-modern --env=development --variant=false", - "-r=www-modern --env=production --variant=false", - "-r=www-modern --env=development --variant=true", - "-r=www-modern --env=production --variant=true", - "-r=xplat --env=development --variant=false", - "-r=xplat --env=development --variant=true", - "-r=xplat --env=production --variant=false", - "-r=xplat --env=production --variant=true", - # TODO: Test more persistent configurations? - "-r=stable --env=development --persistent", - "-r=experimental --env=development --persistent" - ] + params: ${{ fromJSON(needs.build_test_params.outputs.params) }} + chunk_ids: ${{ fromJSON(needs.chunk_tests.outputs.chunk_ids) }} + continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -52,4 +102,6 @@ jobs: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - - run: yarn test ${{ matrix.params }} --ci + - run: echo $CHUNKS | jq '.[${{ matrix.chunk_ids }}] | .[] | @text' | xargs yarn test ${{ matrix.params }} --ci=github + env: + CHUNKS: ${{ needs.chunk_tests.outputs.chunks }} diff --git a/packages/react-dom/src/__tests__/ReactMultiChildText-test.js b/packages/react-dom/src/__tests__/ReactMultiChildText-test.js index c32d13d3b0151..5aeb321308090 100644 --- a/packages/react-dom/src/__tests__/ReactMultiChildText-test.js +++ b/packages/react-dom/src/__tests__/ReactMultiChildText-test.js @@ -77,7 +77,7 @@ const expectChildren = function (container, children) { * faster to render and update. */ describe('ReactMultiChildText', () => { - jest.setTimeout(20000); + jest.setTimeout(30000); it('should correctly handle all possible children for render and update', async () => { await expect(async () => { diff --git a/scripts/jest/jest-cli.js b/scripts/jest/jest-cli.js index 9c3be220fb645..29c58e688a2a0 100644 --- a/scripts/jest/jest-cli.js +++ b/scripts/jest/jest-cli.js @@ -91,8 +91,8 @@ const argv = yargs ci: { describe: 'Run tests in CI', requiresArg: false, - type: 'boolean', - default: false, + type: 'choices', + choices: ['circleci', 'github'], }, compactConsole: { alias: 'c', @@ -309,10 +309,14 @@ function getCommandArgs() { } // CI Environments have limited workers. - if (argv.ci) { + if (argv.ci === 'circleci') { args.push('--maxWorkers=2'); } + if (argv.ci === 'github') { + args.push('--maxConcurrency=10 --workerThreads=true'); + } + // Push the remaining args onto the command. // This will send args like `--watch` to Jest. args.push(...argv._); @@ -364,16 +368,18 @@ function main() { const envars = getEnvars(); const env = Object.entries(envars).map(([k, v]) => `${k}=${v}`); - // Print the full command we're actually running. - const command = `$ ${env.join(' ')} node ${args.join(' ')}`; - console.log(chalk.dim(command)); + if (argv.ci !== 'github') { + // Print the full command we're actually running. + const command = `$ ${env.join(' ')} node ${args.join(' ')}`; + console.log(chalk.dim(command)); - // Print the release channel and project we're running for quick confirmation. - console.log( - chalk.blue( - `\nRunning tests for ${argv.project} (${argv.releaseChannel})...` - ) - ); + // Print the release channel and project we're running for quick confirmation. + console.log( + chalk.blue( + `\nRunning tests for ${argv.project} (${argv.releaseChannel})...` + ) + ); + } // Print a message that the debugger is starting just // for some extra feedback when running the debugger.