1 | import * as fse from "fs-extra";
|
2 | import { expect } from "chai";
|
3 | import path from "./assert_path";
|
4 | import helper from "./helper";
|
5 | import * as jetpack from "..";
|
6 | import { FSJetpack } from "../types";
|
7 |
|
8 | describe("file", () => {
|
9 | beforeEach(helper.setCleanTestCwd);
|
10 | afterEach(helper.switchBackToCorrectCwd);
|
11 |
|
12 | describe("creates file if it doesn't exist", () => {
|
13 | const expectations = () => {
|
14 | path("file.txt").shouldBeFileWithContent("");
|
15 | };
|
16 |
|
17 | it("sync", () => {
|
18 | jetpack.file("file.txt");
|
19 | expectations();
|
20 | });
|
21 |
|
22 | it("async", done => {
|
23 | jetpack
|
24 | .fileAsync("file.txt")
|
25 | .then(() => {
|
26 | expectations();
|
27 | done();
|
28 | })
|
29 | .catch(done);
|
30 | });
|
31 | });
|
32 |
|
33 | describe("leaves file intact if it already exists", () => {
|
34 | const preparations = () => {
|
35 | fse.outputFileSync("file.txt", "abc");
|
36 | };
|
37 |
|
38 | const expectations = () => {
|
39 | path("file.txt").shouldBeFileWithContent("abc");
|
40 | };
|
41 |
|
42 | it("sync", () => {
|
43 | preparations();
|
44 | jetpack.file("file.txt");
|
45 | expectations();
|
46 | });
|
47 |
|
48 | it("async", done => {
|
49 | preparations();
|
50 | jetpack
|
51 | .fileAsync("file.txt")
|
52 | .then(() => {
|
53 | expectations();
|
54 | done();
|
55 | })
|
56 | .catch(done);
|
57 | });
|
58 | });
|
59 |
|
60 | describe("can save file content given as string", () => {
|
61 | const expectations = () => {
|
62 | path("file.txt").shouldBeFileWithContent("ąbć");
|
63 | };
|
64 |
|
65 | it("sync", () => {
|
66 | jetpack.file("file.txt", { content: "ąbć" });
|
67 | expectations();
|
68 | });
|
69 |
|
70 | it("async", done => {
|
71 | jetpack
|
72 | .fileAsync("file.txt", { content: "ąbć" })
|
73 | .then(() => {
|
74 | expectations();
|
75 | done();
|
76 | })
|
77 | .catch(done);
|
78 | });
|
79 | });
|
80 |
|
81 | describe("can save file content given as buffer", () => {
|
82 | const expectations = () => {
|
83 | path("file").shouldBeFileWithContent(new Buffer([11, 22]));
|
84 | };
|
85 |
|
86 | it("sync", () => {
|
87 | jetpack.file("file", { content: new Buffer([11, 22]) });
|
88 | expectations();
|
89 | });
|
90 |
|
91 | it("async", done => {
|
92 | jetpack
|
93 | .fileAsync("file", { content: new Buffer([11, 22]) })
|
94 | .then(() => {
|
95 | expectations();
|
96 | done();
|
97 | })
|
98 | .catch(done);
|
99 | });
|
100 | });
|
101 |
|
102 | describe("can save file content given as plain JS object (will be saved as JSON)", () => {
|
103 | const obj = {
|
104 | a: "abc",
|
105 | b: 123
|
106 | };
|
107 |
|
108 | const expectations = () => {
|
109 | const data = JSON.parse(fse.readFileSync("file.txt", "utf8"));
|
110 | expect(data).to.eql(obj);
|
111 | };
|
112 |
|
113 | it("sync", () => {
|
114 | jetpack.file("file.txt", { content: obj });
|
115 | expectations();
|
116 | });
|
117 |
|
118 | it("async", done => {
|
119 | jetpack
|
120 | .fileAsync("file.txt", { content: obj })
|
121 | .then(() => {
|
122 | expectations();
|
123 | done();
|
124 | })
|
125 | .catch(done);
|
126 | });
|
127 | });
|
128 |
|
129 | describe("written JSON data can be indented", () => {
|
130 | const obj = {
|
131 | a: "abc",
|
132 | b: 123
|
133 | };
|
134 |
|
135 | const expectations = () => {
|
136 | const sizeA = fse.statSync("a.json").size;
|
137 | const sizeB = fse.statSync("b.json").size;
|
138 | const sizeC = fse.statSync("c.json").size;
|
139 | expect(sizeB).to.be.above(sizeA);
|
140 | expect(sizeC).to.be.above(sizeB);
|
141 | };
|
142 |
|
143 | it("sync", () => {
|
144 | jetpack.file("a.json", { content: obj, jsonIndent: 0 });
|
145 | jetpack.file("b.json", { content: obj });
|
146 | jetpack.file("c.json", { content: obj, jsonIndent: 4 });
|
147 | expectations();
|
148 | });
|
149 |
|
150 | it("async", done => {
|
151 | jetpack
|
152 | .fileAsync("a.json", { content: obj, jsonIndent: 0 })
|
153 | .then(() => {
|
154 | return jetpack.fileAsync("b.json", { content: obj });
|
155 | })
|
156 | .then(() => {
|
157 | return jetpack.fileAsync("c.json", { content: obj, jsonIndent: 4 });
|
158 | })
|
159 | .then(() => {
|
160 | expectations();
|
161 | done();
|
162 | })
|
163 | .catch(done);
|
164 | });
|
165 | });
|
166 |
|
167 | describe("replaces content of already existing file", () => {
|
168 | const preparations = () => {
|
169 | fse.writeFileSync("file.txt", "abc");
|
170 | };
|
171 |
|
172 | const expectations = () => {
|
173 | path("file.txt").shouldBeFileWithContent("123");
|
174 | };
|
175 |
|
176 | it("sync", () => {
|
177 | preparations();
|
178 | jetpack.file("file.txt", { content: "123" });
|
179 | expectations();
|
180 | });
|
181 |
|
182 | it("async", done => {
|
183 | preparations();
|
184 | jetpack
|
185 | .fileAsync("file.txt", { content: "123" })
|
186 | .then(() => {
|
187 | expectations();
|
188 | done();
|
189 | })
|
190 | .catch(done);
|
191 | });
|
192 | });
|
193 |
|
194 | describe("throws if given path is not a file", () => {
|
195 | const preparations = () => {
|
196 | fse.mkdirsSync("a");
|
197 | };
|
198 |
|
199 | const expectations = (err: any) => {
|
200 | expect(err.message).to.have.string("exists but is not a file.");
|
201 | };
|
202 |
|
203 | it("sync", () => {
|
204 | preparations();
|
205 | try {
|
206 | jetpack.file("a");
|
207 | throw new Error("Expected error to be thrown");
|
208 | } catch (err) {
|
209 | expectations(err);
|
210 | }
|
211 | });
|
212 |
|
213 | it("async", done => {
|
214 | preparations();
|
215 | jetpack
|
216 | .fileAsync("a")
|
217 | .catch(err => {
|
218 | expectations(err);
|
219 | done();
|
220 | })
|
221 | .catch(done);
|
222 | });
|
223 | });
|
224 |
|
225 | describe("if directory for file doesn't exist creates it as well", () => {
|
226 | const expectations = () => {
|
227 | path("a/b/c.txt").shouldBeFileWithContent("");
|
228 | };
|
229 |
|
230 | it("sync", () => {
|
231 | jetpack.file("a/b/c.txt");
|
232 | expectations();
|
233 | });
|
234 |
|
235 | it("async", done => {
|
236 | jetpack
|
237 | .fileAsync("a/b/c.txt")
|
238 | .then(() => {
|
239 | expectations();
|
240 | done();
|
241 | })
|
242 | .catch(done);
|
243 | });
|
244 | });
|
245 |
|
246 | describe("returns currently used jetpack instance", () => {
|
247 | const expectations = (jetpackContext: FSJetpack) => {
|
248 | expect(jetpackContext).to.equal(jetpack);
|
249 | };
|
250 |
|
251 | it("sync", () => {
|
252 | expectations(jetpack.file("file.txt"));
|
253 | });
|
254 |
|
255 | it("async", done => {
|
256 | jetpack
|
257 | .fileAsync("file.txt")
|
258 | .then(jetpackContext => {
|
259 | expectations(jetpackContext);
|
260 | done();
|
261 | })
|
262 | .catch(done);
|
263 | });
|
264 | });
|
265 |
|
266 | describe("respects internal CWD of jetpack instance", () => {
|
267 | const expectations = () => {
|
268 | path("a/b.txt").shouldBeFileWithContent("");
|
269 | };
|
270 |
|
271 | it("sync", () => {
|
272 | const jetContext = jetpack.cwd("a");
|
273 | jetContext.file("b.txt");
|
274 | expectations();
|
275 | });
|
276 |
|
277 | it("async", done => {
|
278 | const jetContext = jetpack.cwd("a");
|
279 | jetContext
|
280 | .fileAsync("b.txt")
|
281 | .then(() => {
|
282 | expectations();
|
283 | done();
|
284 | })
|
285 | .catch(done);
|
286 | });
|
287 | });
|
288 |
|
289 | if (process.platform !== "win32") {
|
290 | describe("sets mode of newly created file (unix only)", () => {
|
291 | const expectations = () => {
|
292 | path("file.txt").shouldHaveMode("711");
|
293 | };
|
294 |
|
295 | it("sync, mode passed as string", () => {
|
296 | jetpack.file("file.txt", { mode: "711" });
|
297 | expectations();
|
298 | });
|
299 |
|
300 | it("sync, mode passed as number", () => {
|
301 | jetpack.file("file.txt", { mode: 0o711 });
|
302 | expectations();
|
303 | });
|
304 |
|
305 | it("async, mode passed as string", done => {
|
306 | jetpack
|
307 | .fileAsync("file.txt", { mode: "711" })
|
308 | .then(() => {
|
309 | expectations();
|
310 | done();
|
311 | })
|
312 | .catch(done);
|
313 | });
|
314 |
|
315 | it("async, mode passed as number", done => {
|
316 | jetpack
|
317 | .fileAsync("file.txt", { mode: 0o711 })
|
318 | .then(() => {
|
319 | expectations();
|
320 | done();
|
321 | })
|
322 | .catch(done);
|
323 | });
|
324 | });
|
325 |
|
326 | describe("changes mode of existing file if it doesn't match (unix only)", () => {
|
327 | const preparations = () => {
|
328 | fse.writeFileSync("file.txt", "abc", { mode: "700" });
|
329 | };
|
330 |
|
331 | const expectations = () => {
|
332 | path("file.txt").shouldHaveMode("511");
|
333 | };
|
334 |
|
335 | it("sync", () => {
|
336 | preparations();
|
337 | jetpack.file("file.txt", { mode: "511" });
|
338 | expectations();
|
339 | });
|
340 |
|
341 | it("async", done => {
|
342 | preparations();
|
343 | jetpack
|
344 | .fileAsync("file.txt", { mode: "511" })
|
345 | .then(() => {
|
346 | expectations();
|
347 | done();
|
348 | })
|
349 | .catch(done);
|
350 | });
|
351 | });
|
352 |
|
353 | describe("leaves mode of file intact if not explicitly specified (unix only)", () => {
|
354 | const preparations = () => {
|
355 | fse.writeFileSync("file.txt", "abc", { mode: "700" });
|
356 | };
|
357 |
|
358 | const expectations = () => {
|
359 | path("file.txt").shouldHaveMode("700");
|
360 | };
|
361 |
|
362 | it("sync, ensure exists", () => {
|
363 | preparations();
|
364 | jetpack.file("file.txt");
|
365 | expectations();
|
366 | });
|
367 |
|
368 | it("sync, ensure content", () => {
|
369 | preparations();
|
370 | jetpack.file("file.txt", { content: "abc" });
|
371 | expectations();
|
372 | });
|
373 |
|
374 | it("async, ensure exists", done => {
|
375 | preparations();
|
376 | jetpack
|
377 | .fileAsync("file.txt")
|
378 | .then(() => {
|
379 | expectations();
|
380 | done();
|
381 | })
|
382 | .catch(done);
|
383 | });
|
384 |
|
385 | it("async, ensure content", done => {
|
386 | preparations();
|
387 | jetpack
|
388 | .fileAsync("file.txt", { content: "abc" })
|
389 | .then(() => {
|
390 | expectations();
|
391 | done();
|
392 | })
|
393 | .catch(done);
|
394 | });
|
395 | });
|
396 | } else {
|
397 | describe("specyfying mode have no effect and throws no error (windows only)", () => {
|
398 | it("sync", () => {
|
399 | jetpack.file("file.txt", { mode: "711" });
|
400 | });
|
401 |
|
402 | it("async", done => {
|
403 | jetpack
|
404 | .fileAsync("file.txt", { mode: "711" })
|
405 | .then(() => {
|
406 | done();
|
407 | })
|
408 | .catch(done);
|
409 | });
|
410 | });
|
411 | }
|
412 |
|
413 | describe("input validation", () => {
|
414 | const tests = [
|
415 | { type: "sync", method: jetpack.file as any, methodName: "file" },
|
416 | {
|
417 | type: "async",
|
418 | method: jetpack.fileAsync as any,
|
419 | methodName: "fileAsync"
|
420 | }
|
421 | ];
|
422 |
|
423 | describe('"path" argument', () => {
|
424 | tests.forEach(test => {
|
425 | it(test.type, () => {
|
426 | expect(() => {
|
427 | test.method(undefined);
|
428 | }).to.throw(
|
429 | `Argument "path" passed to ${
|
430 | test.methodName
|
431 | }(path, [criteria]) must be a string. Received undefined`
|
432 | );
|
433 | });
|
434 | });
|
435 | });
|
436 |
|
437 | describe('"criteria" object', () => {
|
438 | describe('"content" argument', () => {
|
439 | tests.forEach(test => {
|
440 | it(test.type, () => {
|
441 | expect(() => {
|
442 | test.method("abc", { content: 1 });
|
443 | }).to.throw(
|
444 | `Argument "criteria.content" passed to ${
|
445 | test.methodName
|
446 | }(path, [criteria]) must be a string or a buffer or an object or an array. Received number`
|
447 | );
|
448 | });
|
449 | });
|
450 | });
|
451 | describe('"jsonIndent" argument', () => {
|
452 | tests.forEach(test => {
|
453 | it(test.type, () => {
|
454 | expect(() => {
|
455 | test.method("abc", { jsonIndent: true });
|
456 | }).to.throw(
|
457 | `Argument "criteria.jsonIndent" passed to ${
|
458 | test.methodName
|
459 | }(path, [criteria]) must be a number. Received boolean`
|
460 | );
|
461 | });
|
462 | });
|
463 | });
|
464 | describe('"mode" argument', () => {
|
465 | tests.forEach(test => {
|
466 | it(test.type, () => {
|
467 | expect(() => {
|
468 | test.method("abc", { mode: true });
|
469 | }).to.throw(
|
470 | `Argument "criteria.mode" passed to ${
|
471 | test.methodName
|
472 | }(path, [criteria]) must be a string or a number. Received boolean`
|
473 | );
|
474 | });
|
475 | });
|
476 | });
|
477 | });
|
478 | });
|
479 | });
|