Skip to content

Commit

Permalink
Clear resolved modules cache before runJest in watch mode (#8650)
Browse files Browse the repository at this point in the history
  • Loading branch information
Connormiha authored and SimenB committed Jul 14, 2019
1 parent b76f01b commit e0d9b50
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 3 deletions.
2 changes: 1 addition & 1 deletion e2e/__tests__/__snapshots__/moduleNameMapper.test.ts.snap
Expand Up @@ -30,6 +30,6 @@ FAIL __tests__/index.js
12 | module.exports = () => 'test';
13 |
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:472:17)
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:501:17)
at Object.require (index.js:10:1)
`;
Expand Up @@ -33,6 +33,6 @@ FAIL __tests__/test.js
| ^
4 |
at Resolver.resolveModule (../../packages/jest-resolve/build/index.js:230:17)
at Resolver.resolveModule (../../packages/jest-resolve/build/index.js:259:17)
at Object.require (index.js:3:18)
`;
1 change: 1 addition & 0 deletions packages/jest-core/package.json
Expand Up @@ -19,6 +19,7 @@
"jest-haste-map": "^24.8.0",
"jest-message-util": "^24.8.0",
"jest-regex-util": "^24.3.0",
"jest-resolve": "^24.8.0",
"jest-resolve-dependencies": "^24.8.0",
"jest-runner": "^24.8.0",
"jest-runtime": "^24.8.0",
Expand Down
187 changes: 187 additions & 0 deletions packages/jest-core/src/__tests__/watch-file-changes.test.ts
@@ -0,0 +1,187 @@
/**
* 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 path from 'path';
import fs from 'fs';
import os from 'os';
import {JestHook} from 'jest-watcher';
import Runtime from 'jest-runtime';
import {normalize} from 'jest-config';
import HasteMap from 'jest-haste-map';
import rimraf from 'rimraf';
import {AggregatedResult} from '@jest/test-result';

describe('Watch mode flows with changed files', () => {
jest.resetModules();

let watch: any;
let pipe: NodeJS.ReadStream;
let stdin: MockStdin;
const testDirectory = path.resolve(os.tmpdir(), 'jest-tmp');
const fileTargetPath = path.resolve(testDirectory, 'lost-file.js');
const fileTargetPath2 = path.resolve(
testDirectory,
'watch-test-fake.test.js',
);
const cacheDirectory = path.resolve(os.tmpdir(), `tmp${Math.random()}`);
let hasteMapInstance: HasteMap;

beforeEach(() => {
watch = require('../watch').default;
pipe = {write: jest.fn()} as any;
stdin = new MockStdin();
rimraf.sync(cacheDirectory);
rimraf.sync(testDirectory);
fs.mkdirSync(testDirectory);
fs.mkdirSync(cacheDirectory);
});

afterEach(() => {
jest.resetModules();
if (hasteMapInstance) {
hasteMapInstance.end();
}
rimraf.sync(cacheDirectory);
rimraf.sync(testDirectory);
});

it('should correct require new files without legacy cache', async () => {
fs.writeFileSync(
fileTargetPath2,
`
require('./lost-file.js');
describe('Fake test', () => {
it('Hey', () => {
});
});
`,
);

const config = normalize(
{
cache: false,
cacheDirectory,
coverageReporters: [],
maxConcurrency: 1,
maxWorkers: 1,
moduleDirectories: ['node_modules'],
onlyChanged: false,
reporters: [],
rootDir: testDirectory,
silent: true,
testRegex: ['watch-test-fake\\.test\\.js$'],
watch: false,
watchman: false,
},
{} as any,
).options;

hasteMapInstance = await Runtime.createHasteMap(config, {
maxWorkers: 1,
resetCache: true,
watch: true,
watchman: false,
});

const realContext = await hasteMapInstance.build().then(hasteMap => ({
config,
hasteFS: hasteMap.hasteFS,
moduleMap: hasteMap.moduleMap,
resolver: Runtime.createResolver(config, hasteMap.moduleMap),
}));

const hook = new JestHook();
const firstErrorPromise = new Promise(resolve => {
hook.getSubscriber().onTestRunComplete(resolve);
});
await watch(
{
...config,
watchPlugins: [],
},
[realContext],
pipe,
[hasteMapInstance],
stdin,
hook,
);

await firstErrorPromise;

const successPromise = new Promise<AggregatedResult>(resolve => {
hook.getSubscriber().onTestRunComplete(resolve);
});

// Create lost file
fs.writeFileSync(
fileTargetPath,
`
describe('Fake group', () => {
it('Fake 1', () => {});
it('Fake 2', () => {});
it('Fake 3', () => {});
});
`,
);

const resultSuccessReport = await successPromise;

expect(resultSuccessReport).toMatchObject({
numFailedTestSuites: 0,
numFailedTests: 0,
numPassedTests: 4,
numRuntimeErrorTestSuites: 0,
success: true,
wasInterrupted: false,
});
expect(resultSuccessReport.testResults[0]).toMatchObject({
failureMessage: null,
});

const errorPromise = new Promise<AggregatedResult>(resolve => {
hook.getSubscriber().onTestRunComplete(resolve);
});

// Remove again to ensure about no legacy cache
fs.unlinkSync(fileTargetPath);

const resultErrorReport = await errorPromise;

// After remove file we have to fail tests
expect(resultErrorReport).toMatchObject({
numFailedTestSuites: 1,
numPassedTests: 0,
numRuntimeErrorTestSuites: 1,
success: false,
wasInterrupted: false,
});
});
});

class MockStdin {
private _callbacks: Array<any>;

constructor() {
this._callbacks = [];
}

resume() {}

setEncoding() {}

on(_: any, callback: any) {
this._callbacks.push(callback);
}

emit(key: string) {
this._callbacks.forEach(cb => cb(key));
}
}
4 changes: 4 additions & 0 deletions packages/jest-core/src/watch.ts
Expand Up @@ -15,6 +15,7 @@ import {formatExecError} from 'jest-message-util';
import {isInteractive, preRunMessage, specialChars} from 'jest-util';
import {ValidationError} from 'jest-validate';
import {Context} from 'jest-runtime';
import Resolver from 'jest-resolve';
import {Config} from '@jest/types';
import {
AllowedConfigOptions,
Expand Down Expand Up @@ -275,6 +276,9 @@ export default function watch(
isRunning = true;
const configs = contexts.map(context => context.config);
const changedFilesPromise = getChangedFilesPromise(globalConfig, configs);
// Clear cache for required modules
Resolver.clearDefaultResolverCache();

return runJest({
changedFilesPromise,
contexts,
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-resolve/src/defaultResolver.ts
Expand Up @@ -44,6 +44,10 @@ export default function defaultResolver(
});
}

export const clearDefaultResolverCache = () => {
checkedPaths.clear();
};

const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/;

function resolveSync(
Expand Down
6 changes: 5 additions & 1 deletion packages/jest-resolve/src/index.ts
Expand Up @@ -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 from './defaultResolver';
import defaultResolver, {clearDefaultResolverCache} from './defaultResolver';
import {ResolverConfig} from './types';

type FindNodeModuleConfig = {
Expand Down Expand Up @@ -79,6 +79,10 @@ class Resolver {
this._modulePathCache = new Map();
}

static clearDefaultResolverCache() {
clearDefaultResolverCache();
}

static findNodeModule(
path: Config.Path,
options: FindNodeModuleConfig,
Expand Down

0 comments on commit e0d9b50

Please sign in to comment.