From 3ab9f2a731fa2debec7f5cb915a180789a25cb4e Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Wed, 12 Jul 2017 16:06:14 -0700 Subject: [PATCH] global_config.js for multi-project runner --- .../multi_project_runner.test.js.snap | 38 ++++++++ .../__tests__/multi_project_runner.test.js | 89 +++++++++++++++++++ packages/jest-cli/src/cli/index.js | 2 +- packages/jest-config/src/index.js | 27 +++--- 4 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 integration_tests/__tests__/__snapshots__/multi_project_runner.test.js.snap create mode 100644 integration_tests/__tests__/multi_project_runner.test.js diff --git a/integration_tests/__tests__/__snapshots__/multi_project_runner.test.js.snap b/integration_tests/__tests__/__snapshots__/multi_project_runner.test.js.snap new file mode 100644 index 000000000000..e843354d2ac5 --- /dev/null +++ b/integration_tests/__tests__/__snapshots__/multi_project_runner.test.js.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`can pass projects or global config 1`] = ` +"Test Suites: 2 failed, 2 total +Tests: 0 total +Snapshots: 0 total +Time: <> +Ran all test suites. +" +`; + +exports[`can pass projects or global config 2`] = ` +"Test Suites: 2 passed, 2 total +Tests: 2 passed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites in 2 projects. +" +`; + +exports[`can pass projects or global config 3`] = ` +"PASS project1/__tests__/file1.test.js +PASS project2/__tests__/file1.test.js" +`; + +exports[`can pass projects or global config 4`] = ` +"Test Suites: 2 passed, 2 total +Tests: 2 passed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites in 2 projects. +" +`; + +exports[`can pass projects or global config 5`] = ` +"PASS project1/__tests__/file1.test.js +PASS project2/__tests__/file1.test.js" +`; diff --git a/integration_tests/__tests__/multi_project_runner.test.js b/integration_tests/__tests__/multi_project_runner.test.js new file mode 100644 index 000000000000..487a324059ac --- /dev/null +++ b/integration_tests/__tests__/multi_project_runner.test.js @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +'use strict'; + +import runJest from '../runJest'; +import {cleanup, extractSummary, writeFiles} from '../utils'; +import os from 'os'; +import path from 'path'; + +const skipOnWindows = require('skipOnWindows'); +const DIR = path.resolve(os.tmpdir(), 'multi_project_runner_test'); + +skipOnWindows.suite(); + +const fileContentWithProvidesModule = name => `/* + * @providesModule ${name} + */ + +module.exports = {}; +`; + +beforeEach(() => cleanup(DIR)); +afterEach(() => cleanup(DIR)); + +// Since Jest does not guarantee the order of tests we'll sort the output. +const sortLines = output => + output + .split(/\n/) + .sort() + .map(str => str.trim()) + .filter(str => Boolean(str)) + .join('\n'); + +test('can pass projects or global config', () => { + writeFiles(DIR, { + '.watchmanconfig': '', + 'package.json': '{}', + 'project1/__tests__/file1.test.js': ` + const file1 = require('file1'); + test('file1', () => {}); + `, + 'project1/file1.js': fileContentWithProvidesModule('file1'), + 'project1/jest.config.js': `module.exports = {rootDir: './'}`, + 'project2/__tests__/file1.test.js': ` + const file1 = require('file1'); + test('file1', () => {}); + `, + 'project2/file1.js': fileContentWithProvidesModule('file1'), + 'project2/jest.config.js': `module.exports = {rootDir: './'}`, + }); + let stderr; + + ({stderr} = runJest(DIR)); + expect(stderr).toMatch( + 'The name `file1` was looked up in the Haste module map. It cannot be resolved, because there exists several different files', + ); + + expect(extractSummary(stderr).summary).toMatchSnapshot(); + + writeFiles(DIR, { + 'global_config.js': ` + module.exports = { + projects: ['project1/', 'project2/'], + }; + `, + }); + + ({stderr} = runJest(DIR, ['-i', '--projects', 'project1', 'project2'])); + + const result1 = extractSummary(stderr); + expect(result1.summary).toMatchSnapshot(); + expect(sortLines(result1.rest)).toMatchSnapshot(); + + ({stderr} = runJest(DIR, ['-i', '--config', 'global_config.js'])); + const result2 = extractSummary(stderr); + + expect(result2.summary).toMatchSnapshot(); + expect(sortLines(result2.rest)).toMatchSnapshot(); + + // make sure different ways of passing projects work exactly the same + expect(result1.summary).toBe(result2.summary); + expect(sortLines(result1.rest)).toBe(sortLines(result2.rest)); +}); diff --git a/packages/jest-cli/src/cli/index.js b/packages/jest-cli/src/cli/index.js index 15c05a384be9..a73b08521b59 100644 --- a/packages/jest-cli/src/cli/index.js +++ b/packages/jest-cli/src/cli/index.js @@ -186,7 +186,7 @@ const _getConfigs = ( } if (projects.length > 1) { - const parsedConfigs = projects.map(root => readConfig(argv, root)); + const parsedConfigs = projects.map(root => readConfig(argv, root, true)); configs = parsedConfigs.map(({config}) => config); if (!hasDeprecationWarnings) { hasDeprecationWarnings = parsedConfigs.some( diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index 8576796dd801..7a17dad27edb 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -19,12 +19,17 @@ import normalize from './normalize'; function readConfig( argv: Argv, packageRoot: string, + // Whether it needs to look into `--config` arg passed to CLI. + // It only used to read initial config. If the initial config contains + // `project` property, we don't want to read `--config` value and rather + // read individual configs for every project. + skipArgvConfigOption?: boolean, ): { config: ProjectConfig, globalConfig: GlobalConfig, hasDeprecationWarnings: boolean, } { - const rawOptions = readOptions(argv, packageRoot); + const rawOptions = readOptions(argv, packageRoot, skipArgvConfigOption); const {options, hasDeprecationWarnings} = normalize(rawOptions, argv); const {globalConfig, projectConfig} = getConfigs(options); return { @@ -34,22 +39,22 @@ function readConfig( }; } -const parseConfig = argv => - isJSONString(argv.config) ? JSON.parse(argv.config) : argv.config; - -const readOptions = (argv, root) => { - const rawOptions = parseConfig(argv); - - if (typeof rawOptions === 'object') { - const config = Object.assign({}, rawOptions); +const readOptions = (argv, root, skipArgvConfigOption) => { + // A JSON string was passed to `--config` argument and we can parse it + // and use as is. + if (isJSONString(argv.config)) { + const config = JSON.parse(argv.config); config.rootDir = config.rootDir || root; return config; } - if (typeof rawOptions === 'string') { - root = path.resolve(process.cwd(), rawOptions); + // A string passed to `--config`, which is either a direct path to the config + // or a path to directory containing `package.json` or `jest.conf.js` + if (!skipArgvConfigOption && typeof argv.config == 'string') { + return findConfig(path.resolve(process.cwd(), argv.config)); } + // Otherwise just try to find config in the current rootDir. return findConfig(root); };