1 | import * as fse from "fs-extra";
|
2 | import { expect } from "chai";
|
3 | import * as pathUtil from "path";
|
4 | import path from "./assert_path";
|
5 | import helper from "./helper";
|
6 | import * as jetpack from "..";
|
7 | import { FSJetpack } from "../types";
|
8 |
|
9 | describe("dir", () => {
|
10 | beforeEach(helper.setCleanTestCwd);
|
11 | afterEach(helper.switchBackToCorrectCwd);
|
12 |
|
13 | describe("creates directory if it doesn't exist", () => {
|
14 | const expectations = () => {
|
15 | path("x").shouldBeDirectory();
|
16 | };
|
17 |
|
18 | it("sync", () => {
|
19 | jetpack.dir("x");
|
20 | expectations();
|
21 | });
|
22 |
|
23 | it("async", done => {
|
24 | jetpack.dirAsync("x").then(() => {
|
25 | expectations();
|
26 | done();
|
27 | });
|
28 | });
|
29 | });
|
30 |
|
31 | describe("does nothing if directory already exists", () => {
|
32 | const preparations = () => {
|
33 | fse.mkdirsSync("x");
|
34 | };
|
35 |
|
36 | const expectations = () => {
|
37 | path("x").shouldBeDirectory();
|
38 | };
|
39 |
|
40 | it("sync", () => {
|
41 | preparations();
|
42 | jetpack.dir("x");
|
43 | expectations();
|
44 | });
|
45 |
|
46 | it("async", done => {
|
47 | preparations();
|
48 | jetpack.dirAsync("x").then(() => {
|
49 | expectations();
|
50 | done();
|
51 | });
|
52 | });
|
53 | });
|
54 |
|
55 | describe("creates nested directories if necessary", () => {
|
56 | const expectations = () => {
|
57 | path("a/b/c").shouldBeDirectory();
|
58 | };
|
59 |
|
60 | it("sync", () => {
|
61 | jetpack.dir("a/b/c");
|
62 | expectations();
|
63 | });
|
64 |
|
65 | it("async", done => {
|
66 | jetpack.dirAsync("a/b/c").then(() => {
|
67 | expectations();
|
68 | done();
|
69 | });
|
70 | });
|
71 | });
|
72 |
|
73 | describe("handles well two calls racing to create the same directory", () => {
|
74 | const expectations = () => {
|
75 | path("a/b/c").shouldBeDirectory();
|
76 | };
|
77 |
|
78 | it("async", done => {
|
79 | let doneCount = 0;
|
80 | const check = () => {
|
81 | doneCount += 1;
|
82 | if (doneCount === 2) {
|
83 | expectations();
|
84 | done();
|
85 | }
|
86 | };
|
87 | jetpack.dirAsync("a/b/c").then(check);
|
88 | jetpack.dirAsync("a/b/c").then(check);
|
89 | });
|
90 | });
|
91 |
|
92 | describe("doesn't touch directory content by default", () => {
|
93 | const preparations = () => {
|
94 | fse.mkdirsSync("a/b");
|
95 | fse.outputFileSync("a/c.txt", "abc");
|
96 | };
|
97 |
|
98 | const expectations = () => {
|
99 | path("a/b").shouldBeDirectory();
|
100 | path("a/c.txt").shouldBeFileWithContent("abc");
|
101 | };
|
102 |
|
103 | it("sync", () => {
|
104 | preparations();
|
105 | jetpack.dir("a");
|
106 | expectations();
|
107 | });
|
108 |
|
109 | it("async", done => {
|
110 | preparations();
|
111 | jetpack.dirAsync("a").then(() => {
|
112 | expectations();
|
113 | done();
|
114 | });
|
115 | });
|
116 | });
|
117 |
|
118 | describe("makes directory empty if that option specified", () => {
|
119 | const preparations = () => {
|
120 | fse.outputFileSync("a/b/file.txt", "abc");
|
121 | };
|
122 |
|
123 | const expectations = () => {
|
124 | path("a/b/file.txt").shouldNotExist();
|
125 | path("a").shouldBeDirectory();
|
126 | };
|
127 |
|
128 | it("sync", () => {
|
129 | preparations();
|
130 | jetpack.dir("a", { empty: true });
|
131 | expectations();
|
132 | });
|
133 |
|
134 | it("async", done => {
|
135 | preparations();
|
136 | jetpack.dirAsync("a", { empty: true }).then(() => {
|
137 | expectations();
|
138 | done();
|
139 | });
|
140 | });
|
141 | });
|
142 |
|
143 | describe("throws if given path is something other than directory", () => {
|
144 | const preparations = () => {
|
145 | fse.outputFileSync("a", "abc");
|
146 | };
|
147 |
|
148 | const expectations = (err: any) => {
|
149 | expect(err.message).to.have.string("exists but is not a directory");
|
150 | };
|
151 |
|
152 | it("sync", () => {
|
153 | preparations();
|
154 | try {
|
155 | jetpack.dir("a");
|
156 | throw new Error("Expected error to be thrown");
|
157 | } catch (err) {
|
158 | expectations(err);
|
159 | }
|
160 | });
|
161 |
|
162 | it("async", done => {
|
163 | preparations();
|
164 | jetpack.dirAsync("a").catch(err => {
|
165 | expectations(err);
|
166 | done();
|
167 | });
|
168 | });
|
169 | });
|
170 |
|
171 | describe("respects internal CWD of jetpack instance", () => {
|
172 | const expectations = () => {
|
173 | path("a/b").shouldBeDirectory();
|
174 | };
|
175 |
|
176 | it("sync", () => {
|
177 | const jetContext = jetpack.cwd("a");
|
178 | jetContext.dir("b");
|
179 | expectations();
|
180 | });
|
181 |
|
182 | it("async", done => {
|
183 | const jetContext = jetpack.cwd("a");
|
184 | jetContext.dirAsync("b").then(() => {
|
185 | expectations();
|
186 | done();
|
187 | });
|
188 | });
|
189 | });
|
190 |
|
191 | describe("returns jetack instance pointing on this directory", () => {
|
192 | const expectations = (jetpackContext: FSJetpack) => {
|
193 | expect(jetpackContext.cwd()).to.equal(pathUtil.resolve("a"));
|
194 | };
|
195 |
|
196 | it("sync", () => {
|
197 | expectations(jetpack.dir("a"));
|
198 | });
|
199 |
|
200 | it("async", done => {
|
201 | jetpack.dirAsync("a").then(jetpackContext => {
|
202 | expectations(jetpackContext);
|
203 | done();
|
204 | });
|
205 | });
|
206 | });
|
207 |
|
208 | if (process.platform !== "win32") {
|
209 | describe("sets mode to newly created directory (unix only)", () => {
|
210 | const expectations = () => {
|
211 | path("a").shouldHaveMode("511");
|
212 | };
|
213 |
|
214 | it("sync, mode passed as string", () => {
|
215 | jetpack.dir("a", { mode: "511" });
|
216 | expectations();
|
217 | });
|
218 |
|
219 | it("sync, mode passed as number", () => {
|
220 | jetpack.dir("a", { mode: 0o511 });
|
221 | expectations();
|
222 | });
|
223 |
|
224 | it("async, mode passed as string", done => {
|
225 | jetpack.dirAsync("a", { mode: "511" }).then(() => {
|
226 | expectations();
|
227 | done();
|
228 | });
|
229 | });
|
230 |
|
231 | it("async, mode passed as number", done => {
|
232 | jetpack.dirAsync("a", { mode: 0o511 }).then(() => {
|
233 | expectations();
|
234 | done();
|
235 | });
|
236 | });
|
237 | });
|
238 |
|
239 | describe("sets desired mode to every created directory (unix only)", () => {
|
240 | const expectations = () => {
|
241 | path("a").shouldHaveMode("711");
|
242 | path("a/b").shouldHaveMode("711");
|
243 | };
|
244 |
|
245 | it("sync", () => {
|
246 | jetpack.dir("a/b", { mode: "711" });
|
247 | expectations();
|
248 | });
|
249 |
|
250 | it("async", done => {
|
251 | jetpack.dirAsync("a/b", { mode: "711" }).then(() => {
|
252 | expectations();
|
253 | done();
|
254 | });
|
255 | });
|
256 | });
|
257 |
|
258 | describe("changes mode of existing directory to desired (unix only)", () => {
|
259 | const preparations = () => {
|
260 | fse.mkdirSync("a", "777");
|
261 | };
|
262 | const expectations = () => {
|
263 | path("a").shouldHaveMode("511");
|
264 | };
|
265 |
|
266 | it("sync", () => {
|
267 | preparations();
|
268 | jetpack.dir("a", { mode: "511" });
|
269 | expectations();
|
270 | });
|
271 |
|
272 | it("async", done => {
|
273 | preparations();
|
274 | jetpack.dirAsync("a", { mode: "511" }).then(() => {
|
275 | expectations();
|
276 | done();
|
277 | });
|
278 | });
|
279 | });
|
280 |
|
281 | describe("leaves mode of directory intact by default (unix only)", () => {
|
282 | const preparations = () => {
|
283 | fse.mkdirSync("a", "700");
|
284 | };
|
285 |
|
286 | const expectations = () => {
|
287 | path("a").shouldHaveMode("700");
|
288 | };
|
289 |
|
290 | it("sync", () => {
|
291 | preparations();
|
292 | jetpack.dir("a");
|
293 | expectations();
|
294 | });
|
295 |
|
296 | it("async", done => {
|
297 | preparations();
|
298 | jetpack.dirAsync("a").then(() => {
|
299 | expectations();
|
300 | done();
|
301 | });
|
302 | });
|
303 | });
|
304 | } else {
|
305 | describe("specyfying mode have no effect and throws no error (windows only)", () => {
|
306 | const expectations = () => {
|
307 | path("x").shouldBeDirectory();
|
308 | };
|
309 |
|
310 | it("sync", () => {
|
311 | jetpack.dir("x", { mode: "511" });
|
312 | expectations();
|
313 | });
|
314 |
|
315 | it("async", done => {
|
316 | jetpack.dirAsync("x", { mode: "511" }).then(() => {
|
317 | expectations();
|
318 | done();
|
319 | });
|
320 | });
|
321 | });
|
322 | }
|
323 |
|
324 | describe("input validation", () => {
|
325 | const tests = [
|
326 | { type: "sync", method: jetpack.dir as any, methodName: "dir" },
|
327 | { type: "async", method: jetpack.dirAsync as any, methodName: "dirAsync" }
|
328 | ];
|
329 |
|
330 | describe('"path" argument', () => {
|
331 | tests.forEach(test => {
|
332 | it(test.type, () => {
|
333 | expect(() => {
|
334 | test.method(undefined);
|
335 | }).to.throw(
|
336 | `Argument "path" passed to ${
|
337 | test.methodName
|
338 | }(path, [criteria]) must be a string. Received undefined`
|
339 | );
|
340 | });
|
341 | });
|
342 | });
|
343 |
|
344 | describe('"criteria" object', () => {
|
345 | describe('"empty" argument', () => {
|
346 | tests.forEach(test => {
|
347 | it(test.type, () => {
|
348 | expect(() => {
|
349 | test.method("abc", { empty: 1 });
|
350 | }).to.throw(
|
351 | `Argument "criteria.empty" passed to ${
|
352 | test.methodName
|
353 | }(path, [criteria]) must be a boolean. Received number`
|
354 | );
|
355 | });
|
356 | });
|
357 | });
|
358 | describe('"mode" argument', () => {
|
359 | tests.forEach(test => {
|
360 | it(test.type, () => {
|
361 | expect(() => {
|
362 | test.method("abc", { mode: true });
|
363 | }).to.throw(
|
364 | `Argument "criteria.mode" passed to ${
|
365 | test.methodName
|
366 | }(path, [criteria]) must be a string or a number. Received boolean`
|
367 | );
|
368 | });
|
369 | });
|
370 | });
|
371 | });
|
372 | });
|
373 | });
|