UNPKG

9.54 kBJavaScriptView Raw
1'use strict';
2
3var assert = require('chai').assert,
4 UTIL = require('util'),
5 PATH = require('path'),
6 Q = require('q'),
7 _ = require('lodash/dist/lodash.underscore'),
8 QFS = require('q-io/fs'),
9
10 BEM = require('..'),
11
12 projectPath = PATH.resolve(__dirname, 'data/make/project'),
13 referencePath = PATH.resolve(__dirname, 'data/make/reference-result'),
14 buildPath = PATH.resolve(__dirname, '../test-make-temp');
15
16/**
17 * Mocha BDD interface.
18 *
19 * @name describe @function
20 * @name it @function
21 * @name before @function
22 * @name after @function
23 * @name beforeEach @function
24 * @name afterEach @function
25 */
26
27describe('bem', function() {
28 describe('make', function() {
29
30 before(function(done){
31 prepareProject()
32 .done(done);
33 });
34
35 it('completes successfully', function(done) {
36 this.timeout(0);
37
38 BEM.api.make({root: buildPath, verbosity: 'error'})
39 .then(done)
40 .fail(done)
41 .done();
42 });
43
44 it('creates proper artifacts', function() {
45 return assert.eventually.isNull(
46 BEM.util.exec(
47 UTIL.format(
48 'find %s -type f -exec diff -q {} %s/{} \\; 2>&1',
49 '.',
50 PATH.relative(referencePath, buildPath)),
51 {cwd: referencePath},
52 true)
53 );
54 });
55
56 it('does not rebuild anything on next build with no changes made to the files', function(done) {
57 this.timeout(0);
58
59 collectTimestamps(buildPath)
60 .then(function(timestamps) {
61 return BEM.api.make({root: buildPath, verbosity: 'error'})
62 .then(function() {
63 return collectTimestamps(buildPath);
64 })
65 .then(function(newTimestamps){
66 var mismatches = Object.keys(newTimestamps)
67 .filter(function(ts) {
68 return newTimestamps[ts].getTime() !== timestamps[ts].getTime();
69 });
70
71 if (mismatches.length > 0) throw new Error('There are modified files:\n' + mismatches.join('\n'));
72
73 done();
74 });
75 })
76 .fail(done)
77 .done();
78 });
79
80 it('rebuilds missing artifacts on consequent build', function(done) {
81 this.timeout(0);
82
83 Q.all(['pages/example/example.html',
84 'pages/example/example.css',
85 'pages/client/client.html',
86 'pages/client/client.css'].map(function(file) {
87 return QFS.remove(PATH.join(buildPath, file));
88 }))
89 .then(function() {
90 return BEM.api.make({root: buildPath, verbosity: 'error'});
91 })
92 .then(function() {
93 return BEM.util.exec(
94 UTIL.format(
95 'find %s -type f -exec diff -q {} %s/{} \\; 2>&1',
96 '.',
97 PATH.relative(referencePath, buildPath)),
98 {cwd: referencePath},
99 true);
100 })
101 .then(function(result) {
102 done(result && new Error(result));
103 })
104 .fail(done)
105 .done();
106 });
107
108 it('clean removes build artifacts', function(done) {
109 this.timeout(0);
110
111 BEM.api.make({root: buildPath, verbosity: 'error', method: 'clean'})
112 .then(function() {
113 return Q.all([
114 dirHasOnly(PATH.join(buildPath, 'pages/example'), ['example.bemjson.js']),
115 dirHasOnly(PATH.join(buildPath, 'pages/client'), ['client.bemjson.js'])
116 ])
117 .spread(function(example, client) {
118 if (!(example && client)) throw new Error('build artifacts exist');
119
120 done();
121 });
122 })
123 .fail(done)
124 .done();
125 });
126
127 it('builds two targets', function(done) {
128 this.timeout(0);
129
130 prepareProject()
131 .then(function(){
132 return BEM.api.make({
133 root: buildPath,
134 verbosity: 'error'
135 },
136 {
137 targets: ['pages/example/_example.css', 'pages/client/client.html']
138 });
139 })
140 .then(function(){
141 return Q.all([
142 dirHasOnly(
143 PATH.join(buildPath, 'pages/example'),
144 ['example.bemjson.js', '_example.css', 'example.bemdecl.js', 'example.css',
145 'example.deps.js']),
146 dirHasOnly(
147 PATH.join(buildPath, 'pages/client'),
148 ['client.bemjson.js', 'client.bemhtml.js', 'client.bemdecl.js',
149 'client.deps.js', 'client.html']),
150 dirHasOnly(
151 PATH.join(buildPath, '.bem/cache/pages/example'),
152 ['example.css.meta.js', 'example.deps.js.meta.js']
153 ),
154 dirHasOnly(
155 PATH.join(buildPath, '.bem/cache/pages/client'),
156 ['client.deps.js.meta.js', 'client.bemhtml.meta.js']
157 )
158 ])
159 .spread(function(example, client) {
160 if (!(example && client)) throw new Error('set of build artifacts differs from expected');
161 });
162 })
163 .then(function() {
164 return BEM.util.exec(
165 UTIL.format(
166 'diff -rq %s %s 2>&1 | grep -v ^O; true',
167 '.',
168 PATH.relative(referencePath, buildPath)),
169 {cwd: referencePath},
170 true);
171 })
172 .then(function(result) {
173 done(result && new Error(result));
174 })
175 .fail(done)
176 .done();
177 });
178
179 it('invalidates deps when bemdecl is modified', function(done) {
180 this.timeout(0);
181
182 prepareProject()
183 .then(function() {
184 BEM.api.make({root: buildPath, verbosity: 'error'})
185 .then(function() {
186 return BEM.util.exec(UTIL.format('cp %s %s',
187 PATH.resolve(__dirname, 'data/make/misc/changed.bemjson.js'),
188 PATH.resolve(buildPath, 'pages/example/example.bemjson.js')))
189
190 .then(function() {
191 return BEM.api.make({root: buildPath, verbosity: 'error'},
192 {
193 targets: ['pages/example/example.deps.js']
194 });
195 })
196 .then(function() {
197 return Q.all([
198 QFS.lastModified(PATH.join(buildPath, 'pages/example/example.bemjson.js')),
199 QFS.lastModified(PATH.join(buildPath, 'pages/example/example.deps.js'))
200 ])
201 .spread(function(bemjson, deps) {
202 assert.operator(deps.getTime(), '>=', bemjson.getTime());
203 });
204 });
205
206 })
207 .then(done)
208 .fail(done)
209 .done();
210
211 });
212 });
213
214 });
215});
216
217
218function prepareProject() {
219 return QFS.exists(buildPath)
220 .then(function(exists) {
221 return exists && BEM.util.exec(UTIL.format('rm -rf %s', buildPath));
222 })
223 .then(function() {
224 return BEM.util.exec(UTIL.format('cp -r %s %s', projectPath, buildPath));
225 });
226}
227
228function collectTimestamps(root) {
229 var list = {};
230
231 return QFS.listTree(root, function(path, stat) {
232 return PATH.basename(path)[0] !== '.' &&
233 Q.when(stat.isFile(), function(isFile) {
234 if (isFile) {
235 return QFS.lastModified(path)
236 .then(function(modified) {
237 list[path] = modified;
238 return true;
239 });
240 }
241
242 return false;
243 });
244 })
245 .then(function() {
246 return list;
247 });
248}
249
250function dirHasOnly(dir, files) {
251 return BEM.util.getFilesAsync(dir)
252 .then(function(dirFiles) {
253 return dirFiles.length === files.length &&
254 _.union(files, dirFiles).length === files.length;
255 });
256}