Skip to content

Commit eedb92c

Browse files
committed
test: add ignore with /** suffix tests
1 parent d56dcfc commit eedb92c

1 file changed

Lines changed: 312 additions & 0 deletions

File tree

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2+
import { glob as nodeGlob } from 'glob';
3+
import { loadGloblin, createTestFixture, cleanupFixture, FixtureConfig } from '../harness';
4+
import * as path from 'path';
5+
6+
describe('ignore with /** suffix behavior', () => {
7+
let globlin: Awaited<ReturnType<typeof loadGloblin>>;
8+
let fixturePath: string;
9+
10+
beforeAll(async () => {
11+
globlin = await loadGloblin();
12+
13+
// Create a fixture with a typical node_modules-like structure
14+
const config: FixtureConfig = {
15+
files: [
16+
'src/index.ts',
17+
'src/utils.ts',
18+
'src/components/Button.tsx',
19+
'src/components/Input.tsx',
20+
'node_modules/lodash/index.js',
21+
'node_modules/lodash/package.json',
22+
'node_modules/lodash/dist/lodash.min.js',
23+
'node_modules/react/index.js',
24+
'node_modules/react/package.json',
25+
'node_modules/react/cjs/react.development.js',
26+
'dist/bundle.js',
27+
'dist/bundle.min.js',
28+
'tmp/cache/data.json',
29+
'tmp/logs/app.log',
30+
'package.json',
31+
'README.md',
32+
],
33+
};
34+
35+
fixturePath = await createTestFixture('ignore-globstar-suffix', config);
36+
});
37+
38+
afterAll(async () => {
39+
if (fixturePath) {
40+
await cleanupFixture(fixturePath);
41+
}
42+
});
43+
44+
describe('/** suffix vs exact match', () => {
45+
it('ignore "node_modules/**" excludes node_modules and all children', async () => {
46+
const results = await globlin.glob('**', {
47+
cwd: fixturePath,
48+
ignore: 'node_modules/**',
49+
});
50+
const sorted = results.sort();
51+
52+
// node_modules directory and all its children should be excluded
53+
expect(sorted.filter(r => r.includes('node_modules'))).toEqual([]);
54+
55+
// Other files should be present
56+
expect(sorted).toContain('src');
57+
expect(sorted).toContain('src/index.ts');
58+
expect(sorted).toContain('dist');
59+
expect(sorted).toContain('package.json');
60+
});
61+
62+
it('ignore "node_modules" only excludes exact match, not children', async () => {
63+
const results = await globlin.glob('**', {
64+
cwd: fixturePath,
65+
ignore: 'node_modules',
66+
});
67+
const sorted = results.sort();
68+
69+
// node_modules directory itself should be excluded
70+
expect(sorted).not.toContain('node_modules');
71+
72+
// But children of node_modules SHOULD still be present
73+
expect(sorted.filter(r => r.startsWith('node_modules/'))).toContain(
74+
'node_modules/lodash'
75+
);
76+
expect(sorted.filter(r => r.startsWith('node_modules/'))).toContain(
77+
'node_modules/lodash/index.js'
78+
);
79+
});
80+
81+
it('ignore "dist/**" excludes dist and all children', async () => {
82+
const results = await globlin.glob('**/*.js', {
83+
cwd: fixturePath,
84+
ignore: 'dist/**',
85+
});
86+
const sorted = results.sort();
87+
88+
// dist/ files should be excluded
89+
expect(sorted.filter(r => r.startsWith('dist/'))).toEqual([]);
90+
91+
// Other .js files should be present
92+
expect(sorted.some(r => r.includes('node_modules'))).toBe(true);
93+
});
94+
95+
it('ignore "dist" only excludes exact match', async () => {
96+
const results = await globlin.glob('**/*.js', {
97+
cwd: fixturePath,
98+
ignore: 'dist',
99+
});
100+
const sorted = results.sort();
101+
102+
// Files under dist should still be present (only "dist" itself is ignored)
103+
expect(sorted.filter(r => r.startsWith('dist/'))).toContain('dist/bundle.js');
104+
expect(sorted.filter(r => r.startsWith('dist/'))).toContain('dist/bundle.min.js');
105+
});
106+
});
107+
108+
describe('multiple ignores with /** suffix', () => {
109+
it('can ignore multiple directories with /** suffix', async () => {
110+
const results = await globlin.glob('**', {
111+
cwd: fixturePath,
112+
ignore: ['node_modules/**', 'dist/**', 'tmp/**'],
113+
});
114+
const sorted = results.sort();
115+
116+
// All ignored directories should be excluded
117+
expect(sorted.filter(r => r.includes('node_modules'))).toEqual([]);
118+
expect(sorted.filter(r => r.startsWith('dist'))).toEqual([]);
119+
expect(sorted.filter(r => r.startsWith('tmp'))).toEqual([]);
120+
121+
// Other files should be present
122+
expect(sorted).toContain('src');
123+
expect(sorted).toContain('src/index.ts');
124+
expect(sorted).toContain('package.json');
125+
});
126+
127+
it('mix of /** and exact match ignores', async () => {
128+
const results = await globlin.glob('**', {
129+
cwd: fixturePath,
130+
ignore: ['node_modules/**', 'dist'],
131+
});
132+
const sorted = results.sort();
133+
134+
// node_modules and children excluded
135+
expect(sorted.filter(r => r.includes('node_modules'))).toEqual([]);
136+
137+
// dist directory excluded but its children might be present
138+
expect(sorted).not.toContain('dist');
139+
// The directory itself is ignored but children may be found via **
140+
// Actually in glob behavior, children are still found
141+
});
142+
});
143+
144+
describe('nested patterns with /** suffix', () => {
145+
it('ignore "src/components/**" excludes only that subdirectory', async () => {
146+
const results = await globlin.glob('**/*.ts', {
147+
cwd: fixturePath,
148+
ignore: 'src/components/**',
149+
});
150+
const sorted = results.sort();
151+
152+
// src/components files should be excluded
153+
expect(sorted.filter(r => r.startsWith('src/components/'))).toEqual([]);
154+
155+
// Other src files should be present
156+
expect(sorted).toContain('src/index.ts');
157+
expect(sorted).toContain('src/utils.ts');
158+
});
159+
160+
it('ignore "**/lodash/**" excludes nested directory', async () => {
161+
const results = await globlin.glob('**/*.js', {
162+
cwd: fixturePath,
163+
ignore: '**/lodash/**',
164+
});
165+
const sorted = results.sort();
166+
167+
// lodash files should be excluded
168+
expect(sorted.filter(r => r.includes('lodash'))).toEqual([]);
169+
170+
// Other node_modules files should be present
171+
expect(sorted.filter(r => r.includes('react'))).toContain(
172+
'node_modules/react/index.js'
173+
);
174+
});
175+
});
176+
177+
describe('comparison with glob for /** suffix', () => {
178+
const testCases = [
179+
{
180+
pattern: '**',
181+
ignore: 'node_modules/**',
182+
description: 'node_modules/** excludes directory and children',
183+
},
184+
{
185+
pattern: '**',
186+
ignore: 'node_modules',
187+
description: 'node_modules excludes only exact match',
188+
},
189+
{
190+
pattern: '**/*.js',
191+
ignore: 'dist/**',
192+
description: 'dist/** with file pattern',
193+
},
194+
{
195+
pattern: '**',
196+
ignore: ['node_modules/**', 'dist/**'],
197+
description: 'multiple /** ignores',
198+
},
199+
{
200+
pattern: '**/*.ts',
201+
ignore: 'src/components/**',
202+
description: 'nested component ignore',
203+
},
204+
];
205+
206+
for (const tc of testCases) {
207+
it(`comparison: ${tc.description}`, async () => {
208+
const options = {
209+
cwd: fixturePath,
210+
ignore: tc.ignore,
211+
};
212+
213+
const [globResults, globlinResults] = await Promise.all([
214+
nodeGlob(tc.pattern, options),
215+
globlin.glob(tc.pattern, options),
216+
]);
217+
218+
const globSorted = globResults.sort();
219+
const globlinSorted = globlinResults.sort();
220+
221+
expect(globlinSorted).toEqual(globSorted);
222+
});
223+
224+
it(`sync comparison: ${tc.description}`, () => {
225+
const options = {
226+
cwd: fixturePath,
227+
ignore: tc.ignore,
228+
};
229+
230+
const globResults = nodeGlob.sync(tc.pattern, options);
231+
const globlinResults = globlin.globSync(tc.pattern, options);
232+
233+
const globSorted = globResults.sort();
234+
const globlinSorted = globlinResults.sort();
235+
236+
expect(globlinSorted).toEqual(globSorted);
237+
});
238+
}
239+
});
240+
241+
describe('childrenIgnored optimization', () => {
242+
it('/** suffix should skip traversing into directory', async () => {
243+
// This tests that the optimization is working - we don't traverse into ignored directories
244+
// We can't easily verify this without timing, but we can verify the results are correct
245+
const results = await globlin.glob('**', {
246+
cwd: fixturePath,
247+
ignore: 'node_modules/**',
248+
});
249+
250+
// Verify no node_modules entries
251+
expect(results.filter(r => r.includes('node_modules'))).toEqual([]);
252+
});
253+
254+
it('multiple /** patterns should skip all matching directories', async () => {
255+
const results = await globlin.glob('**', {
256+
cwd: fixturePath,
257+
ignore: ['node_modules/**', 'dist/**', 'tmp/**'],
258+
});
259+
260+
// Verify none of the ignored directories appear
261+
for (const dir of ['node_modules', 'dist', 'tmp']) {
262+
expect(results.filter(r => r.includes(dir))).toEqual([]);
263+
}
264+
});
265+
});
266+
267+
describe('edge cases with /** suffix', () => {
268+
it('/**/** (double globstar) should work like /**', async () => {
269+
const results = await globlin.glob('**', {
270+
cwd: fixturePath,
271+
ignore: 'node_modules/**/**',
272+
});
273+
274+
// Should behave the same as node_modules/**
275+
expect(results.filter(r => r.includes('node_modules'))).toEqual([]);
276+
});
277+
278+
it('ignore "./**" at root', async () => {
279+
// ./** means current directory and all children
280+
const results = await globlin.glob('**', {
281+
cwd: fixturePath,
282+
ignore: './**',
283+
});
284+
285+
// Should ignore everything
286+
expect(results).toEqual([]);
287+
});
288+
289+
it('brace expansion with /** suffix', async () => {
290+
const results = await globlin.glob('**', {
291+
cwd: fixturePath,
292+
ignore: '{node_modules,dist}/**',
293+
});
294+
295+
// Both should be excluded
296+
expect(results.filter(r => r.includes('node_modules'))).toEqual([]);
297+
expect(results.filter(r => r.startsWith('dist'))).toEqual([]);
298+
});
299+
300+
it('** alone without prefix', async () => {
301+
// "/**" at the start - means absolute root
302+
// In most cases, users would use "**" to match all
303+
const results = await globlin.glob('*', {
304+
cwd: fixturePath,
305+
ignore: '**',
306+
});
307+
308+
// All files in cwd should be ignored
309+
expect(results).toEqual([]);
310+
});
311+
});
312+
});

0 commit comments

Comments
 (0)