Skip to content

Commit d8dafce

Browse files
committed
Ensure glob patterns can be relative to the project directory
1 parent 55ab2c1 commit d8dafce

File tree

3 files changed

+168
-28
lines changed

3 files changed

+168
-28
lines changed

lib/globs.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ async function findTests({cwd, extensions, testPatterns, helperPatterns}) {
162162
continue;
163163
}
164164

165-
if (rejectHelpers && matches(file, helperPatterns)) {
165+
if (rejectHelpers && matches(normalizeFileForMatching(cwd, file), helperPatterns)) {
166166
continue;
167167
}
168168

@@ -223,11 +223,34 @@ const matches = (file, patterns) => {
223223

224224
const NOT_IGNORED = ['**/*'];
225225

226-
function classify(file, {extensions, helperPatterns, testPatterns, sourcePatterns}) {
226+
const normalizeFileForMatching = (cwd, file) => {
227+
if (process.platform === 'win32') {
228+
cwd = slash(cwd);
229+
file = slash(file);
230+
}
231+
232+
if (!cwd) { // TODO: Ensure tests provide an actual value.
233+
return file;
234+
}
235+
236+
// TODO: If `file` is outside `cwd` we can't normalize it. Need to figure
237+
// out if that's a real-world scenario, but we may have to ensure the file
238+
// isn't even selected.
239+
if (!file.startsWith(cwd)) {
240+
return file;
241+
}
242+
243+
// Assume `cwd` does *not* end in a slash.
244+
return file.slice(cwd.length + 1);
245+
};
246+
247+
function classify(file, {cwd, extensions, helperPatterns, testPatterns, sourcePatterns}) {
227248
let isHelper = false;
228249
let isTest = false;
229250
let isSource = false;
230251

252+
file = normalizeFileForMatching(cwd, file);
253+
231254
if (hasExtension(extensions, file)) {
232255
if (path.basename(file).startsWith('_')) {
233256
isHelper = matches(file, NOT_IGNORED);

test/globs.js

Lines changed: 142 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@ test('ignores relativeness in patterns', t => {
2323
});
2424

2525
test('isTest', t => {
26-
const options = globs.normalizeGlobs(
27-
['**/foo*.js', '**/foo*/**/*.js', '!**/fixtures', '!**/helpers'],
28-
undefined,
29-
undefined,
30-
['js']
31-
);
26+
const options = {
27+
...globs.normalizeGlobs(
28+
['**/foo*.js', '**/foo*/**/*.js', '!**/fixtures', '!**/helpers'],
29+
undefined,
30+
undefined,
31+
['js']
32+
),
33+
cwd: fixture()
34+
};
3235

3336
function isTest(file) {
3437
t.true(globs.classify(fixture(file), options).isTest, `${file} should be a test`);
@@ -55,15 +58,54 @@ test('isTest', t => {
5558
t.end();
5659
});
5760

61+
test('isTest (pattern starts with directory)', t => {
62+
const options = {
63+
...globs.normalizeGlobs(
64+
['bar/**/*'],
65+
undefined,
66+
undefined,
67+
['js']
68+
),
69+
cwd: fixture()
70+
};
71+
72+
function isTest(file) {
73+
t.true(globs.classify(fixture(file), options).isTest, `${file} should be a test`);
74+
}
75+
76+
function notTest(file) {
77+
t.false(globs.classify(fixture(file), options).isTest, `${file} should not be a test`);
78+
}
79+
80+
notTest('foo-bar.js');
81+
notTest('foo.js');
82+
notTest('foo/blah.js');
83+
isTest('bar/foo.js');
84+
isTest('bar/foo-bar/baz/buz.js');
85+
isTest('bar/baz/buz.js');
86+
notTest('bar.js');
87+
isTest('bar/bar.js');
88+
notTest('bar/_foo-bar.js');
89+
notTest('foo/_foo-bar.js');
90+
notTest('foo-bar.txt');
91+
notTest('node_modules/foo.js');
92+
notTest('fixtures/foo.js');
93+
notTest('helpers/foo.js');
94+
t.end();
95+
});
96+
5897
test('isSource with defaults', t => {
59-
const options = globs.normalizeGlobs(undefined, undefined, undefined, ['js']);
98+
const options = {
99+
...globs.normalizeGlobs(undefined, undefined, undefined, ['js']),
100+
cwd: fixture()
101+
};
60102

61103
function isSource(file) {
62-
t.true(globs.classify(file, options).isSource, `${file} should be a source`);
104+
t.true(globs.classify(fixture(file), options).isSource, `${file} should be a source`);
63105
}
64106

65107
function notSource(file) {
66-
t.false(globs.classify(file, options).isSource, `${file} should not be a source`);
108+
t.false(globs.classify(fixture(file), options).isSource, `${file} should not be a source`);
67109
}
68110

69111
isSource('foo-bar.js');
@@ -91,28 +133,51 @@ test('isSource with defaults', t => {
91133
});
92134

93135
test('isSource with negation negation patterns', t => {
94-
const options = globs.normalizeGlobs(
95-
['**/foo*'],
96-
undefined,
97-
['!**/bar*'],
98-
['js']
99-
);
100-
101-
t.false(globs.classify('node_modules/foo/foo.js', options).isSource);
102-
t.false(globs.classify('bar.js', options).isSource);
103-
t.false(globs.classify('foo/bar.js', options).isSource);
136+
const options = {
137+
...globs.normalizeGlobs(
138+
['**/foo*'],
139+
undefined,
140+
['!**/bar*'],
141+
['js']
142+
),
143+
cwd: fixture()
144+
};
145+
146+
t.false(globs.classify(fixture('node_modules/foo/foo.js'), options).isSource);
147+
t.false(globs.classify(fixture('bar.js'), options).isSource);
148+
t.false(globs.classify(fixture('foo/bar.js'), options).isSource);
149+
t.end();
150+
});
151+
152+
test('isSource (pattern starts with directory)', t => {
153+
const options = {
154+
...globs.normalizeGlobs(
155+
['**/foo*'],
156+
undefined,
157+
['foo/**/*'],
158+
['js']
159+
),
160+
cwd: fixture()
161+
};
162+
163+
t.false(globs.classify(fixture('node_modules/foo/foo.js'), options).isSource);
164+
t.false(globs.classify(fixture('bar.js'), options).isSource);
165+
t.true(globs.classify(fixture('foo/bar.js'), options).isSource);
104166
t.end();
105167
});
106168

107169
test('isHelper (prefixed only)', t => {
108-
const options = globs.normalizeGlobs(undefined, undefined, undefined, ['js']);
170+
const options = {
171+
...globs.normalizeGlobs(undefined, undefined, undefined, ['js']),
172+
cwd: fixture()
173+
};
109174

110175
function isHelper(file) {
111-
t.true(globs.classify(file, options).isHelper, `${file} should be a helper`);
176+
t.true(globs.classify(fixture(file), options).isHelper, `${file} should be a helper`);
112177
}
113178

114179
function notHelper(file) {
115-
t.false(globs.classify(file, options).isHelper, `${file} should not be a helper`);
180+
t.false(globs.classify(fixture(file), options).isHelper, `${file} should not be a helper`);
116181
}
117182

118183
notHelper('foo.js');
@@ -133,14 +198,17 @@ test('isHelper (prefixed only)', t => {
133198
});
134199

135200
test('isHelper (with patterns)', t => {
136-
const options = globs.normalizeGlobs(undefined, ['**/f*.*'], undefined, ['js']);
201+
const options = {
202+
...globs.normalizeGlobs(undefined, ['**/f*.*'], undefined, ['js']),
203+
cwd: fixture()
204+
};
137205

138206
function isHelper(file) {
139-
t.true(globs.classify(file, options).isHelper, `${file} should be a helper`);
207+
t.true(globs.classify(fixture(file), options).isHelper, `${file} should be a helper`);
140208
}
141209

142210
function notHelper(file) {
143-
t.false(globs.classify(file, options).isHelper, `${file} should not be a helper`);
211+
t.false(globs.classify(fixture(file), options).isHelper, `${file} should not be a helper`);
144212
}
145213

146214
isHelper('foo.js');
@@ -160,6 +228,37 @@ test('isHelper (with patterns)', t => {
160228
t.end();
161229
});
162230

231+
test('isHelper (pattern stars with directory)', t => {
232+
const options = {
233+
...globs.normalizeGlobs(undefined, ['foo/**/*'], undefined, ['js']),
234+
cwd: fixture()
235+
};
236+
237+
function isHelper(file) {
238+
t.true(globs.classify(fixture(file), options).isHelper, `${file} should be a helper`);
239+
}
240+
241+
function notHelper(file) {
242+
t.false(globs.classify(fixture(file), options).isHelper, `${file} should not be a helper`);
243+
}
244+
245+
notHelper('foo.js');
246+
isHelper('foo/bar.js');
247+
notHelper('bar/foo.js');
248+
249+
isHelper('_foo.js');
250+
isHelper('foo/_foo.js');
251+
notHelper('fixtures/foo.js');
252+
notHelper('helpers/foo.js');
253+
254+
notHelper('snapshots/foo.js.snap');
255+
256+
notHelper('foo.json');
257+
notHelper('foo.coffee');
258+
notHelper('node_modules/foo.js');
259+
t.end();
260+
});
261+
163262
test('findHelpersAndTests finds tests (just .js)', async t => {
164263
const fixtureDir = fixture('default-patterns');
165264
process.chdir(fixtureDir);
@@ -276,3 +375,21 @@ test('findTests finds tests (.js, .jsx)', async t => {
276375
actual.sort();
277376
t.deepEqual(actual, expected);
278377
});
378+
379+
test('findTests excludes helpers', async t => {
380+
const fixtureDir = fixture('custom-extension');
381+
process.chdir(fixtureDir);
382+
383+
const expected = [
384+
'test/do-not-compile.js',
385+
'test/foo.jsx',
386+
'test/sub/bar.jsx'
387+
].sort().map(file => path.join(fixtureDir, file));
388+
389+
const {tests: actual} = await globs.findTests({
390+
cwd: fixtureDir,
391+
...globs.normalizeGlobs(['!**/fixtures/*'], ['test/helpers/**/*'], undefined, ['js', 'jsx'])
392+
});
393+
actual.sort();
394+
t.deepEqual(actual, expected);
395+
});

test/watcher.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ group('chokidar', (beforeEach, test, group) => {
145145
Subject = proxyWatcher();
146146
});
147147

148-
const start = (specificFiles, sources) => new Subject({reporter, api, files: specificFiles || [], globs: normalizeGlobs(files, undefined, sources, ['js'])});
148+
const start = (specificFiles, sources) => new Subject({reporter, api, files: specificFiles || [], globs: normalizeGlobs(files, undefined, sources, ['js']), resolveTestsFrom: ''});
149149

150150
const emitChokidar = (event, path) => {
151151
chokidarEmitter.emit('all', event, path);

0 commit comments

Comments
 (0)