Skip to content

Commit

Permalink
Add good test for watcher ✅
Browse files Browse the repository at this point in the history
  • Loading branch information
Connormiha committed Jul 11, 2019
1 parent b4b7bc2 commit 5192931
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 69 deletions.
179 changes: 179 additions & 0 deletions 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));
}
}
64 changes: 0 additions & 64 deletions packages/jest-core/src/__tests__/watch.test.js
Expand Up @@ -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`;
Expand Down Expand Up @@ -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: [],
Expand Down Expand Up @@ -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`;

Expand Down
2 changes: 1 addition & 1 deletion packages/jest-core/src/watch.ts
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-resolve/src/defaultResolver.ts
Expand Up @@ -44,7 +44,7 @@ export default function defaultResolver(
});
}

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

Expand Down
6 changes: 3 additions & 3 deletions 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, {clearResolverCache} from './defaultResolver';
import defaultResolver, {clearDefaultResolverCache} from './defaultResolver';
import {ResolverConfig} from './types';

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

static clearCache() {
clearResolverCache();
static clearDefaultResolverCache() {
clearDefaultResolverCache();
}

static findNodeModule(
Expand Down

0 comments on commit 5192931

Please sign in to comment.