UNPKG

18.1 kBPlain TextView Raw
1import * as fse from "fs-extra";
2import { expect } from "chai";
3import path from "./assert_path";
4import helper from "./helper";
5import * as jetpack from "..";
6
7describe("find", () => {
8 beforeEach(helper.setCleanTestCwd);
9 afterEach(helper.switchBackToCorrectCwd);
10
11 describe("returns list of relative paths anchored to CWD", () => {
12 const preparations = () => {
13 fse.outputFileSync("a/b/file.txt", "abc");
14 };
15
16 const expectations = (found: string[]) => {
17 const normalizedPaths = helper.osSep(["a/b/file.txt"]);
18 expect(found).to.eql(normalizedPaths);
19 };
20
21 it("sync", () => {
22 preparations();
23 expectations(jetpack.find("a", { matching: "*.txt" }));
24 });
25
26 it("async", done => {
27 preparations();
28 jetpack.findAsync("a", { matching: "*.txt" }).then(found => {
29 expectations(found);
30 done();
31 });
32 });
33 });
34
35 describe("if recursive=false will exclude subfolders from search", () => {
36 const preparations = () => {
37 fse.outputFileSync("x/file.txt", "abc");
38 fse.outputFileSync("x/y/file.txt", "123");
39 fse.outputFileSync("x/y/b/file.txt", "456");
40 };
41
42 const expectations = (found: string[]) => {
43 const normalizedPaths = helper.osSep(["x/file.txt"]);
44 expect(found).to.eql(normalizedPaths);
45 };
46
47 it("sync", () => {
48 preparations();
49 expectations(jetpack.find("x", { matching: "*.txt", recursive: false }));
50 });
51
52 it("async", done => {
53 preparations();
54 jetpack
55 .findAsync("x", { matching: "*.txt", recursive: false })
56 .then(found => {
57 expectations(found);
58 done();
59 });
60 });
61 });
62
63 describe("defaults to CWD if no path provided", () => {
64 const preparations = () => {
65 fse.outputFileSync("a/b/file.txt", "abc");
66 };
67
68 const expectations = (found: string[]) => {
69 const normalizedPaths = helper.osSep(["a/b/file.txt"]);
70 expect(found).to.eql(normalizedPaths);
71 };
72
73 it("sync", () => {
74 preparations();
75 expectations(jetpack.find({ matching: "*.txt" }));
76 });
77
78 it("async", done => {
79 preparations();
80 jetpack.findAsync({ matching: "*.txt" }).then(found => {
81 expectations(found);
82 done();
83 });
84 });
85 });
86
87 describe("returns empty list if nothing found", () => {
88 const preparations = () => {
89 fse.outputFileSync("a/b/c.md", "abc");
90 };
91
92 const expectations = (found: string[]) => {
93 expect(found).to.eql([]);
94 };
95
96 it("sync", () => {
97 preparations();
98 expectations(jetpack.find("a", { matching: "*.txt" }));
99 });
100
101 it("async", done => {
102 preparations();
103 jetpack.findAsync("a", { matching: "*.txt" }).then(found => {
104 expectations(found);
105 done();
106 });
107 });
108 });
109
110 describe("finds all paths which match globs", () => {
111 const preparations = () => {
112 fse.outputFileSync("a/b/file.txt", "1");
113 fse.outputFileSync("a/b/c/file.txt", "2");
114 fse.outputFileSync("a/b/c/file.md", "3");
115 fse.outputFileSync("a/x/y/z", "Zzzzz...");
116 };
117
118 const expectations = (found: string[]) => {
119 const normalizedPaths = helper.osSep([
120 "a/b/c/file.txt",
121 "a/b/file.txt",
122 "a/x/y/z"
123 ]);
124 found.sort();
125 expect(found).to.eql(normalizedPaths);
126 };
127
128 it("sync", () => {
129 preparations();
130 expectations(jetpack.find("a", { matching: ["*.txt", "z"] }));
131 });
132
133 it("async", done => {
134 preparations();
135 jetpack.findAsync("a", { matching: ["*.txt", "z"] }).then(found => {
136 expectations(found);
137 done();
138 });
139 });
140 });
141
142 describe("anchors globs to directory you're finding in", () => {
143 const preparations = () => {
144 fse.outputFileSync("x/y/a/b/file.txt", "123");
145 fse.outputFileSync("x/y/a/b/c/file.txt", "456");
146 };
147
148 const expectations = (found: string[]) => {
149 const normalizedPaths = helper.osSep(["x/y/a/b/file.txt"]);
150 expect(found).to.eql(normalizedPaths);
151 };
152
153 it("sync", () => {
154 preparations();
155 expectations(jetpack.find("x/y/a", { matching: "b/*.txt" }));
156 });
157
158 it("async", done => {
159 preparations();
160 jetpack.findAsync("x/y/a", { matching: "b/*.txt" }).then(found => {
161 expectations(found);
162 done();
163 });
164 });
165 });
166
167 describe("can use ./ as indication of anchor directory", () => {
168 const preparations = () => {
169 fse.outputFileSync("x/y/file.txt", "123");
170 fse.outputFileSync("x/y/b/file.txt", "456");
171 };
172
173 const expectations = (found: string[]) => {
174 const normalizedPaths = helper.osSep(["x/y/file.txt"]);
175 expect(found).to.eql(normalizedPaths);
176 };
177
178 it("sync", () => {
179 preparations();
180 expectations(jetpack.find("x/y", { matching: "./file.txt" }));
181 });
182
183 it("async", done => {
184 preparations();
185 jetpack.findAsync("x/y", { matching: "./file.txt" }).then(found => {
186 expectations(found);
187 done();
188 });
189 });
190 });
191
192 describe("deals with negation globs", () => {
193 const preparations = () => {
194 fse.outputFileSync("x/y/a/b", "bbb");
195 fse.outputFileSync("x/y/a/x", "xxx");
196 fse.outputFileSync("x/y/a/y", "yyy");
197 fse.outputFileSync("x/y/a/z", "zzz");
198 };
199
200 const expectations = (found: string[]) => {
201 const normalizedPaths = helper.osSep(["x/y/a/b"]);
202 expect(found).to.eql(normalizedPaths);
203 };
204
205 it("sync", () => {
206 preparations();
207 expectations(
208 jetpack.find("x/y", {
209 matching: [
210 "a/*",
211 // Three different pattern types to test:
212 "!x",
213 "!a/y",
214 "!./a/z"
215 ]
216 })
217 );
218 });
219
220 it("async", done => {
221 preparations();
222 jetpack
223 .findAsync("x/y", {
224 matching: [
225 "a/*",
226 // Three different pattern types to test:
227 "!x",
228 "!a/y",
229 "!./a/z"
230 ]
231 })
232 .then(found => {
233 expectations(found);
234 done();
235 });
236 });
237 });
238
239 describe("doesn't look for directories by default", () => {
240 const preparations = () => {
241 fse.outputFileSync("a/b/foo1", "abc");
242 fse.mkdirsSync("a/b/foo2");
243 };
244
245 const expectations = (found: string[]) => {
246 const normalizedPaths = helper.osSep(["a/b/foo1"]);
247 expect(found).to.eql(normalizedPaths);
248 };
249
250 it("sync", () => {
251 preparations();
252 expectations(jetpack.find("a", { matching: "foo*" }));
253 });
254
255 it("async", done => {
256 preparations();
257 jetpack.findAsync("a", { matching: "foo*" }).then(found => {
258 expectations(found);
259 done();
260 });
261 });
262 });
263
264 describe("treats symlinks like real files", () => {
265 const preparations = () => {
266 fse.mkdirsSync("dir");
267 fse.outputFileSync("file", "abc");
268 jetpack.symlink("dir", "symdir");
269 jetpack.symlink("file", "symfile");
270 };
271
272 const expectations = (found: string[]) => {
273 expect(found).to.eql(["file", "symfile"]);
274 };
275
276 it("sync", () => {
277 preparations();
278 expectations(jetpack.find({ matching: "*" }));
279 });
280
281 it("async", done => {
282 preparations();
283 jetpack.findAsync({ matching: "*" }).then(found => {
284 expectations(found);
285 done();
286 });
287 });
288 });
289
290 describe("follows to symlinked directories", () => {
291 const preparations = () => {
292 fse.outputFileSync("dir1/dir2/file.txt", "abc");
293 jetpack.symlink("../dir1", "foo/symlink_to_dir1");
294 expect(jetpack.read("foo/symlink_to_dir1/dir2/file.txt")).to.eql("abc");
295 };
296
297 const expectations = (found: string[]) => {
298 const normalizedPaths = helper.osSep([
299 "foo/symlink_to_dir1/dir2/file.txt"
300 ]);
301 expect(found).to.eql(normalizedPaths);
302 };
303
304 it("sync", () => {
305 preparations();
306 expectations(jetpack.find("foo", { matching: "file*" }));
307 });
308
309 it("async", done => {
310 preparations();
311 jetpack.findAsync("foo", { matching: "file*" }).then(found => {
312 expectations(found);
313 done();
314 });
315 });
316 });
317
318 describe("can look for files and directories", () => {
319 const preparations = () => {
320 fse.outputFileSync("a/b/foo1", "abc");
321 fse.mkdirsSync("a/b/foo2");
322 };
323
324 const expectations = (found: string[]) => {
325 const normalizedPaths = helper.osSep(["a/b/foo1", "a/b/foo2"]);
326 expect(found).to.eql(normalizedPaths);
327 };
328
329 it("sync", () => {
330 preparations();
331 expectations(
332 jetpack.find("a", {
333 matching: "foo*",
334 directories: true
335 })
336 );
337 });
338
339 it("async", done => {
340 preparations();
341 jetpack
342 .findAsync("a", {
343 matching: "foo*",
344 directories: true
345 })
346 .then(found => {
347 expectations(found);
348 done();
349 })
350 .catch(done);
351 });
352 });
353
354 describe("can look for only directories", () => {
355 const preparations = () => {
356 fse.outputFileSync("a/b/foo1", "abc");
357 fse.mkdirsSync("a/b/foo2");
358 };
359
360 const expectations = (found: string[]) => {
361 const normalizedPaths = helper.osSep(["a/b/foo2"]);
362 expect(found).to.eql(normalizedPaths);
363 };
364
365 it("sync", () => {
366 preparations();
367 expectations(
368 jetpack.find("a", {
369 matching: "foo*",
370 files: false,
371 directories: true
372 })
373 );
374 });
375
376 it("async", done => {
377 preparations();
378 jetpack
379 .findAsync("a", {
380 matching: "foo*",
381 files: false,
382 directories: true
383 })
384 .then(found => {
385 expectations(found);
386 done();
387 })
388 .catch(done);
389 });
390 });
391
392 describe("looking for directories works ok with only negation globs in set", () => {
393 const preparations = () => {
394 fse.outputFileSync("a/x", "123");
395 fse.outputFileSync("a/y", "789");
396 };
397
398 const expectations = (found: string[]) => {
399 const normalizedPaths = helper.osSep(["a/x"]);
400 expect(found).to.eql(normalizedPaths);
401 };
402
403 it("sync", () => {
404 preparations();
405 expectations(
406 jetpack.find("a", {
407 matching: ["!y"],
408 directories: true
409 })
410 );
411 });
412
413 it("async", done => {
414 preparations();
415 jetpack
416 .findAsync("a", {
417 matching: ["!y"],
418 directories: true
419 })
420 .then(found => {
421 expectations(found);
422 done();
423 })
424 .catch(done);
425 });
426 });
427
428 describe("when you turn off files and directoies returns empty list", () => {
429 const preparations = () => {
430 fse.outputFileSync("a/b/foo1", "abc");
431 fse.mkdirsSync("a/b/foo2");
432 };
433
434 const expectations = (found: string[]) => {
435 expect(found).to.eql([]);
436 };
437
438 it("sync", () => {
439 preparations();
440 expectations(
441 jetpack.find("a", {
442 matching: "foo*",
443 files: false,
444 directories: false
445 })
446 );
447 });
448
449 it("async", done => {
450 preparations();
451 jetpack
452 .findAsync("a", {
453 matching: "foo*",
454 files: false,
455 directories: false
456 })
457 .then(found => {
458 expectations(found);
459 done();
460 });
461 });
462 });
463
464 describe("throws if path doesn't exist", () => {
465 const expectations = (err: any) => {
466 expect(err.code).to.equal("ENOENT");
467 expect(err.message).to.have.string(
468 "Path you want to find stuff in doesn't exist"
469 );
470 };
471
472 it("sync", () => {
473 try {
474 jetpack.find("a", { matching: "*.txt" });
475 throw new Error("Expected error to be thrown");
476 } catch (err) {
477 expectations(err);
478 }
479 });
480
481 it("async", done => {
482 jetpack.findAsync("a", { matching: "*.txt" }).catch(err => {
483 expectations(err);
484 done();
485 });
486 });
487 });
488
489 describe("throws if path is a file, not a directory", () => {
490 const preparations = () => {
491 fse.outputFileSync("a/b", "abc");
492 };
493
494 const expectations = (err: any) => {
495 expect(err.code).to.equal("ENOTDIR");
496 expect(err.message).to.have.string(
497 "Path you want to find stuff in must be a directory"
498 );
499 };
500
501 it("sync", () => {
502 preparations();
503 try {
504 jetpack.find("a/b", { matching: "*.txt" });
505 throw new Error("Expected error to be thrown");
506 } catch (err) {
507 expectations(err);
508 }
509 });
510
511 it("async", done => {
512 preparations();
513 jetpack.findAsync("a/b", { matching: "*.txt" }).catch(err => {
514 expectations(err);
515 done();
516 });
517 });
518 });
519
520 describe("respects internal CWD of jetpack instance", () => {
521 const preparations = () => {
522 fse.outputFileSync("a/b/c/d.txt", "abc");
523 };
524
525 const expectations = (found: string[]) => {
526 const normalizedPaths = helper.osSep(["b/c/d.txt"]); // NOT a/b/c/d.txt
527 expect(found).to.eql(normalizedPaths);
528 };
529
530 it("sync", () => {
531 const jetContext = jetpack.cwd("a");
532 preparations();
533 expectations(jetContext.find("b", { matching: "*.txt" }));
534 });
535
536 it("async", done => {
537 const jetContext = jetpack.cwd("a");
538 preparations();
539 jetContext.findAsync("b", { matching: "*.txt" }).then(found => {
540 expectations(found);
541 done();
542 });
543 });
544 });
545
546 describe("finds dot-dirs and dot-files", () => {
547 const preparations = () => {
548 fse.outputFileSync(".dir/file", "a");
549 fse.outputFileSync(".dir/.file", "b");
550 fse.outputFileSync(".foo/.file", "c");
551 };
552
553 const expectations = (found: string[]) => {
554 const normalizedPaths = helper.osSep([".dir", ".dir/.file"]);
555 expect(found).to.eql(normalizedPaths);
556 };
557
558 it("sync", () => {
559 preparations();
560 expectations(
561 jetpack.find({
562 matching: [".dir", ".file", "!.foo/**"],
563 directories: true
564 })
565 );
566 });
567
568 it("async", done => {
569 preparations();
570 jetpack
571 .findAsync({
572 matching: [".dir", ".file", "!.foo/**"],
573 directories: true
574 })
575 .then(found => {
576 expectations(found);
577 done();
578 });
579 });
580 });
581
582 describe("if ignoreCase=true it ignores case in patterns", () => {
583 const preparations = () => {
584 fse.outputFileSync("FOO/BAR", "a");
585 };
586
587 const expectations = (found: string[]) => {
588 const paths = ["FOO", "FOO/BAR"];
589 const normalizedPaths = helper.osSep(paths);
590 expect(found).to.eql(normalizedPaths);
591 };
592
593 it("sync", () => {
594 preparations();
595 expectations(
596 jetpack.find({
597 matching: ["foo", "bar"],
598 directories: true,
599 ignoreCase: true
600 })
601 );
602 });
603
604 it("async", done => {
605 preparations();
606 jetpack
607 .findAsync({
608 matching: ["foo", "bar"],
609 directories: true,
610 ignoreCase: true
611 })
612 .then(found => {
613 expectations(found);
614 done();
615 })
616 .catch(done);
617 });
618 });
619
620 describe("input validation", () => {
621 const tests = [
622 { type: "sync", method: jetpack.find as any, methodName: "find" },
623 {
624 type: "async",
625 method: jetpack.findAsync as any,
626 methodName: "findAsync"
627 }
628 ];
629
630 describe('"path" argument', () => {
631 tests.forEach(test => {
632 it(test.type, () => {
633 expect(() => {
634 test.method(undefined, {});
635 }).to.throw(
636 `Argument "path" passed to ${
637 test.methodName
638 }([path], options) must be a string. Received undefined`
639 );
640 });
641 });
642 });
643
644 describe('"options" object', () => {
645 describe('"matching" argument', () => {
646 tests.forEach(test => {
647 it(test.type, () => {
648 expect(() => {
649 test.method({ matching: 1 });
650 }).to.throw(
651 `Argument "options.matching" passed to ${
652 test.methodName
653 }([path], options) must be a string or an array of string. Received number`
654 );
655 });
656 });
657 });
658 describe('"files" argument', () => {
659 tests.forEach(test => {
660 it(test.type, () => {
661 expect(() => {
662 test.method("abc", { files: 1 });
663 }).to.throw(
664 `Argument "options.files" passed to ${
665 test.methodName
666 }([path], options) must be a boolean. Received number`
667 );
668 });
669 });
670 });
671 describe('"directories" argument', () => {
672 tests.forEach(test => {
673 it(test.type, () => {
674 expect(() => {
675 test.method("abc", { directories: 1 });
676 }).to.throw(
677 `Argument "options.directories" passed to ${
678 test.methodName
679 }([path], options) must be a boolean. Received number`
680 );
681 });
682 });
683 });
684 describe('"recursive" argument', () => {
685 tests.forEach(test => {
686 it(test.type, () => {
687 expect(() => {
688 test.method("abc", { recursive: 1 });
689 }).to.throw(
690 `Argument "options.recursive" passed to ${
691 test.methodName
692 }([path], options) must be a boolean. Received number`
693 );
694 });
695 });
696 });
697 describe('"ignoreCase" argument', () => {
698 tests.forEach(test => {
699 it(test.type, () => {
700 expect(() => {
701 test.method("abc", { ignoreCase: 1 });
702 }).to.throw(
703 `Argument "options.ignoreCase" passed to ${
704 test.methodName
705 }([path], options) must be a boolean. Received number`
706 );
707 });
708 });
709 });
710 });
711 });
712});