diff --git a/packages/jest-core/src/__tests__/watch-file-changes.test.js b/packages/jest-core/src/__tests__/watch-file-changes.test.js new file mode 100644 index 000000000000..fc5f242e83c1 --- /dev/null +++ b/packages/jest-core/src/__tests__/watch-file-changes.test.js @@ -0,0 +1,179 @@ +/** + * 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'; + +import {JestHook} from 'jest-watcher'; +import Runtime from 'jest-runtime'; +import {normalize} from 'jest-config'; +import path from 'path'; +import fs from 'fs'; + +describe('Watch mode flows with changed files', () => { + let watch; + let pipe; + let stdin; + const fileTargetPath = `${__dirname}/__fixtures__/hey.js`; + const fileTargetPath2 = `${__dirname}/__fixtures__/heyhey.test.js`; + const cacheDirectory = `${__dirname}/tmp${Math.random()}`; + let hasteMapInstance; + const deleteFolderRecursive = pathname => { + if (fs.existsSync(pathname)) { + fs.readdirSync(pathname).forEach((file, index) => { + const curPath = path.resolve(pathname, file); + if (fs.lstatSync(curPath).isDirectory()) { + // recurse + deleteFolderRecursive(curPath); + } else { + // delete file + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(pathname); + } + }; + + beforeEach(() => { + watch = require('../watch').default; + pipe = {write: jest.fn()}; + stdin = new MockStdin(); + }); + + afterEach(() => { + jest.resetModules(); + hasteMapInstance.end(); + [fileTargetPath2, fileTargetPath].forEach(file => { + try { + fs.unlinkSync(file); + } catch (e) {} + }); + deleteFolderRecursive(cacheDirectory); + }); + + it('should correct require new files without legacy cache', async () => { + fs.writeFileSync( + fileTargetPath2, + ` + require('${fileTargetPath}'); + describe('Fake test', () => { + it('Hey', () => { + + }); + }); + `, + { + encoding: 'utf-8', + }, + ); + + fs.mkdirSync(cacheDirectory); + const config = normalize( + { + automock: false, + cache: false, + cacheDirectory, + coverageReporters: [], + maxConcurrency: 1, + maxWorkers: 1, + moduleDirectories: ['node_modules'], + moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json'], + modulePathIgnorePatterns: [], + onlyChanged: false, + reporters: [], + rootDir: __dirname, + roots: [__dirname], + testPathIgnorePatterns: ['/node_modules/'], + testRegex: ['hey\\.test\\.js$'], + watch: false, + watchman: false, + }, + [], + ).options; + + hasteMapInstance = await Runtime.createHasteMap(config, { + maxWorkers: 1, + resetCache: true, + retainAllFiles: true, + watch: true, + watchman: true, + }); + + const realContext = await hasteMapInstance.build().then( + hasteMap => ({ + config, + hasteFS: hasteMap.hasteFS, + moduleMap: hasteMap.moduleMap, + resolver: Runtime.createResolver(config, hasteMap.moduleMap), + }), + error => { + throw error; + }, + ); + + const hook = new JestHook(); + await watch( + { + ...config, + watchPlugins: [], + }, + [realContext], + pipe, + [hasteMapInstance], + stdin, + hook, + ); + + await new Promise(resolve => setTimeout(resolve, 300)); + + fs.writeFileSync( + fileTargetPath, + ` + describe('Fake group', () => { + it('Fake 1', () => {}); + it('Fake 2', () => {}); + it('Fake 3', () => {}); + }); + `, + {encoding: 'utf-8'}, + ); + + const resultReport = await new Promise(resolve => { + hook.getSubscriber().onTestRunComplete(result => { + resolve({ + numFailedTests: result.numFailedTests, + numPassedTests: result.numPassedTests, + }); + }); + }); + + expect(resultReport).toEqual({ + numFailedTests: 0, + numPassedTests: 4, + }); + }); +}); + +class MockStdin { + constructor() { + this._callbacks = []; + } + + setRawMode() {} + + resume() {} + + setEncoding() {} + + on(evt, callback) { + this._callbacks.push(callback); + } + + emit(key) { + this._callbacks.forEach(cb => cb(key)); + } +} diff --git a/packages/jest-core/src/__tests__/watch.test.js b/packages/jest-core/src/__tests__/watch.test.js index 290490f79b1e..358446807c64 100644 --- a/packages/jest-core/src/__tests__/watch.test.js +++ b/packages/jest-core/src/__tests__/watch.test.js @@ -11,8 +11,6 @@ import chalk from 'chalk'; import TestWatcher from '../TestWatcher'; import {JestHook, KEYS} from 'jest-watcher'; -import HasteMap from 'jest-haste-map'; -import fs from 'fs'; const runJestMock = jest.fn(); const watchPluginPath = `${__dirname}/__fixtures__/watch_plugin`; @@ -111,10 +109,6 @@ describe('Watch mode flows', () => { jest.doMock('jest-util/build/isInteractive', () => isInteractive); watch = require('../watch').default; const config = { - haste: { - defaultPlatform: 'android', - }, - moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json'], rootDir: __dirname, roots: [], testPathIgnorePatterns: [], @@ -582,64 +576,6 @@ describe('Watch mode flows', () => { }); }); - describe('check clear cache modules', () => { - const fileTargetPath = `${__dirname}/__fixtures__/hey.test.js`; - let hasteMapInstance; - let Resolver; - let originalClearCache; - - beforeEach(() => { - Resolver = require('jest-resolve'); - originalClearCache = Resolver.clearCache; - }); - - afterEach(() => { - Resolver.clearCache = originalClearCache; - hasteMapInstance.end(); - try { - fs.unlinkSync(fileTargetPath); - } catch (e) {} - }); - - it('should correct require new files without legacy cache', async () => { - hasteMapInstance = new HasteMap({ - computeSha1: false, - extensions: ['js'], - forceNodeFilesystemAPI: false, - maxWorkers: 2, - name: 'tmp_' + Date.now(), - platforms: [], - retainAllFiles: true, - rootDir: __dirname, - roots: [__dirname], - throwOnModuleCollision: true, - useWatchman: true, - watch: true, - }); - - await hasteMapInstance.build(); - - await watch( - { - ...globalConfig, - rootDir: __dirname, - watchPlugins: [], - }, - contexts, - pipe, - [hasteMapInstance], - stdin, - ); - - Resolver.clearCache = jest.fn(); - - fs.writeFileSync(fileTargetPath, '', {encoding: 'utf-8'}); - - await new Promise(resolve => setTimeout(resolve, 100)); - expect(Resolver.clearCache).toHaveBeenCalledTimes(1); - }); - }); - it('makes watch plugin initialization errors look nice', async () => { const pluginPath = `${__dirname}/__fixtures__/watch_plugin_throws`; diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 3cbf0444d86c..483983a34aa0 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -277,7 +277,7 @@ export default function watch( const configs = contexts.map(context => context.config); const changedFilesPromise = getChangedFilesPromise(globalConfig, configs); // Clear cache for required modules - Resolver.clearCache(); + Resolver.clearDefaultResolverCache(); return runJest({ changedFilesPromise, diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index 40e7949b12e4..8422ebcfc519 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -44,7 +44,7 @@ export default function defaultResolver( }); } -export const clearResolverCache = () => { +export const clearDefaultResolverCache = () => { checkedPaths.clear(); }; diff --git a/packages/jest-resolve/src/index.ts b/packages/jest-resolve/src/index.ts index b607ed8db450..9e21e5faa806 100644 --- a/packages/jest-resolve/src/index.ts +++ b/packages/jest-resolve/src/index.ts @@ -12,7 +12,7 @@ import {sync as realpath} from 'realpath-native'; import chalk from 'chalk'; import nodeModulesPaths from './nodeModulesPaths'; import isBuiltinModule from './isBuiltinModule'; -import defaultResolver, {clearResolverCache} from './defaultResolver'; +import defaultResolver, {clearDefaultResolverCache} from './defaultResolver'; import {ResolverConfig} from './types'; type FindNodeModuleConfig = { @@ -79,8 +79,8 @@ class Resolver { this._modulePathCache = new Map(); } - static clearCache() { - clearResolverCache(); + static clearDefaultResolverCache() { + clearDefaultResolverCache(); } static findNodeModule(