UNPKG

12.1 kBJavaScriptView Raw
1var build = require('../lib/build'),
2 configLoader = require('../lib/config'),
3 Context = require('../lib/context'),
4 EventEmitter = require('events').EventEmitter,
5 fs = require('fs'),
6 fu = require('../lib/fileUtil'),
7 Libraries = require('../lib/libraries'),
8 plugins = require('../lib/plugin'),
9 sinon = require('sinon'),
10 stateMachine = require('../lib/state-machine');
11
12describe('state machine', function() {
13 var event,
14 context,
15 plugin;
16
17 beforeEach(function() {
18 this.stub(plugins, 'create', function() {
19 return plugin;
20 });
21
22 event = new EventEmitter();
23 plugin = {
24 initialize: function() {},
25 loadConfig: this.spy(function(context, callback) { callback(); }),
26 modes: function() { return ['foo', 'bar']; },
27 outputConfigs: function(context, callback) { callback(undefined, ['fu', 'gazi']); },
28 module: this.spy(function(context, callback) { callback(); }),
29 modeComplete: this.spy(function(context, callback) { callback(); })
30 };
31
32 var config = configLoader.create({
33 "packages": {
34 "web": {
35 "platforms": [ "web" ],
36 "combine": false
37 },
38 "native-home": {
39 "platforms": [ "android", "iphone" ],
40 "modules": [ "base", "home" ],
41 "combine": true
42 }
43 },
44 "modules": {
45 "home": {},
46 "base": {}
47 }
48 });
49 context = new Context({}, config, plugin, {}, event);
50 });
51
52 describe('#loadConfig', function() {
53 var isDir,
54 config;
55 beforeEach(function() {
56 var test = this;
57
58 isDir = true;
59 config = {
60 modules: { 'foo': {} }
61 };
62 this.stub(fu, 'ensureDirs', function(path, callback) {
63 test.stub(fs, 'statSync', function() {
64 return {
65 isDirectory: function() { return isDir; }
66 };
67 });
68 callback();
69 });
70 });
71
72 it('should create context', function() {
73 stateMachine.loadConfig(config, event, {outdir: 'foo'}, function(err, context) {
74 should.not.exist(err);
75 should.exist(context);
76 });
77 plugin.loadConfig.should.have.been.calledOnce;
78 });
79 it('should emit config event', function() {
80 var spy = this.spy(function(_config) {
81 _config.attributes.should.eql(config);
82 });
83 event.on('config', spy);
84 stateMachine.loadConfig(config, event, {outdir: 'foo'}, function(err, context) {});
85 spy.should.have.been.calledOnce;
86 });
87 it('should emit logging event', function() {
88 var spy = this.spy(function(config) {
89 config.should.match(/Finalized config/);
90 });
91 event.on('log', spy);
92 stateMachine.loadConfig(config, event, {outdir: 'foo', verbose: true}, function(err, context) {});
93 spy.should.have.been.called;
94 });
95 it('should handle thrown errors', function() {
96 plugin.initialize = function() {
97 throw new Error('FAILED!');
98 };
99 stateMachine.loadConfig(config, event, {}, function(err) {
100 err.should.match(/FAILED!/);
101 });
102 });
103 it('should handle library init errors', function() {
104 this.stub(Libraries.prototype, 'initialize', function(context, callback) { callback(new Error('FAILED!')); });
105 stateMachine.loadConfig(config, event, {}, function(err) {
106 err.should.match(/FAILED!/);
107 });
108 });
109 it('should handle loadConfig errors', function() {
110 plugin.loadConfig = function(context, callback) { callback(new Error('FAILED!')); };
111 stateMachine.loadConfig(config, event, {}, function(err) {
112 err.should.match(/FAILED!/);
113 });
114 });
115 it('should handle missing directory error', function() {
116 stateMachine.loadAndInitDir(config, event, {}, function(err, context) {
117 err.should.match(/Output must be defined/);
118 });
119 });
120 it('should handle directory errors', function() {
121 isDir = false;
122
123 stateMachine.loadAndInitDir(config, event, {outdir: 'foo'}, function(err, context) {
124 err.should.match(/Output must be a directory/);
125 });
126 });
127 });
128
129 describe('#loadPackages', function() {
130 beforeEach(function() {
131 this.stub(stateMachine, 'loadPlatform');
132 });
133 function built() {
134 return stateMachine.loadPlatform.args.map(function(arg) {
135 return arg[0].package + ':' + arg[0].platform + ':' + arg[0].module;
136 });
137 }
138
139 it('should iterate over all platforms and packages', function() {
140 stateMachine.loadPackages(context, undefined, function() {});
141
142 built().should.eql(['web:web:undefined', 'native-home:android:undefined', 'native-home:iphone:undefined']);
143 });
144 it('should iterate over platforms and packages', function() {
145 stateMachine.loadPackages(context, 'web', function() {});
146
147 built().should.eql(['web:web:undefined']);
148 });
149
150 it('should accept string module name', function() {
151 stateMachine.loadPackages(context, 'native-home', 'home', function() {});
152
153 built().should.eql(['native-home:android:home', 'native-home:iphone:home']);
154 });
155 it('should accept array of module names', function() {
156 stateMachine.loadPackages(context, 'native-home', ['base', 'home'], function() {});
157
158 built().should.eql([
159 'native-home:android:base', 'native-home:iphone:base',
160 'native-home:android:home', 'native-home:iphone:home'
161 ]);
162 });
163 it('should treat empty array as all modules', function() {
164 stateMachine.loadPackages(context, 'native-home', [], function() {});
165
166 built().should.eql(['native-home:android:undefined', 'native-home:iphone:undefined']);
167 });
168
169 it('should accept package name via hash', function() {
170 stateMachine.loadPackages(context, {package: 'web'}, function() {});
171
172 built().should.eql(['web:web:undefined']);
173 });
174 });
175 describe('#loadPlatform', function() {
176 beforeEach(function() {
177 this.stub(stateMachine, 'loadMode');
178 });
179 function built() {
180 return stateMachine.loadMode.args.map(function(arg) {
181 return arg[0];
182 });
183 }
184
185 it('should iterate over all modes', function() {
186 stateMachine.loadPlatform(context, undefined, function() {});
187
188 built().should.eql(['foo', 'bar']);
189 });
190 it('should exec a specific mode', function() {
191 context.mode = 'scripts';
192 stateMachine.loadPlatform(context, function() {});
193
194 built().should.eql(['scripts']);
195 });
196 });
197
198 describe('#loadMode', function() {
199 var spy;
200 beforeEach(function() {
201 spy = this.spy();
202
203 this.stub(stateMachine, 'buildModule');
204 context.package = 'native-home';
205 });
206 function built() {
207 return spy.getCall(0).args[1].map(function(context) {
208 return context.fileConfig;
209 });
210 }
211
212 it('should build modules', function() {
213 stateMachine.loadMode('foo', context, spy);
214 built().should.eql(['fu', 'gazi']);
215 });
216
217 it('should use passed fileConfig', function() {
218 context.fileConfig = 'bar';
219 stateMachine.loadMode('foo', context, spy);
220 built().should.eql(['bar']);
221 });
222
223 it('should handle outputConfigs error', function() {
224 plugin.outputConfigs = function(context, callback) { callback(new Error('FAILED')); };
225 stateMachine.loadMode('foo', context, function(err) {
226 err.should.match(/FAILED/);
227 });
228 });
229 });
230
231 describe('#buildContexts', function() {
232 var spy;
233 beforeEach(function() {
234 spy = this.spy();
235
236 this.stub(stateMachine, 'buildModule');
237 context.package = 'native-home';
238 });
239 function built() {
240 return stateMachine.buildModule.args.map(function(arg) {
241 return arg[0].fileConfig + ':' + arg[0].module;
242 });
243 }
244
245 it('should build modules', function() {
246 var fu = context.clone(),
247 gazi = context.clone();
248
249 fu.fileConfig = 'fu';
250 gazi.fileConfig = 'gazi';
251 stateMachine.buildContexts([fu, gazi], function() {});
252 built().should.eql(['fu:home', 'fu:base', 'gazi:home', 'gazi:base']);
253 });
254
255 it('should use passed fileConfig', function() {
256 var bar = context.clone();
257 bar.fileConfig = 'bar';
258 stateMachine.buildContexts([bar], function() {});
259 built().should.eql(['bar:home', 'bar:base']);
260 });
261 it('should build passed modules', function() {
262 var bar = context.clone();
263 bar.fileConfig = 'bar';
264 bar.module = 'base';
265 stateMachine.buildContexts([bar], function() {});
266 built().should.eql(['bar:base']);
267 });
268
269 it('should handle buildModule error', function() {
270 stateMachine.buildModule.restore();
271 this.stub(stateMachine, 'buildModule', function(context, callback) { callback(new Error('FAILED')); });
272
273 stateMachine.buildContexts([context.clone()], function(err) {
274 err.should.match(/FAILED/);
275 });
276 });
277
278 it('should call modeComplete', function() {
279 stateMachine.buildModule.restore();
280 this.stub(stateMachine, 'buildModule', function(context, callback) { callback(); });
281
282 var bar = context.clone();
283 bar.fileConfig = 'bar';
284 bar.module = 'base';
285 stateMachine.buildContexts([bar], function() {});
286 plugin.modeComplete.should.have.been.calledOnce;
287 });
288 });
289
290 describe('#buildModule', function() {
291 beforeEach(function() {
292 this.stub(stateMachine, 'processResources');
293 });
294 function built() {
295 return stateMachine.processResources.args.map(function(arg) {
296 return arg[1];
297 });
298 }
299
300 it('should error on missing module', function() {
301 context.module = 'fugazi';
302 stateMachine.buildModule(context, function(err) {
303 err.should.match(/Unable to find module "fugazi"/);
304 });
305 });
306 it('should iterate over resources', function() {
307 var resources = ['foo', 'bar'];
308 this.stub(build, 'loadResources', function(context, callback) { callback(undefined, resources); });
309
310 context.module = 'home';
311 stateMachine.buildModule(context, function() {});
312
313 stateMachine.processResources.should.have.been.calledWith(context, resources);
314 });
315 it('should use passed resource', function() {
316 var resources = ['foo', 'bar'];
317 this.stub(build, 'loadResources', function(context, callback) { callback(new Error('FAILED')); });
318
319 context.module = 'home';
320 context.resource = 'baz';
321 stateMachine.buildModule(context, function() {});
322
323 stateMachine.processResources.should.have.been.calledWith(context, ['baz']);
324 });
325 it('should handle load error', function() {
326 var resources = ['foo', 'bar'];
327 this.stub(build, 'loadResources', function(context, callback) { callback(new Error('FAILED')); });
328
329 context.module = 'home';
330 stateMachine.buildModule(context, function(err) {
331 err.should.match(/FAILED/);
332 });
333
334 stateMachine.processResources.should.not.have.been.called;
335 });
336 });
337 describe('#processResources', function() {
338 it('should call module plugins', function() {
339 this.stub(build, 'processResources', function(resources, context, callback) {
340 callback(undefined, resources);
341 });
342
343 var resources = ['foo', 'bar'],
344 stub = this.spy();
345 stateMachine.processResources(context, resources, stub);
346
347 plugin.module.should.have.been.calledOnce;
348 plugin.module.args[0][0].moduleResources.should.equal(resources);
349
350 stub.should.have.been.calledOnce;
351 stub.should.have.been.calledWith(undefined);
352 });
353 it('should handle errors', function() {
354 this.stub(build, 'processResources', function(resources, context, callback) {
355 callback(new Error('FAILED!'), resources);
356 });
357
358 var resources = ['foo', 'bar'],
359 stub = this.spy();
360 stateMachine.processResources(context, resources, stub);
361
362 plugin.module.should.not.have.been.called;
363
364 stub.should.have.been.calledOnce;
365 stub.should.have.been.calledWith(sinon.match.instanceOf(Error));
366 });
367 });
368});