diff --git a/integration_tests/__tests__/only_changed.test.js b/integration_tests/__tests__/only_changed.test.js index e346e7310d0d..daebe051f461 100644 --- a/integration_tests/__tests__/only_changed.test.js +++ b/integration_tests/__tests__/only_changed.test.js @@ -16,6 +16,7 @@ import path from 'path'; const skipOnWindows = require('skipOnWindows'); const DIR = path.resolve(os.tmpdir(), 'jest_only_changed'); const GIT = 'git -c user.name=jest_test -c user.email=jest_test@test.com'; +const HG = 'hg --config ui.username=jest_test'; skipOnWindows.suite(); @@ -133,3 +134,53 @@ test('onlyChanged in config is overwritten by --all', () => { expect(stderr).toMatch('PASS __tests__/file2.test.js'); expect(stderr).toMatch('PASS __tests__/file3.test.js'); }); + +test('gets changed files for hg', async () => { + if (process.env.CI) { + // Circle and Travis have very old version of hg (v2, and current + // version is v4.2) and its API changed since then and not compatible + // any more. Changing the SCM version on CIs is not trivial, so we'll just + // skip this test and run it only locally. + return; + } + writeFiles(DIR, { + '.watchmanconfig': '', + '__tests__/file1.test.js': `require('../file1'); test('file1', () => {});`, + 'file1.js': 'module.exports = {}', + 'package.json': JSON.stringify({jest: {testEnvironment: 'node'}}), + }); + + run(`${HG} init`, DIR); + run(`${HG} add .`, DIR); + run(`${HG} commit -m "test"`, DIR); + + let stdout; + let stderr; + + ({stdout, stderr} = runJest(DIR, ['-o'])); + expect(stdout).toMatch('No tests found related to files changed'); + + writeFiles(DIR, { + '__tests__/file2.test.js': `require('../file2'); test('file2', () => {});`, + 'file2.js': 'module.exports = {}', + 'file3.js': `require('./file2')`, + }); + + ({stdout, stderr} = runJest(DIR, ['-o'])); + expect(stderr).toMatch('PASS __tests__/file2.test.js'); + + run(`${HG} add .`, DIR); + run(`${HG} commit -m "test2"`, DIR); + + writeFiles(DIR, { + '__tests__/file3.test.js': `require('../file3'); test('file3', () => {});`, + }); + + ({stdout, stderr} = runJest(DIR, ['-o'])); + expect(stderr).toMatch('PASS __tests__/file3.test.js'); + expect(stderr).not.toMatch('PASS __tests__/file2.test.js'); + + ({stdout, stderr} = runJest(DIR, ['-o', '--changedFilesWithAncestor'])); + expect(stderr).toMatch('PASS __tests__/file2.test.js'); + expect(stderr).toMatch('PASS __tests__/file3.test.js'); +}); diff --git a/packages/jest-changed-files/src/git.js b/packages/jest-changed-files/src/git.js index f725bf5881cd..2069be26d805 100644 --- a/packages/jest-changed-files/src/git.js +++ b/packages/jest-changed-files/src/git.js @@ -19,6 +19,11 @@ const adapter: SCMAdapter = { cwd: string, options?: Options, ): Promise> => { + if (options && options.withAncestor) { + throw new Error( + '`changedFilesWithAncestor` is not supported in git repos', + ); + } return new Promise((resolve, reject) => { const args = options && options.lastCommit diff --git a/packages/jest-changed-files/src/hg.js b/packages/jest-changed-files/src/hg.js index 767e03eb3053..a33275f596c7 100644 --- a/packages/jest-changed-files/src/hg.js +++ b/packages/jest-changed-files/src/hg.js @@ -35,7 +35,7 @@ const adapter: SCMAdapter = { let stderr = ''; child.stdout.on('data', data => (stdout += data)); child.stderr.on('data', data => (stderr += data)); - child.on('error', e => reject(e)); + child.on('error', (error: Error) => reject(error)); child.on('close', code => { if (code === 0) { stdout = stdout.trim(); @@ -49,7 +49,7 @@ const adapter: SCMAdapter = { ); } } else { - reject(code + ': ' + stderr); + reject(new Error(code + ': ' + stderr)); } }); }); diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 9c1c03312ade..ec99c48d9126 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -90,6 +90,13 @@ const options = { ' dependency information.', type: 'string', }, + changedFilesWithAncestor: { + description: + 'When used together with `--onlyChanged`, it runs tests ' + + 'related to the current changes and the changes made in the last commit. ' + + '(NOTE: this only works for hg repos)', + type: 'boolean', + }, ci: { default: isCI, description: diff --git a/packages/jest-cli/src/get_changed_files_promise.js b/packages/jest-cli/src/get_changed_files_promise.js index 896c0162aafa..0ab3b0b740d2 100644 --- a/packages/jest-cli/src/get_changed_files_promise.js +++ b/packages/jest-cli/src/get_changed_files_promise.js @@ -23,6 +23,7 @@ module.exports = ( ); return getChangedFilesForRoots(allRootsForAllProjects, { lastCommit: globalConfig.lastCommit, + withAncestor: globalConfig.changedFilesWithAncestor, }); } diff --git a/packages/jest-config/src/defaults.js b/packages/jest-config/src/defaults.js index 5e29c41fda12..f77cf2a05fb1 100644 --- a/packages/jest-config/src/defaults.js +++ b/packages/jest-config/src/defaults.js @@ -34,6 +34,7 @@ module.exports = ({ browser: false, cache: true, cacheDirectory, + changedFilesWithAncestor: false, clearMocks: false, coveragePathIgnorePatterns: [NODE_MODULES_REGEXP], coverageReporters: ['json', 'text', 'lcov', 'clover'], diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index efcd6c7d8665..ed3c6e94cb12 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -64,6 +64,7 @@ const getConfigs = ( return { globalConfig: Object.freeze({ bail: options.bail, + changedFilesWithAncestor: options.changedFilesWithAncestor, collectCoverage: options.collectCoverage, collectCoverageFrom: options.collectCoverageFrom, collectCoverageOnlyFrom: options.collectCoverageOnlyFrom, diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 8f0084fd1090..a69791aaa441 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -448,6 +448,7 @@ function normalize(options: InitialOptions, argv: Argv) { case 'bail': case 'browser': case 'cache': + case 'changedFilesWithAncestor': case 'clearMocks': case 'collectCoverage': case 'coverageReporters': diff --git a/packages/jest-config/src/valid_config.js b/packages/jest-config/src/valid_config.js index 060f918438ab..3556cd38e82d 100644 --- a/packages/jest-config/src/valid_config.js +++ b/packages/jest-config/src/valid_config.js @@ -21,6 +21,7 @@ module.exports = ({ browser: false, cache: true, cacheDirectory: '/tmp/user/jest', + changedFilesWithAncestor: false, clearMocks: false, collectCoverage: true, collectCoverageFrom: ['src', '!public'], diff --git a/types/Argv.js b/types/Argv.js index 25ae5c7a83b9..5cc931a42f48 100644 --- a/types/Argv.js +++ b/types/Argv.js @@ -18,6 +18,7 @@ export type Argv = {| browser: boolean, cache: boolean, cacheDirectory: string, + changedFilesWithAncestor: boolean, clearMocks: boolean, ci: boolean, collectCoverage: boolean, diff --git a/types/Config.js b/types/Config.js index c1f07060ef35..fcd64d1345d7 100644 --- a/types/Config.js +++ b/types/Config.js @@ -28,6 +28,7 @@ export type DefaultOptions = {| browser: boolean, cache: boolean, cacheDirectory: Path, + changedFilesWithAncestor: boolean, clearMocks: boolean, coveragePathIgnorePatterns: Array, coverageReporters: Array, @@ -66,6 +67,7 @@ export type InitialOptions = {| cache?: boolean, cacheDirectory?: Path, clearMocks?: boolean, + changedFilesWithAncestor?: boolean, collectCoverage?: boolean, collectCoverageFrom?: Array, collectCoverageOnlyFrom?: {[key: string]: boolean}, @@ -132,6 +134,7 @@ export type SnapshotUpdateState = 'all' | 'new' | 'none'; export type GlobalConfig = {| bail: boolean, + changedFilesWithAncestor: boolean, collectCoverage: boolean, collectCoverageFrom: Array, collectCoverageOnlyFrom: ?{[key: string]: boolean},