diff --git a/e2e/__tests__/multiProjectRunner.test.ts b/e2e/__tests__/multiProjectRunner.test.ts index 77b2a374ccd0..ebb995a61f62 100644 --- a/e2e/__tests__/multiProjectRunner.test.ts +++ b/e2e/__tests__/multiProjectRunner.test.ts @@ -199,7 +199,57 @@ test.each([{projectPath: 'packages/somepackage'}, {projectPath: 'packages/*'}])( }); const {stdout, stderr, exitCode} = runJest(DIR, ['--no-watchman']); - expect(stderr).toContain('PASS packages/somepackage/test.js'); + expect(stderr).toContain('PASS somepackage packages/somepackage/test.js'); + expect(stderr).toContain('Test Suites: 1 passed, 1 total'); + expect(stdout).toEqual(''); + expect(exitCode).toEqual(0); + }, +); + +test.each([ + {displayName: 'p1', projectPath: 'packages/p1'}, + {displayName: 'p2', projectPath: 'packages/p2'}, +])( + 'correctly runs a single non-root project', + ({projectPath, displayName}: {projectPath: string; displayName: string}) => { + writeFiles(DIR, { + 'package.json': ` + { + "jest": { + "projects": [ + "${projectPath}" + ] + } + } + `, + 'packages/p1/package.json': ` + { + "jest": { + "displayName": "p1" + } + } + `, + 'packages/p1/test.js': ` + test('1+1', () => { + expect(1).toBe(1); + }); + `, + 'packages/p2/package.json': ` + { + "jest": { + "displayName": "p2" + } + } + `, + 'packages/p2/test.js': ` + test('1+1', () => { + expect(1).toBe(1); + }); + `, + }); + + const {stdout, stderr, exitCode} = runJest(DIR, ['--no-watchman']); + expect(stderr).toContain(`PASS ${displayName} ${projectPath}/test.js`); expect(stderr).toContain('Test Suites: 1 passed, 1 total'); expect(stdout).toEqual(''); expect(exitCode).toEqual(0); diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index fc796086e2a1..0df90f5d9c39 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -9,6 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; import {Config} from '@jest/types'; import chalk = require('chalk'); +import {sync as realpath} from 'realpath-native'; import {isJSONString, replaceRootDirInPath} from './utils'; import normalize from './normalize'; import resolveConfigPath from './resolveConfigPath'; @@ -278,26 +279,24 @@ export function readConfigs( const parsedConfig = readConfig(argv, projects[0]); configPath = parsedConfig.configPath; - if (parsedConfig.globalConfig.projects) { - // If this was a single project, and its config has `projects` - // settings, use that value instead. - projects = parsedConfig.globalConfig.projects; - } - hasDeprecationWarnings = parsedConfig.hasDeprecationWarnings; globalConfig = parsedConfig.globalConfig; configs = [parsedConfig.projectConfig]; if (globalConfig.projects && globalConfig.projects.length) { // Even though we had one project in CLI args, there might be more // projects defined in the config. + // In other words, if this was a single project, + // and its config has `projects` settings, use that value instead. projects = globalConfig.projects; } } - if ( - projects.length > 1 || - (projects.length && typeof projects[0] === 'object') - ) { + if (projects.length > 0) { + const projectIsCwd = + process.platform === 'win32' + ? projects[0] === realpath(process.cwd()) + : projects[0] === process.cwd(); + const parsedConfigs = projects .filter(root => { // Ignore globbed files that cannot be `require`d. @@ -313,9 +312,19 @@ export function readConfigs( return true; }) - .map((root, projectIndex) => - readConfig(argv, root, true, configPath, projectIndex), - ); + .map((root, projectIndex) => { + const projectIsTheOnlyProject = + projectIndex === 0 && projects.length === 1; + const skipArgvConfigOption = !(projectIsTheOnlyProject && projectIsCwd); + + return readConfig( + argv, + root, + skipArgvConfigOption, + configPath, + projectIndex, + ); + }); ensureNoDuplicateConfigs(parsedConfigs, projects); configs = parsedConfigs.map(({projectConfig}) => projectConfig);