Skip to content

Commit 43f5092

Browse files
committed
feat(jest-haste-map): Enable crawling for symlink test files
1 parent 9419034 commit 43f5092

File tree

5 files changed

+90
-8
lines changed

5 files changed

+90
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- `[jest-environment-node]` Implement `compileFunction` ([#9140](https://github.com/facebook/jest/pull/9140))
2727
- `[@jest/fake-timers]` Add Lolex as implementation of fake timers ([#8897](https://github.com/facebook/jest/pull/8897))
2828
- `[jest-get-type]` Add `BigInt` support. ([#8382](https://github.com/facebook/jest/pull/8382))
29+
- `[jest-haste-map]` Enable crawling for symlinked test files ([#9350](https://github.com/facebook/jest/issues/9350))
2930
- `[jest-matcher-utils]` Add `BigInt` support to `ensureNumbers` `ensureActualIsNumber`, `ensureExpectedIsNumber` ([#8382](https://github.com/facebook/jest/pull/8382))
3031
- `[jest-reporters]` Export utils for path formatting ([#9162](https://github.com/facebook/jest/pull/9162))
3132
- `[jest-runner]` Warn if a worker had to be force exited ([#8206](https://github.com/facebook/jest/pull/8206))

e2e/Utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,25 @@ export const writeFiles = (
9090
});
9191
};
9292

93+
export const writeSymlinks = (
94+
directory: string,
95+
symlinks: {[existingFile: string]: string},
96+
) => {
97+
createDirectory(directory);
98+
Object.keys(symlinks).forEach(fileOrPath => {
99+
const symLinkPath = symlinks[fileOrPath];
100+
const dirname = path.dirname(symLinkPath);
101+
102+
if (dirname !== '/') {
103+
createDirectory(path.join(directory, dirname));
104+
}
105+
fs.symlinkSync(
106+
path.resolve(directory, ...fileOrPath.split('/')),
107+
path.resolve(directory, ...symLinkPath.split('/')),
108+
);
109+
});
110+
};
111+
93112
const NUMBER_OF_TESTS_TO_FORCE_USING_WORKERS = 25;
94113
/**
95114
* Forces Jest to use workers by generating many test files to run.

e2e/__tests__/crawlSymlinks.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {tmpdir} from 'os';
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
import {writeFiles, writeSymlinks} from '../Utils';
5+
import runJest from '../runJest';
6+
const DIR = path.resolve(tmpdir(), 'crawl-symlinks-test');
7+
8+
test('Node crawler picks up symlinked files', () => {
9+
if (fs.existsSync(DIR)) {
10+
fs.rmdirSync(DIR, {recursive: true});
11+
}
12+
13+
writeFiles(DIR, {
14+
'package.json': `
15+
{
16+
"jest": {
17+
"testMatch": ["<rootDir>/test-files/test.js"]
18+
}
19+
}
20+
`,
21+
'symlinked-files/test.js': `
22+
test('1+1', () => {
23+
expect(1).toBe(1);
24+
});
25+
`,
26+
});
27+
28+
writeSymlinks(DIR, {
29+
'symlinked-files/test.js': 'test-files/test.js',
30+
});
31+
32+
const {stdout, stderr, exitCode} = runJest(DIR, ['--no-watchman']);
33+
expect(stderr).toContain('Test Suites: 1 passed, 1 total');
34+
expect(stdout).toEqual('');
35+
expect(exitCode).toEqual(0);
36+
});

packages/jest-haste-map/src/crawlers/__tests__/node.test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,13 @@ describe('node crawler', () => {
118118
expect(childProcess.spawn).lastCalledWith('find', [
119119
'/project/fruits',
120120
'/project/vegtables',
121+
'(',
121122
'-type',
122123
'f',
124+
'-o',
125+
'-type',
126+
'l',
127+
')',
123128
'(',
124129
'-iname',
125130
'*.js',

packages/jest-haste-map/src/crawlers/node.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,32 @@ function find(
4848
fs.lstat(file, (err, stat) => {
4949
activeCalls--;
5050

51-
if (!err && stat && !stat.isSymbolicLink()) {
52-
if (stat.isDirectory()) {
53-
search(file);
51+
if (!err && stat) {
52+
if (stat.isSymbolicLink()) {
53+
activeCalls++;
54+
fs.stat(file, (err, stat) => {
55+
activeCalls--;
56+
if (!err && stat) {
57+
if (stat.isFile()) {
58+
const ext = path.extname(file).substr(1);
59+
if (extensions.indexOf(ext) !== -1) {
60+
result.push([file, stat.mtime.getTime(), stat.size]);
61+
}
62+
}
63+
}
64+
65+
if (activeCalls === 0) {
66+
callback(result);
67+
}
68+
});
5469
} else {
55-
const ext = path.extname(file).substr(1);
56-
if (extensions.indexOf(ext) !== -1) {
57-
result.push([file, stat.mtime.getTime(), stat.size]);
70+
if (stat.isDirectory()) {
71+
search(file);
72+
} else {
73+
const ext = path.extname(file).substr(1);
74+
if (extensions.indexOf(ext) !== -1) {
75+
result.push([file, stat.mtime.getTime(), stat.size]);
76+
}
5877
}
5978
}
6079
}
@@ -84,7 +103,8 @@ function findNative(
84103
callback: Callback,
85104
): void {
86105
const args = Array.from(roots);
87-
args.push('-type', 'f');
106+
args.push('(', '-type', 'f', '-o', '-type', 'l', ')');
107+
88108
if (extensions.length) {
89109
args.push('(');
90110
}
@@ -121,7 +141,8 @@ function findNative(
121141
} else {
122142
lines.forEach(path => {
123143
fs.stat(path, (err, stat) => {
124-
if (!err && stat) {
144+
// Filter out symlinks that describe directories
145+
if (!err && stat && !stat.isDirectory()) {
125146
result.push([path, stat.mtime.getTime(), stat.size]);
126147
}
127148
if (--count === 0) {

0 commit comments

Comments
 (0)