UNPKG

6.82 kBPlain TextView Raw
1import {dir} from 'tmp';
2import {mkdirSync, rmdirSync, unlinkSync, writeFileSync} from 'fs';
3import {join} from 'path';
4import {expect} from 'chai';
5import {assertFileSystemContract, content, dirName, fileName, ignoredDir, ignoredFile} from './implementation-suite'
6import {EventsMatcher} from '../test-kit/drivers/events-matcher';
7import {LocalFileSystem, FileSystem, fileSystemEventNames} from '../src/nodejs';
8
9describe(`the local filesystem implementation`, () => {
10 let dirCleanup: () => void, rootPath: string, testPath: string;
11 let counter = 0;
12 let disposableFileSystem: LocalFileSystem;
13
14 before(done => {
15 dir({unsafeCleanup: true}, (_err, path, cleanupCallback) => {
16 dirCleanup = cleanupCallback;
17 rootPath = path;
18 done();
19 })
20 });
21 after(() => {
22 try {
23 dirCleanup();
24
25 } catch (e) {
26 console.log('cleanup error', e);
27 }
28 });
29 afterEach(() => {
30 // if beforeEach fails, disposableFileSystem can stay undefined
31 disposableFileSystem && disposableFileSystem.dispose();
32 });
33
34 function getFS() {
35 testPath = join(rootPath, 'fs_' + (counter++));
36 mkdirSync(testPath);
37 disposableFileSystem = new LocalFileSystem(
38 testPath,
39 [ignoredDir, ignoredFile]
40 );
41 return disposableFileSystem.init();
42 }
43
44 const eventMatcherOptions: EventsMatcher.Options = {
45 retries: 40,
46 interval: 50,
47 timeout: 2500,
48 noExtraEventsGrace: 150
49 };
50 assertFileSystemContract(getFS, eventMatcherOptions);
51 describe(`external changes`, () => {
52 let fs: FileSystem;
53 let matcher: EventsMatcher;
54 beforeEach(() => {
55 matcher = new EventsMatcher(eventMatcherOptions);
56 return getFS().then(newFs => {
57 fs = newFs;
58 matcher.track(fs.events, ...fileSystemEventNames);
59 });
60 });
61
62 it(`handles dir creation`, () => {
63 const path = join(testPath, dirName);
64 mkdirSync(path);
65 return expect(fs.loadDirectoryTree())
66 .to.eventually.have.property('children').eql([
67 {children: [], fullPath: dirName, name: dirName, type: 'dir'}
68 ]);
69 });
70
71 it(`handles dir deletion`, () => {
72 const path = join(testPath, dirName);
73 mkdirSync(path);
74 rmdirSync(path);
75 return expect(fs.loadDirectoryTree()).to.eventually.have.property('children').eql([]);
76 });
77
78 it(`handles file creation`, () => {
79 const path = join(testPath, fileName);
80 writeFileSync(path, content);
81 return expect(fs.loadTextFile(fileName)).to.eventually.equals(content);
82 });
83
84 it(`handles file deletion`, () => {
85 const path = join(testPath, fileName);
86 writeFileSync(path, content);
87 unlinkSync(path);
88 return expect(fs.loadTextFile(fileName)).to.eventually.be.rejected;
89 });
90
91 it(`handles file change`, () => {
92 const path = join(testPath, fileName);
93 const newContent = `_${content}`;
94 writeFileSync(path, content);
95 return matcher.expect([{type: 'fileCreated', fullPath: fileName, newContent: content}])
96 .then(() => {
97 writeFileSync(path, newContent);
98 return Promise.resolve();
99 })
100 .then(() => expect(fs.loadTextFile(fileName)).to.eventually.equals(newContent));
101 });
102
103 it(`ignores events from ignored dir`, () => {
104 mkdirSync(join(testPath, ignoredDir))
105 return matcher.expect([])
106 });
107
108 it(`ignores events from ignored file`, () => {
109 mkdirSync(join(testPath, dirName))
110 return matcher.expect([{type: 'directoryCreated', fullPath: dirName}])
111 .then(() => writeFileSync(join(testPath, ignoredFile), content))
112 .then(() => matcher.expect([]))
113 });
114
115 it(`loadDirectoryTree() ignores ignored folder and file`, () => {
116 const expectedStructure = {
117 name: '',
118 type: 'dir',
119 fullPath: '',
120 children: [{name: dirName, type: 'dir', fullPath: dirName, children: []}]
121 };
122 mkdirSync(join(testPath, ignoredDir))
123 mkdirSync(join(testPath, dirName))
124 writeFileSync(join(testPath, ignoredFile), content)
125 return expect(fs.loadDirectoryTree()).to.eventually.deep.equal(expectedStructure)
126 });
127
128 it(`loadDirectoryTree() ignores ignored folder with special characters`, () => {
129 const expectedStructure = {
130 name: '',
131 type: 'dir',
132 fullPath: '',
133 children: [{name: dirName, type: 'dir', fullPath: dirName, children: []}]
134 };
135 mkdirSync(join(testPath, ignoredDir))
136 mkdirSync(join(testPath, ignoredDir, 'name-with-dashes'))
137 mkdirSync(join(testPath, ignoredDir, 'name-with-dashes', '.name_starts_with_dot'))
138 mkdirSync(join(testPath, ignoredDir, 'name-with-dashes', '.name_starts_with_dot', '.name_starts_with_dot'))
139 mkdirSync(join(testPath, dirName))
140 return expect(fs.loadDirectoryTree()).to.eventually.deep.equal(expectedStructure)
141 });
142
143 it(`ignores events in dot-folders and files`, () => {
144 mkdirSync(join(testPath, ignoredDir));
145 mkdirSync(join(testPath, ignoredDir, `.${dirName}`));
146 writeFileSync(join(testPath, ignoredDir, `.${dirName}`, `.${fileName}`), content);
147
148 return matcher.expect([]);
149 });
150
151 it(`loading existed ignored file - fails`, function () {
152 mkdirSync(join(testPath, dirName))
153 writeFileSync(join(testPath, ignoredFile), content)
154
155 return expect(fs.loadTextFile(ignoredFile)).to.be.rejectedWith(Error)
156 });
157
158 it(`emits 'unexpectedError' if 'loadTextFile' rejected in watcher 'add' callback`, () => {
159 fs.loadTextFile = () => Promise.reject('go away!');
160 const path = join(testPath, fileName);
161 writeFileSync(path, content);
162 return matcher.expect([{type: 'unexpectedError'}]);
163 });
164
165 it(`emits 'unexpectedError' if 'loadTextFile' rejected in watcher 'change' callback`, () => {
166 return fs.saveFile(fileName, content)
167 .then(() => fs.loadTextFile = () => Promise.reject('go away!'))
168 .then(() => fs.saveFile(fileName, `_${content}`))
169 .then(() => matcher.expect([{type: 'unexpectedError'}]))
170 });
171 });
172});