UNPKG

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