From 72bbcad160e9c2d27143f8bd617138a2790de3e9 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 25 Jun 2020 20:39:50 -0400 Subject: [PATCH] Add new test cli (#19184) * Add new test cli * Remove --variant accidentally added to test-persist * s/test/tests * Updates from review * Update package.json tests * Missed a release channel in circle.yaml * Update config.yml to use just run: with test commands * Update release-channel options and add build dir checks * Update test args to use the new release-channel options * Fix error in circle config.yml * Fix a wrong condition for the --variant check * Fix a wrong condition for the --persistent check * Prettier * Require build check for devtool tests as well --- .circleci/config.yml | 94 +++--------- package.json | 35 ++--- scripts/jest/jest-cli.js | 323 +++++++++++++++++++++++++++++++++++++++ scripts/jest/jest.js | 13 ++ yarn.lock | 7 - 5 files changed, 374 insertions(+), 98 deletions(-) create mode 100644 scripts/jest/jest-cli.js create mode 100644 scripts/jest/jest.js diff --git a/.circleci/config.yml b/.circleci/config.yml index f318991d22..5804192ca4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -97,10 +97,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test --maxWorkers=2 + - run: yarn test --release-channel=stable --ci yarn_test: docker: *docker @@ -109,10 +106,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test --maxWorkers=2 + - run: yarn test --ci RELEASE_CHANNEL_stable_yarn_test_www: docker: *docker @@ -121,10 +115,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-www --maxWorkers=2 + - run: yarn test --release-channel=www-classic --ci RELEASE_CHANNEL_stable_yarn_test_www_variant: docker: *docker @@ -133,10 +124,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-www-variant --maxWorkers=2 + - run: yarn test --release-channel=www-classic --variant --ci RELEASE_CHANNEL_stable_yarn_test_prod_www: docker: *docker @@ -145,10 +133,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-prod-www --maxWorkers=2 + - run: yarn test --release-channel=www-classic --prod --ci RELEASE_CHANNEL_stable_yarn_test_prod_www_variant: docker: *docker @@ -157,10 +142,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-prod-www-variant --maxWorkers=2 + - run: yarn test --release-channel=www-classic --prod --variant --ci yarn_test_www: docker: *docker @@ -169,10 +151,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-www --maxWorkers=2 + - run: yarn test --release-channel=www-modern --ci yarn_test_www_variant: docker: *docker @@ -181,10 +160,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-www-variant --maxWorkers=2 + - run: yarn test --release-channel=www-modern --variant --ci yarn_test_prod_www: docker: *docker @@ -193,10 +169,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-prod-www --maxWorkers=2 + - run: yarn test --release-channel=www-modern --prod --ci yarn_test_prod_www_variant: docker: *docker @@ -205,10 +178,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-prod-www-variant --maxWorkers=2 + - run: yarn test --release-channel=www-modern --prod --variant --ci RELEASE_CHANNEL_stable_yarn_test_persistent: docker: *docker @@ -218,10 +188,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-persistent --maxWorkers=2 + - run: yarn test --release-channel=stable --persistent --ci RELEASE_CHANNEL_stable_yarn_test_prod: docker: *docker @@ -231,10 +198,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-prod --maxWorkers=2 + - run: yarn test --release-channel=stable --prod --ci yarn_test_prod: docker: *docker @@ -243,10 +207,7 @@ jobs: - checkout - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-prod --maxWorkers=2 + - run: yarn test --release-channel=experimental --prod --ci RELEASE_CHANNEL_stable_yarn_build: docker: *docker @@ -388,10 +349,7 @@ jobs: - attach_workspace: *attach_workspace - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-build --maxWorkers=2 + - run: yarn test --release-channel=stable --build --ci yarn_test_build: docker: *docker @@ -401,10 +359,7 @@ jobs: - attach_workspace: *attach_workspace - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-build --maxWorkers=2 + - run: yarn test --release-channel=experimental --build --ci yarn_test_build_devtools: docker: *docker @@ -414,10 +369,7 @@ jobs: - attach_workspace: *attach_workspace - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-build-devtools --maxWorkers=2 + - run: yarn test --project=devtools --build --ci RELEASE_CHANNEL_stable_yarn_test_dom_fixtures: docker: *docker @@ -446,8 +398,8 @@ jobs: - run: name: Run fuzz tests command: | - FUZZ_TEST_SEED=$RANDOM yarn test fuzz --maxWorkers=2 - FUZZ_TEST_SEED=$RANDOM yarn test-prod fuzz --maxWorkers=2 + FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci + FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci RELEASE_CHANNEL_stable_yarn_test_build_prod: docker: *docker @@ -457,10 +409,7 @@ jobs: - attach_workspace: *attach_workspace - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn test-build-prod --maxWorkers=2 + - run: yarn test --release-channel=stable --build --prod --ci yarn_test_build_prod: docker: *docker @@ -470,10 +419,7 @@ jobs: - attach_workspace: *attach_workspace - *restore_yarn_cache - *run_yarn - - run: - environment: - RELEASE_CHANNEL: experimental - command: yarn test-build-prod --maxWorkers=2 + - run: yarn test --release-channel=experimental --build --prod --ci workflows: version: 2 diff --git a/package.json b/package.json index ec71d97ceb..ac955280bc 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "core-js": "^3.6.4", "coveralls": "^3.0.9", "create-react-class": "^15.6.3", - "cross-env": "^6.0.3", "danger": "^9.2.10", "error-stack-parser": "^2.0.6", "eslint": "^7.0.0", @@ -65,6 +64,7 @@ "gzip-size": "^5.1.1", "jasmine-check": "^1.0.0-rc.0", "jest": "^25.2.7", + "jest-cli": "^25.2.7", "jest-diff": "^25.2.6", "jest-snapshot-serializer-raw": "^1.1.0", "minimatch": "^3.0.4", @@ -90,7 +90,8 @@ "through2": "^3.0.1", "tmp": "^0.1.0", "typescript": "^3.7.5", - "webpack": "^4.41.2" + "webpack": "^4.41.2", + "yargs": "^15.3.1" }, "devEngines": { "node": "8.x || 9.x || 10.x || 11.x || 12.x || 13.x || 14.x" @@ -106,21 +107,21 @@ "lint-build": "node ./scripts/rollup/validate/index.js", "extract-errors": "yarn build --type=dev --extract-errors", "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js && node ./scripts/yarn/downloadReactIsForPrettyFormat.js", - "debug-test": "cross-env NODE_ENV=development node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.source.js --runInBand", - "test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js", - "test-www": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-www.js", - "test-www-variant": "cross-env NODE_ENV=development VARIANT=true jest --config ./scripts/jest/config.source-www.js", - "test-prod-www": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source-www.js", - "test-prod-www-variant": "cross-env NODE_ENV=production VARIANT=true jest --config ./scripts/jest/config.source-www.js", - "test-persistent": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-persistent.js", - "debug-test-persistent": "cross-env NODE_ENV=development node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.source-persistent.js --runInBand", - "test-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source.js", - "debug-test-prod": "cross-env NODE_ENV=production node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.source.js --runInBand", - "test-prod-build": "yarn test-build-prod", - "test-build": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.build.js", - "test-build-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.build.js", - "test-build-devtools": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.build-devtools.js", - "debug-test-build-devtools": "cross-env NODE_ENV=development node --inspect-brk node_modules/jest/bin/jest.js --config ./scripts/jest/config.build-devtools.js", + "debug-test": "yarn test --debug", + "test": "node ./scripts/jest/jest-cli.js", + "test-www": "yarn test --release-channel=www-modern", + "test-www-variant": "yarn test --release-channel=www-modern --variant", + "test-prod-www": "yarn test --prod --release-channel=www-modern", + "test-prod-www-variant": "yarn test --prod --release-channel=www-modern --variant", + "test-persistent": "yarn test --persistent", + "debug-test-persistent": "yarn test --debug --persistent", + "test-prod": "yarn test --prod", + "debug-test-prod": "yarn test --debug --prod", + "test-prod-build": "yarn test --prod --build", + "test-build": "yarn test --build", + "test-build-prod": "yarn test --build --prod", + "test-build-devtools": "yarn test --build --project devtools", + "debug-test-build-devtools": "yarn test --debug --build --project devtools", "test-dom-fixture": "cd fixtures/dom && yarn && yarn prestart && yarn test", "flow": "node ./scripts/tasks/flow.js", "flow-ci": "node ./scripts/tasks/flow-ci.js", diff --git a/scripts/jest/jest-cli.js b/scripts/jest/jest-cli.js new file mode 100644 index 0000000000..74e4e62f08 --- /dev/null +++ b/scripts/jest/jest-cli.js @@ -0,0 +1,323 @@ +'use strict'; + +const {spawn} = require('child_process'); +const chalk = require('chalk'); +const yargs = require('yargs'); +const fs = require('fs'); +const path = require('path'); + +const ossConfig = './scripts/jest/config.source.js'; +const wwwConfig = './scripts/jest/config.source-www.js'; +const devToolsConfig = './scripts/jest/config.build-devtools.js'; + +// TODO: These configs are separate but should be rolled into the configs above +// so that the CLI can provide them as options for any of the configs. +const persistentConfig = './scripts/jest/config.source-persistent.js'; +const buildConfig = './scripts/jest/config.build.js'; + +const argv = yargs + .parserConfiguration({ + // Important: This option tells yargs to move all other options not + // specified here into the `_` key. We use this to send all of the + // Jest options that we don't use through to Jest (like --watch). + 'unknown-options-as-args': true, + }) + .wrap(yargs.terminalWidth()) + .options({ + debug: { + alias: 'd', + describe: 'Run with node debugger attached.', + requiresArg: false, + type: 'boolean', + default: false, + }, + project: { + alias: 'p', + describe: 'Run the given project.', + requiresArg: true, + type: 'string', + default: 'default', + choices: ['default', 'devtools'], + }, + releaseChannel: { + alias: 'r', + describe: 'Run with the given release channel.', + requiresArg: true, + type: 'string', + default: 'experimental', + choices: ['experimental', 'stable', 'www-classic', 'www-modern'], + }, + env: { + alias: 'e', + describe: 'Run with the given node environment.', + requiresArg: true, + type: 'string', + choices: ['development', 'production'], + }, + prod: { + describe: 'Run with NODE_ENV=production.', + requiresArg: false, + type: 'boolean', + default: false, + }, + dev: { + describe: 'Run with NODE_ENV=development.', + requiresArg: false, + type: 'boolean', + default: false, + }, + variant: { + alias: 'v', + describe: 'Run with www variant set to true.', + requiresArg: false, + type: 'boolean', + default: false, + }, + build: { + alias: 'b', + describe: 'Run tests on builds.', + requiresArg: false, + type: 'boolean', + default: false, + }, + persistent: { + alias: 'n', + describe: 'Run with persistence.', + requiresArg: false, + type: 'boolean', + default: false, + }, + ci: { + describe: 'Run tests in CI', + requiresArg: false, + type: 'boolean', + default: false, + }, + }).argv; + +function logError(message) { + console.error(chalk.red(`\n${message}`)); +} +function isWWWConfig() { + return ( + argv.releaseChannel === 'www-classic' || + argv.releaseChannel === 'www-modern' + ); +} + +function isOSSConfig() { + return ( + argv.releaseChannel === 'stable' || argv.releaseChannel === 'experimental' + ); +} + +function validateOptions() { + let success = true; + + if (argv.project === 'devtools') { + if (argv.prod) { + logError( + 'DevTool tests do not support --prod. Remove this option to continue.' + ); + success = false; + } + + if (argv.dev) { + logError( + 'DevTool tests do not support --dev. Remove this option to continue.' + ); + success = false; + } + + if (argv.env) { + logError( + 'DevTool tests do not support --env. Remove this option to continue.' + ); + success = false; + } + + if (argv.persistent) { + logError( + 'DevTool tests do not support --persistent. Remove this option to continue.' + ); + success = false; + } + + if (argv.variant) { + logError( + 'DevTool tests do not support --variant. Remove this option to continue.' + ); + success = false; + } + + if (!argv.build) { + logError('DevTool tests require --build.'); + success = false; + } + } + + if (argv.variant && !isWWWConfig()) { + logError( + 'Variant is only supported for the www release channels. Update these options to continue.' + ); + success = false; + } + + if (argv.build && argv.persistent) { + logError( + 'Persistence is not supported for build targets. Update these options to continue.' + ); + success = false; + } + + if (!isOSSConfig() && argv.persistent) { + logError( + 'Persistence only supported for oss release channels. Update these options to continue.' + ); + success = false; + } + + if (argv.build && isWWWConfig()) { + logError( + 'Build targets are only not supported for www release channels. Update these options to continue.' + ); + success = false; + } + + if (argv.env && argv.env !== 'production' && argv.prod) { + logError( + 'Build type does not match --prod. Update these options to continue.' + ); + success = false; + } + + if (argv.env && argv.env !== 'development' && argv.dev) { + logError( + 'Build type does not match --dev. Update these options to continue.' + ); + success = false; + } + + if (argv.prod && argv.dev) { + logError( + 'Cannot supply both --prod and --dev. Remove one of these options to continue.' + ); + success = false; + } + + if (argv.build) { + // TODO: We could build this if it hasn't been built yet. + const buildDir = path.resolve('./build'); + if (!fs.existsSync(buildDir)) { + logError( + 'Build directory does not exist, please run `yarn build` or remove the --build option.' + ); + success = false; + } else if (Date.now() - fs.statSync(buildDir).mtimeMs > 1000 * 60 * 15) { + logError( + 'Warning: Running a build test with a build directory older than 15 minutes.\nPlease remember to run `yarn build` when using --build.' + ); + } + } + + if (!success) { + console.log(''); // Extra newline. + process.exit(1); + } +} + +function getCommandArgs() { + // Add the correct Jest config. + const args = ['./scripts/jest/jest.js', '--config']; + if (argv.build) { + args.push(buildConfig); + } else if (argv.persistent) { + args.push(persistentConfig); + } else if (argv.project === 'devtools') { + args.push(devToolsConfig); + } else if (isWWWConfig()) { + args.push(wwwConfig); + } else if (isOSSConfig()) { + args.push(ossConfig); + } else { + // We should not get here. + logError('Unrecognized release channel'); + process.exit(1); + } + + // Set the debug options, if necessary. + if (argv.debug) { + args.unshift('--inspect-brk'); + args.push('--runInBand'); + } + + // CI Environments have limited workers. + if (argv.ci) { + args.push('--maxWorkers=2'); + } + + // Push the remaining args onto the command. + // This will send args like `--watch` to Jest. + args.push(argv._); + + return args; +} + +function getEnvars() { + const envars = { + NODE_ENV: argv.env || 'development', + RELEASE_CHANNEL: argv.releaseChannel.match(/modern|experimental/) + ? 'experimental' + : 'stable', + }; + + if (argv.prod) { + envars.NODE_ENV = 'production'; + } + + if (argv.dev) { + envars.NODE_ENV = 'development'; + } + + if (argv.variant) { + envars.VARIANT = true; + } + + return envars; +} + +function main() { + validateOptions(); + const args = getCommandArgs(); + const envars = getEnvars(); + + // Print the full command we're actually running. + console.log( + chalk.dim( + `$ ${Object.keys(envars) + .map(envar => `${envar}=${envars[envar]}`) + .join(' ')}`, + 'node', + args.join(' ') + ) + ); + + // 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. + if (argv.debug) { + console.log(chalk.green('\nStarting debugger...')); + console.log(chalk.green('Open chrome://inspect and press "inspect"\n')); + } + + // Run Jest. + spawn('node', args, {stdio: 'inherit', env: {...envars, ...process.env}}); +} + +main(); diff --git a/scripts/jest/jest.js b/scripts/jest/jest.js new file mode 100644 index 0000000000..fae824c6b3 --- /dev/null +++ b/scripts/jest/jest.js @@ -0,0 +1,13 @@ +#!/usr/bin/env node +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +// --- Welcome to debugging React tests --- +// The debugger pauses on this statement so that you can open the dev tools. +// You can now set breakpoints and begin debugging. +require('jest-cli/bin/jest'); diff --git a/yarn.lock b/yarn.lock index 1045bf53d0..5f6a0f03f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3973,13 +3973,6 @@ cross-env@^3.1.4: cross-spawn "^5.1.0" is-windows "^1.0.0" -cross-env@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" - integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag== - dependencies: - cross-spawn "^7.0.0" - cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"