1 | 'use strict';
|
2 |
|
3 | var 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 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | describe('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 |
|
218 | function 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 |
|
228 | function 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 |
|
250 | function 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 | }
|