From 9687eed075b814d5d7cde952ee5196c156a21f06 Mon Sep 17 00:00:00 2001 From: Vincent Ricard Date: Sun, 10 May 2020 13:06:50 +0200 Subject: [PATCH] Move jest-runtime CLI into jest-repl Fixes #10011 --- CHANGELOG.md | 1 + jest.config.js | 1 + .../src/__tests__/SearchSource.test.ts | 2 - .../bin/jest-runtime-cli.js} | 2 +- packages/jest-repl/package.json | 7 +- .../src/__tests__/runtime_cli.test.js | 53 +++++++++++++ .../src/__tests__/test_root/logging.js | 4 +- .../src/__tests__/test_root/throwing.js | 10 +++ packages/jest-repl/src/cli/args.ts | 37 +++++++++- packages/jest-repl/src/cli/index.ts | 7 +- .../src/cli/runtime-cli.ts} | 8 +- .../src => jest-repl/src/cli}/version.ts | 2 +- packages/jest-repl/tsconfig.json | 6 +- packages/jest-runtime/package.json | 1 - .../src/__mocks__/createRuntime.js | 74 +++++++++++++++++-- .../src/__tests__/runtime_cli.test.js | 55 -------------- packages/jest-runtime/src/cli/args.ts | 44 ----------- packages/jest-runtime/src/index.ts | 10 +-- packages/jest-runtime/tsconfig.json | 1 - 19 files changed, 195 insertions(+), 130 deletions(-) rename packages/{jest-runtime/bin/jest-runtime.js => jest-repl/bin/jest-runtime-cli.js} (87%) create mode 100644 packages/jest-repl/src/__tests__/runtime_cli.test.js rename packages/{jest-runtime => jest-repl}/src/__tests__/test_root/logging.js (78%) create mode 100644 packages/jest-repl/src/__tests__/test_root/throwing.js rename packages/{jest-runtime/src/cli/index.ts => jest-repl/src/cli/runtime-cli.ts} (95%) rename packages/{jest-runtime/src => jest-repl/src/cli}/version.ts (80%) delete mode 100644 packages/jest-runtime/src/__tests__/runtime_cli.test.js delete mode 100644 packages/jest-runtime/src/cli/args.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c66a5d976f..dd584acd041b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - `[jest-core]` 🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉 ([#10000](https://github.com/facebook/jest/pull/10000)) - `[jest-core, jest-reporters, jest-test-result, jest-types]` Cleanup `displayName` type ([#10049](https://github.com/facebook/jest/pull/10049)) - `[jest-runtime]` Jest-internal sandbox escape hatch ([#9907](https://github.com/facebook/jest/pull/9907)) +- `[jest-repl, jest-runtime]` [**BREAKING**] Move the `jest-runtime` CLI into `jest-repl` ([#10016](https://github.com/facebook/jest/pull/10016)) ### Performance diff --git a/jest.config.js b/jest.config.js index 18ad91a82b6d..819888e3e832 100644 --- a/jest.config.js +++ b/jest.config.js @@ -49,6 +49,7 @@ module.exports = { '/packages/jest-cli/src/init/__tests__/fixtures/', '/packages/jest-haste-map/src/__tests__/haste_impl.js', '/packages/jest-haste-map/src/__tests__/dependencyExtractor.js', + '/packages/jest-repl/src/__tests__/test_root', '/packages/jest-resolve-dependencies/src/__tests__/__fixtures__/', '/packages/jest-runtime/src/__tests__/defaultResolver.js', '/packages/jest-runtime/src/__tests__/module_dir/', diff --git a/packages/jest-core/src/__tests__/SearchSource.test.ts b/packages/jest-core/src/__tests__/SearchSource.test.ts index fbc4513ef1f6..b1e143d1160a 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.ts +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -423,14 +423,12 @@ describe('SearchSource', () => { it('finds tests that depend directly on the path', () => { const filePath = path.join(rootDir, 'RegularModule.js'); const file2Path = path.join(rootDir, 'RequireRegularModule.js'); - const loggingDep = path.join(rootDir, 'logging.js'); const parentDep = path.join(rootDir, 'ModuleWithSideEffects.js'); const data = searchSource.findRelatedTests(new Set([filePath]), false); expect(toPaths(data.tests).sort()).toEqual([ parentDep, filePath, file2Path, - loggingDep, rootPath, ]); }); diff --git a/packages/jest-runtime/bin/jest-runtime.js b/packages/jest-repl/bin/jest-runtime-cli.js similarity index 87% rename from packages/jest-runtime/bin/jest-runtime.js rename to packages/jest-repl/bin/jest-runtime-cli.js index 6a510e724c5f..c54353904cd7 100755 --- a/packages/jest-runtime/bin/jest-runtime.js +++ b/packages/jest-repl/bin/jest-runtime-cli.js @@ -10,4 +10,4 @@ if (process.env.NODE_ENV == null) { process.env.NODE_ENV = 'test'; } -require('../build/cli').run(); +require('../build/cli/runtime-cli').run(); diff --git a/packages/jest-repl/package.json b/packages/jest-repl/package.json index fd1b1d69f98e..860643c6d200 100644 --- a/packages/jest-repl/package.json +++ b/packages/jest-repl/package.json @@ -10,17 +10,22 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { + "@jest/console": "^26.0.1", + "@jest/environment": "^26.0.1", "@jest/transform": "^26.0.1", "@jest/types": "^26.0.1", + "chalk": "^4.0.0", "jest-config": "^26.0.1", "jest-runtime": "^26.0.1", + "jest-util": "^26.0.1", "jest-validate": "^26.0.1", "repl": "^0.1.3", "yargs": "^15.3.1" }, "devDependencies": { "@jest/test-utils": "^26.0.0", - "@types/yargs": "^15.0.0" + "@types/yargs": "^15.0.0", + "execa": "^4.0.0" }, "bin": "./bin/jest-repl.js", "engines": { diff --git a/packages/jest-repl/src/__tests__/runtime_cli.test.js b/packages/jest-repl/src/__tests__/runtime_cli.test.js new file mode 100644 index 000000000000..91f5d3a820e9 --- /dev/null +++ b/packages/jest-repl/src/__tests__/runtime_cli.test.js @@ -0,0 +1,53 @@ +/** + * 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. + */ + +import path from 'path'; +// eslint-disable-next-line import/named +import {sync as spawnSync} from 'execa'; +import {skipSuiteOnWindows} from '@jest/test-utils'; + +skipSuiteOnWindows(); + +const JEST_RUNTIME = path.resolve(__dirname, '../../bin/jest-runtime-cli.js'); + +const run = args => + spawnSync(JEST_RUNTIME, args, { + cwd: process.cwd(), + env: process.env, + reject: false, + }); + +describe('Runtime CLI', () => { + it('fails with no path', () => { + const expectedOutput = + 'Please provide a path to a script. (See --help for details)'; + expect(run([]).stdout).toBe(expectedOutput); + }); + + it('displays script output', () => { + const scriptPath = path.resolve(__dirname, './test_root/logging.js'); + expect(run([scriptPath, '--no-cache']).stdout).toMatch('Hello, world!'); + }); + + it('always disables automocking', () => { + const scriptPath = path.resolve(__dirname, './test_root/logging.js'); + const output = run([ + scriptPath, + '--no-cache', + '--config=' + + JSON.stringify({ + automock: true, + }), + ]); + expect(output.stdout).toMatch('Hello, world!'); + }); + + it('throws script errors', () => { + const scriptPath = path.resolve(__dirname, './test_root/throwing.js'); + expect(run([scriptPath, '--no-cache']).stderr).toMatch('Error: throwing'); + }); +}); diff --git a/packages/jest-runtime/src/__tests__/test_root/logging.js b/packages/jest-repl/src/__tests__/test_root/logging.js similarity index 78% rename from packages/jest-runtime/src/__tests__/test_root/logging.js rename to packages/jest-repl/src/__tests__/test_root/logging.js index 27fc7d13343f..c68f46394840 100644 --- a/packages/jest-runtime/src/__tests__/test_root/logging.js +++ b/packages/jest-repl/src/__tests__/test_root/logging.js @@ -7,7 +7,9 @@ 'use strict'; -if (require('./RegularModule').getModuleStateValue()) { +if ( + require('jest-runtime/src/__tests__/test_root/RegularModule').getModuleStateValue() +) { console.log('Hello, world!'); } else { console.log('Automocking is not properly disabled in jest-runtime.'); diff --git a/packages/jest-repl/src/__tests__/test_root/throwing.js b/packages/jest-repl/src/__tests__/test_root/throwing.js new file mode 100644 index 000000000000..9b40a996eab0 --- /dev/null +++ b/packages/jest-repl/src/__tests__/test_root/throwing.js @@ -0,0 +1,10 @@ +/** + * 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'; + +throw new Error('throwing'); diff --git a/packages/jest-repl/src/cli/args.ts b/packages/jest-repl/src/cli/args.ts index 3e4a194682b6..09f1b6392660 100644 --- a/packages/jest-repl/src/cli/args.ts +++ b/packages/jest-repl/src/cli/args.ts @@ -7,12 +7,45 @@ */ import type {Options} from 'yargs'; -import Runtime = require('jest-runtime'); export const usage = 'Usage: $0 [--config=]'; +const runtimeCLIOptions: Record< + 'cache' | 'config' | 'debug' | 'version' | 'watchman', + Options +> = { + cache: { + default: true, + description: + 'Whether to use the preprocessor cache. Disable ' + + 'the cache using --no-cache.', + type: 'boolean', + }, + config: { + alias: 'c', + description: 'The path to a Jest config file.', + type: 'string', + }, + debug: { + description: 'Print debugging info about your jest config.', + type: 'boolean', + }, + version: { + alias: 'v', + description: 'Print the version and exit', + type: 'boolean', + }, + watchman: { + default: true, + description: + 'Whether to use watchman for file crawling. Disable using ' + + '--no-watchman.', + type: 'boolean', + }, +}; + export const options: Record = { - ...Runtime.getCLIOptions(), + ...runtimeCLIOptions, replname: { alias: 'r', description: diff --git a/packages/jest-repl/src/cli/index.ts b/packages/jest-repl/src/cli/index.ts index 9d027435023c..3bf1a6fb726d 100644 --- a/packages/jest-repl/src/cli/index.ts +++ b/packages/jest-repl/src/cli/index.ts @@ -7,14 +7,13 @@ * */ -import Runtime = require('jest-runtime'); import yargs = require('yargs'); import {validateCLIOptions} from 'jest-validate'; import {deprecationEntries} from 'jest-config'; import type {Config} from '@jest/types'; import * as args from './args'; - -const {version: VERSION} = require('../../package.json'); +import {run as runtimeCLI} from './runtime-cli'; +import {VERSION} from './version'; const REPL_SCRIPT = require.resolve('./repl.js'); @@ -25,5 +24,5 @@ export = function (): void { argv._ = [REPL_SCRIPT]; - Runtime.runCLI(argv, [`Jest REPL v${VERSION}`]); + runtimeCLI(argv, [`Jest REPL v${VERSION}`]); }; diff --git a/packages/jest-runtime/src/cli/index.ts b/packages/jest-repl/src/cli/runtime-cli.ts similarity index 95% rename from packages/jest-runtime/src/cli/index.ts rename to packages/jest-repl/src/cli/runtime-cli.ts index 490848a2ba1e..23b9fed5e1b2 100644 --- a/packages/jest-runtime/src/cli/index.ts +++ b/packages/jest-repl/src/cli/runtime-cli.ts @@ -9,14 +9,15 @@ import {cpus} from 'os'; import * as path from 'path'; import chalk = require('chalk'); import yargs = require('yargs'); +import Runtime = require('jest-runtime'); import type {Config} from '@jest/types'; import type {JestEnvironment} from '@jest/environment'; import {CustomConsole} from '@jest/console'; import {setGlobal, tryRealpath} from 'jest-util'; import {validateCLIOptions} from 'jest-validate'; import {deprecationEntries, readConfig} from 'jest-config'; -import {VERSION} from '../version'; -import type {Context} from '../types'; +import type {Context} from 'jest-runtime'; +import {VERSION} from './version'; import * as args from './args'; export async function run( @@ -67,9 +68,6 @@ export async function run( automock: false, }; - // Break circular dependency - const Runtime: any = require('..'); - try { const hasteMap: Context = await Runtime.createContext(config, { maxWorkers: Math.max(cpus().length - 1, 1), diff --git a/packages/jest-runtime/src/version.ts b/packages/jest-repl/src/cli/version.ts similarity index 80% rename from packages/jest-runtime/src/version.ts rename to packages/jest-repl/src/cli/version.ts index 6c68483e5054..589132f9db10 100644 --- a/packages/jest-runtime/src/version.ts +++ b/packages/jest-repl/src/cli/version.ts @@ -6,4 +6,4 @@ */ // For some reason, doing `require`ing here works, while inside `cli` fails -export const VERSION: string = require('../package.json').version; +export const VERSION: string = require('../../package.json').version; diff --git a/packages/jest-repl/tsconfig.json b/packages/jest-repl/tsconfig.json index 49565cc45a7e..635574018add 100644 --- a/packages/jest-repl/tsconfig.json +++ b/packages/jest-repl/tsconfig.json @@ -6,9 +6,13 @@ }, "references": [ {"path": "../jest-config"}, + {"path": "../jest-console"}, + {"path": "../jest-environment"}, {"path": "../jest-runtime"}, {"path": "../jest-transform"}, {"path": "../jest-types"}, - {"path": "../jest-validate"} + {"path": "../jest-util"}, + {"path": "../jest-validate"}, + {"path": "../test-utils"} ] } diff --git a/packages/jest-runtime/package.json b/packages/jest-runtime/package.json index e8c0ea9c80aa..3210bf3167f7 100644 --- a/packages/jest-runtime/package.json +++ b/packages/jest-runtime/package.json @@ -24,7 +24,6 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-config": "^26.0.1", "jest-haste-map": "^26.0.1", "jest-message-util": "^26.0.1", "jest-mock": "^26.0.1", diff --git a/packages/jest-runtime/src/__mocks__/createRuntime.js b/packages/jest-runtime/src/__mocks__/createRuntime.js index 1512da0cb3eb..384ed8cd90b6 100644 --- a/packages/jest-runtime/src/__mocks__/createRuntime.js +++ b/packages/jest-runtime/src/__mocks__/createRuntime.js @@ -6,15 +6,71 @@ */ import path from 'path'; +import {tmpdir} from 'os'; +import {tryRealpath} from 'jest-util'; +import {makeProjectConfig} from '../../../../TestUtils'; + +// Copy from jest-config (since we don't want to depend on this package) +const getCacheDirectory = () => { + const {getuid} = process; + const tmpdirPath = path.join(tryRealpath(tmpdir()), 'jest'); + if (getuid == null) { + return tmpdirPath; + } else { + // On some platforms tmpdir() is `/tmp`, causing conflicts between different + // users and permission issues. Adding an additional subdivision by UID can + // help. + return `${tmpdirPath}_${getuid.call(process).toString(36)}`; + } +}; + +const setupModuleNameMapper = (config, rootDir) => { + if (config && config.moduleNameMapper) { + return Object.keys(config.moduleNameMapper).map(regex => { + const item = config.moduleNameMapper && config.moduleNameMapper[regex]; + return item && [regex, item.replace('', rootDir)]; + }); + } + return []; +}; + +const setupTransform = (config, rootDir) => { + if (config && config.transform) { + const transform = config.transform; + return Object.keys(transform).map(regex => [ + regex, + path.resolve(rootDir, transform[regex]), + ]); + } + return [ + [ + '^.+\\.[jt]sx?$', + path.resolve( + __dirname, + '..', + '..', + '..', + 'babel-jest', + 'build', + 'index.js', + ), + ], + ]; +}; module.exports = async function createRuntime(filename, config) { const NodeEnvironment = require('jest-environment-node'); const Runtime = require('../'); - const {normalize} = require('jest-config'); + const rootDir = path.resolve(path.dirname(filename), 'test_root'); - config = normalize( + const moduleNameMapper = setupModuleNameMapper(config, rootDir); + const transform = setupTransform(config, rootDir); + + config = makeProjectConfig( { + cacheDirectory: getCacheDirectory(), + cwd: path.resolve(__dirname, '..', '..', '..', '..'), haste: { hasteImplModulePath: path.resolve( __dirname, @@ -27,13 +83,21 @@ module.exports = async function createRuntime(filename, config) { 'haste_impl.js', ), }, + moduleDirectories: ['node_modules'], + moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node'], name: 'Runtime-' + filename.replace(/\W/, '-') + '.tests', - rootDir: path.resolve(path.dirname(filename), 'test_root'), + rootDir, ...config, + // eslint-disable-next-line sort-keys + moduleNameMapper, + transform, }, - {}, - ).options; + ); + + if (!config.roots.length) { + config.roots = [config.rootDir]; + } const environment = new NodeEnvironment(config); environment.global.console = console; diff --git a/packages/jest-runtime/src/__tests__/runtime_cli.test.js b/packages/jest-runtime/src/__tests__/runtime_cli.test.js deleted file mode 100644 index 2c78d9aa0b1a..000000000000 --- a/packages/jest-runtime/src/__tests__/runtime_cli.test.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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. - */ - -import path from 'path'; -// eslint-disable-next-line import/named -import {sync as spawnSync} from 'execa'; -import {skipSuiteOnWindows} from '@jest/test-utils'; - -skipSuiteOnWindows(); - -const JEST_RUNTIME = path.resolve(__dirname, '../../bin/jest-runtime.js'); - -const run = args => - spawnSync(JEST_RUNTIME, args, { - cwd: process.cwd(), - env: process.env, - reject: false, - }); - -describe('Runtime', () => { - describe('cli', () => { - it('fails with no path', () => { - const expectedOutput = - 'Please provide a path to a script. (See --help for details)'; - expect(run([]).stdout).toBe(expectedOutput); - }); - - it('displays script output', () => { - const scriptPath = path.resolve(__dirname, './test_root/logging.js'); - expect(run([scriptPath, '--no-cache']).stdout).toMatch('Hello, world!'); - }); - - it('always disables automocking', () => { - const scriptPath = path.resolve(__dirname, './test_root/logging.js'); - const output = run([ - scriptPath, - '--no-cache', - '--config=' + - JSON.stringify({ - automock: true, - }), - ]); - expect(output.stdout).toMatch('Hello, world!'); - }); - - it('throws script errors', () => { - const scriptPath = path.resolve(__dirname, './test_root/throwing.js'); - expect(run([scriptPath, '--no-cache']).stderr).toMatch('Error: throwing'); - }); - }); -}); diff --git a/packages/jest-runtime/src/cli/args.ts b/packages/jest-runtime/src/cli/args.ts deleted file mode 100644 index 34fa4144a640..000000000000 --- a/packages/jest-runtime/src/cli/args.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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. - */ - -import type {Options} from 'yargs'; - -export const usage = 'Usage: $0 [--config=] '; - -export const options: Record< - 'cache' | 'config' | 'debug' | 'version' | 'watchman', - Options -> = { - cache: { - default: true, - description: - 'Whether to use the preprocessor cache. Disable ' + - 'the cache using --no-cache.', - type: 'boolean', - }, - config: { - alias: 'c', - description: 'The path to a Jest config file.', - type: 'string', - }, - debug: { - description: 'Print debugging info about your jest config.', - type: 'boolean', - }, - version: { - alias: 'v', - description: 'Print the version and exit', - type: 'boolean', - }, - watchman: { - default: true, - description: - 'Whether to use watchman for file crawling. Disable using ' + - '--no-watchman.', - type: 'boolean', - }, -}; diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 2cfe0a14d10a..306ef859537b 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -43,8 +43,6 @@ import { import type {V8CoverageResult} from '@jest/test-result'; import {CoverageInstrumenter, V8Coverage} from 'collect-v8-coverage'; import * as fs from 'graceful-fs'; -import {run as cliRun} from './cli'; -import {options as cliOptions} from './cli/args'; import { createOutsideJestVmPath, decodePossibleOutsideJestVmPath, @@ -332,12 +330,12 @@ class Runtime { }); } - static runCLI(args?: Config.Argv, info?: Array): Promise { - return cliRun(args, info); + static async runCLI(): Promise { + throw new Error('The jest-runtime CLI has been moved into jest-repl'); } - static getCLIOptions(): typeof cliOptions { - return cliOptions; + static getCLIOptions(): never { + throw new Error('The jest-runtime CLI has been moved into jest-repl'); } // unstable as it should be replaced by https://github.com/nodejs/modules/issues/393, and we don't want people to use it diff --git a/packages/jest-runtime/tsconfig.json b/packages/jest-runtime/tsconfig.json index fb40160ffc2b..b52d4b35ec8a 100644 --- a/packages/jest-runtime/tsconfig.json +++ b/packages/jest-runtime/tsconfig.json @@ -5,7 +5,6 @@ "outDir": "build" }, "references": [ - {"path": "../jest-config"}, {"path": "../jest-console"}, {"path": "../jest-environment"}, {"path": "../jest-environment-node"},