UNPKG

30 kBJavaScriptView Raw
1var _ = require('underscore'),
2 assert = require('assert'),
3 bower = require('bower'),
4 EventEmitter = require('events').EventEmitter,
5 fu = require('../lib/fileUtil'),
6 fs = require('fs'),
7 lib = require('./lib'),
8 watch = require('./lib/watch');
9
10describe('mixins', function() {
11 function stripper(resources) {
12 // Drop the mixin reference to make testing easier
13 _.each(resources, function(resource) { delete resource.mixin; delete resource.library; });
14 return resources;
15 }
16
17 describe('loading', function() {
18 var readFileSync = fs.readFileSync,
19 statSync = fs.statSync,
20 read = [];
21 beforeEach(function() {
22 read = [];
23 fu.lookupPath('');
24 });
25 beforeEach(function() {
26 this.stub(fs, 'readFileSync', function(path) {
27 if (/library.*\.json$/.test(path)) {
28 read.push(path);
29 return '{"name": "loading", "foo": "bar"}';
30 } else {
31 return readFileSync.apply(this, arguments);
32 }
33 });
34 this.stub(fs, 'statSync', function(path) {
35 if (/library/.test(path)) {
36 return {isDirectory: function() { return !/\.json$/.test(path); }};
37 } else {
38 return statSync.apply(this, arguments);
39 }
40 });
41 });
42
43 it('should load direct mixin config file references', function(done) {
44 lib.mixinExec({}, ['library/file.json'], function(libraries, context) {
45 read.should.eql(['library/file.json']);
46
47 libraries.configs.length.should.eql(1);
48 libraries.configs[0].root.should.equal('library/');
49 context.config.attributes.foo.should.equal('bar');
50
51 done();
52 });
53 });
54
55 it('should load mixin config directory references', function(done) {
56 lib.mixinExec({}, ['library'], function(libraries, context) {
57 read.should.eql(['library/lumbar.json']);
58
59 libraries.configs.length.should.eql(1);
60 libraries.configs[0].root.should.equal('library/');
61 context.config.attributes.foo.should.equal('bar');
62
63 done();
64 });
65 });
66 });
67
68 describe('config', function() {
69 it('should mixin undefined modules', function(done) {
70 var modules = {
71 'baz': 'bat',
72 'foo': 'bah'
73 };
74
75 lib.mixinExec(undefined, [{name: 'config', modules: modules}], {modules: {'foo': 'bar'}}, function(libraries, context) {
76 context.config.moduleList().should.eql(['foo', 'baz']);
77 context.config.attributes.modules.foo.should.eql('bar');
78 context.config.attributes.modules.baz.should.eql('bat');
79
80 done();
81 });
82 });
83 it('should update paths for mixin modules', function(done) {
84 var modules = {
85 'baz': {
86 'scripts': ['foo.js'],
87 'styles': ['foo.css'],
88 'static': ['foo.html'],
89 }
90 };
91
92 lib.mixinExec(undefined, [{name: 'update', root: 'bar', modules: modules}], {modules: {'foo': 'bar'}}, function(libraries, context) {
93 context.config.moduleList().should.eql(['foo', 'baz']);
94
95 var module = context.config.attributes.modules.baz;
96 stripper(module.scripts).should.eql([{src: 'bar/foo.js'}]);
97 stripper(module.styles).should.eql([{src: 'bar/foo.css'}]);
98 stripper(module.static).should.eql([{src: 'bar/foo.html'}]);
99
100 done();
101 });
102 });
103 it('should apply mixins for mixin modules', function(done) {
104 var mixins = {
105 'baz': {
106 'scripts': ['foo.js'],
107 'styles': ['foo.css'],
108 'static': ['foo.html'],
109 }
110 };
111 var modules = {
112 'bar': {
113 'mixins': ['baz']
114 }
115 };
116
117 lib.mixinExec(undefined, [{name: 'apply', root: 'bar', modules: modules, mixins: mixins}], {modules: {'foo': 'bar'}}, function(libraries, context) {
118 context.config.moduleList().should.eql(['foo', 'bar']);
119
120 var module = context.config.attributes.modules.bar;
121 stripper(module.scripts).should.eql([{src: 'bar/foo.js'}]);
122 stripper(module.styles).should.eql([{src: 'bar/foo.css'}]);
123 stripper(module.static).should.eql([{src: 'bar/foo.html'}]);
124
125 done();
126 });
127 });
128 it('should apply mixins from mixin modules', function(done) {
129 var mixinModules = {
130 'baz': {
131 'scripts': ['foo.js'],
132 'styles': ['foo.css'],
133 'static': ['foo.html'],
134 }
135 };
136 var modules = {
137 'bar': {
138 'mixins': ['baz'],
139 'scripts': ['baz.js']
140 }
141 };
142
143 lib.mixinExec(undefined, [{name: 'apply', root: 'bar', modules: mixinModules}], {modules: modules}, function(libraries, context) {
144 context.config.moduleList().should.eql(['bar', 'baz']);
145
146 var module = context.config.attributes.modules.bar;
147 stripper(module.scripts).should.eql([{src: 'bar/foo.js'}, 'baz.js']);
148 stripper(module.styles).should.eql([{src: 'bar/foo.css'}]);
149 stripper(module.static).should.eql([{src: 'bar/foo.html'}]);
150
151 done();
152 });
153 });
154
155 it('should allow mixin module suppression', function(done) {
156 var mixinModules = {
157 'baz': {
158 'scripts': ['foo.js'],
159 'styles': ['foo.css'],
160 'static': ['foo.html'],
161 }
162 };
163 var modules = {
164 'baz': false,
165 'bar': {
166 'scripts': ['baz.js']
167 }
168 };
169
170 lib.mixinExec(undefined, [{name: 'supress', root: 'bar', modules: mixinModules}], {modules: modules}, function(libraries, context) {
171 context.config.moduleList().should.eql(['bar']);
172
173 var module = context.config.attributes.modules.bar;
174 stripper(module.scripts).should.eql(['baz.js']);
175
176 done();
177 });
178 });
179 });
180
181 describe('mixin namespace', function() {
182 it('should lookup default mixin', function(done) {
183 var mixinModules = {
184 'baz': {
185 'scripts': ['foo.js']
186 }
187 };
188 var modules = {
189 'bar': {
190 'mixins': ['baz'],
191 'scripts': ['baz.js']
192 }
193 };
194
195 lib.mixinExec(undefined, [{name: 'bar', root: 'bar', modules: mixinModules}], {modules: modules}, function(libraries, context) {
196 context.config.moduleList().should.eql(['bar', 'baz']);
197
198 var module = context.config.attributes.modules.bar;
199 stripper(module.scripts).should.eql([{src: 'bar/foo.js'}, 'baz.js']);
200
201 done();
202 });
203 });
204 it('should lookup mixin by container', function(done) {
205 var mixin1 = {
206 root: '1',
207 name: '1',
208 'modules': {
209 'baz': {
210 'scripts': ['foo1.js']
211 }
212 }
213 };
214 var mixin2 = {
215 root: '2',
216 name: '2',
217 'modules': {
218 'baz': {
219 'scripts': ['foo2.js']
220 }
221 }
222 };
223 var modules = {
224 'bar': {
225 'mixins': [{name: 'baz', container: '2'}],
226 'scripts': ['baz.js']
227 }
228 };
229
230 lib.mixinExec(undefined, [mixin1, mixin2], {modules: modules}, function(libraries, context) {
231 if (libraries.err) {
232 throw libraries.err;
233 }
234
235 context.config.moduleList().should.eql(['bar', 'baz']);
236
237 var module = context.config.attributes.modules.bar;
238 stripper(module.scripts).should.eql([{src: '2/foo2.js'}, 'baz.js']);
239
240 module = context.config.attributes.modules.baz;
241 stripper(module.scripts).should.eql([{src: '1/foo1.js'}]);
242
243 done();
244 });
245 });
246 it('should lookup mixin by library', function(done) {
247 var mixin1 = {
248 root: '1',
249 name: '1',
250 'modules': {
251 'baz': {
252 'scripts': ['foo1.js']
253 }
254 }
255 };
256 var mixin2 = {
257 root: '2',
258 name: '2',
259 'modules': {
260 'baz': {
261 'scripts': ['foo2.js']
262 }
263 }
264 };
265 var modules = {
266 'bar': {
267 'mixins': [{name: 'baz', library: '2'}],
268 'scripts': ['baz.js']
269 }
270 };
271
272 lib.mixinExec(undefined, [mixin1, mixin2], {modules: modules}, function(libraries, context) {
273 if (libraries.err) {
274 throw libraries.err;
275 }
276
277 context.config.moduleList().should.eql(['bar', 'baz']);
278
279 var module = context.config.attributes.modules.bar;
280 stripper(module.scripts).should.eql([{src: '2/foo2.js'}, 'baz.js']);
281
282 module = context.config.attributes.modules.baz;
283 stripper(module.scripts).should.eql([{src: '1/foo1.js'}]);
284
285 done();
286 });
287 });
288 it('should fail if a mixin library does not define a name', function(done) {
289 var mixin1 = {
290 root: '1',
291 'modules': {
292 'baz': {'scripts': ['foo1.js']}
293 }
294 };
295 var modules = {
296 'bar': {'scripts': ['baz.js']}
297 };
298
299 lib.mixinExec(undefined, [mixin1], {modules: modules}, function(libraries) {
300 libraries.err.should.be.an.instanceof(Error);
301 libraries.err.message.should.match(/missing a name\./);
302
303 done();
304 });
305 });
306 it('should fail if multiple mixins are defined', function(done) {
307 var mixin1 = {
308 root: '1',
309 name: '1',
310 'modules': {
311 'baz': {
312 'scripts': ['foo1.js']
313 }
314 }
315 };
316 var mixin2 = {
317 root: '2',
318 name: '2',
319 'modules': {
320 'baz': {
321 'scripts': ['foo2.js']
322 }
323 }
324 };
325 var modules = {
326 'bar': {
327 'mixins': [{name: 'baz'}],
328 'scripts': ['baz.js']
329 }
330 };
331
332 lib.mixinExec(undefined, [mixin1, mixin2], {modules: modules}, function(libraries) {
333 libraries.err.should.be.an.instanceof(Error);
334 libraries.err.message.should.match(/Duplicate mixins found for "baz"/);
335
336 done();
337 });
338 });
339 it('should fail if no mixin from the given library is defined', function(done) {
340 var mixin1 = {
341 root: '1',
342 name: '1',
343 'modules': {
344 'baz': {
345 'scripts': ['foo1.js']
346 }
347 }
348 };
349 var modules = {
350 'bar': {
351 'mixins': [{name: 'baz', library: 2}],
352 'scripts': ['baz.js']
353 }
354 };
355
356 lib.mixinExec(undefined, [mixin1], {modules: modules}, function(libraries) {
357 libraries.err.should.be.an.instanceof(Error);
358 libraries.err.message.should.match(/Mixin named "baz" not found in library "2"/);
359
360 done();
361 });
362 });
363 it('should select mixin if a mixin has both mixins and module of the same name', function(done) {
364 var mixin1 = {
365 root: '1',
366 name: '1',
367 'modules': {
368 'baz': {
369 'scripts': ['foo1.js']
370 }
371 },
372 'mixins': {
373 'baz': {
374 'scripts': ['foo2.js']
375 }
376 }
377 };
378 var modules = {
379 'bar': {
380 'mixins': [{name: 'baz'}],
381 'scripts': ['baz.js']
382 }
383 };
384
385 lib.mixinExec(undefined, [mixin1], {modules: modules}, function(libraries, context) {
386 context.config.moduleList().should.eql(['bar', 'baz']);
387
388 var module = context.config.attributes.modules.bar;
389 stripper(module.scripts).should.eql([{src: '1/foo2.js'}, 'baz.js']);
390
391 module = context.config.attributes.modules.baz;
392 stripper(module.scripts).should.eql([{src: '1/foo1.js'}]);
393
394 done();
395 });
396 });
397 });
398
399 describe('mixin file references', function() {
400 it('should update paths for mixin modules', function(done) {
401 var mixin = {
402 name: 'foo',
403 root: 'bar'
404 };
405 var modules = {
406 'foo': {
407 scripts: [
408 {src: 'bar.js', library: 'foo'}
409 ]
410 }
411 };
412
413 lib.mixinExec(undefined, [mixin], {modules: modules}, function(libraries, context) {
414 context.config.moduleList().should.eql(['foo']);
415
416 var module = context.config.attributes.modules.foo;
417 stripper(module.scripts).should.eql([{src: 'bar/bar.js'}]);
418
419 done();
420 });
421 });
422 it('should update paths for nested mixin modules', function(done) {
423 var mixins = [
424 {
425 name: 'foo',
426 mixins: {
427 foo: {
428 scripts: [
429 {src: 'bar.js', library: 'bar'}
430 ]
431 }
432 },
433 root: 'foo'
434 },
435 {
436 name: 'bar',
437 root: 'bar'
438 }
439 ];
440 var modules = {
441 'foo': {
442 mixins: ['foo']
443 }
444 };
445
446 lib.mixinExec(undefined, mixins, {modules: modules}, function(libraries, context) {
447 context.config.moduleList().should.eql(['foo']);
448
449 var module = context.config.attributes.modules.foo;
450 stripper(module.scripts).should.eql([{src: 'bar/bar.js'}]);
451
452 done();
453 });
454 });
455 it('should throw an error if a mixin is not found', function(done) {
456 var mixin = {
457 name: 'foo',
458 root: 'bar'
459 };
460 var modules = {
461 'foo': {
462 scripts: [
463 {src: 'bar.js', library: 'bar'}
464 ]
465 }
466 };
467
468 lib.mixinExec(undefined, [mixin], {modules: modules}, function(libraries) {
469 (libraries.err + '').should.match(/mixin "bar" not found/i);
470
471 done();
472 });
473 });
474 });
475
476 describe('bower file references', function() {
477 beforeEach(function() {
478 require('bower').config.directory = 'bower_components';
479 });
480
481 it('should update paths for bower packages', function(done) {
482 var mixin = {
483 name: 'foo',
484 root: 'bar'
485 };
486 var modules = {
487 'foo': {
488 scripts: [
489 {src: 'bar.js', bower: 'foo'}
490 ]
491 }
492 };
493
494 lib.mixinExec(undefined, [mixin], {modules: modules}, function(libraries, context) {
495 context.config.moduleList().should.eql(['foo']);
496
497 var module = context.config.attributes.modules.foo;
498 stripper(module.scripts).should.eql([{src: 'bower_components/foo/bar.js', bower: 'foo', bowerResolved: true}]);
499
500 done();
501 });
502 });
503 it('should give priority to bower path over module path', function(done) {
504 var mixins = [
505 {
506 name: 'foo',
507 mixins: {
508 foo: {
509 scripts: [
510 {src: 'bar.js', bower: 'foo'}
511 ]
512 }
513 },
514 root: 'foo'
515 },
516 {
517 name: 'bar',
518 root: 'bar'
519 }
520 ];
521 var modules = {
522 'foo': {
523 mixins: ['foo']
524 }
525 };
526
527 lib.mixinExec(undefined, mixins, {modules: modules}, function(libraries, context) {
528 context.config.moduleList().should.eql(['foo']);
529
530 var module = context.config.attributes.modules.foo;
531 stripper(module.scripts).should.eql([{src: 'bower_components/foo/bar.js', bower: 'foo', bowerResolved: true}]);
532
533 done();
534 });
535 });
536 });
537
538 describe('modules', function() {
539 it('should mixin module attributes', function(done) {
540 var module = {
541 mixins: ['mixin1', 'mixin2'],
542 bat: 3
543 };
544
545 var mixins = {
546 mixin1: { foo: 1, baz: 1, bat: 1 },
547 mixin2: { bar: 2, baz: 2, bat: 2 }
548 };
549
550 lib.mixinExec(module, [{name: 'attr', mixins: mixins}], function() {
551 assert.equal(module.foo, 1, 'foo should be written');
552 assert.equal(module.bar, 2, 'bar should be written');
553 assert.equal(module.baz, 2, 'baz should be overwritten');
554 assert.equal(module.bat, 3, 'bat should not be overwritten');
555
556 assert.deepEqual(mixins.mixin1, {foo: 1, baz: 1, bat: 1});
557 assert.deepEqual(mixins.mixin2, {bar: 2, baz: 2, bat: 2});
558
559 done();
560 });
561 });
562
563 it('should merge routes', function(done) {
564 var module = {
565 mixins: ['mixin1', 'mixin2'],
566 routes: { bat: 3 }
567 };
568
569 var mixins = {
570 mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
571 mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
572 };
573
574 lib.mixinExec(module, [{name: 'routes', mixins: mixins}], function() {
575 assert.equal(module.routes.foo, 1);//, 'foo should be written');
576 assert.equal(module.routes.bar, 2, 'bar should be written');
577 assert.equal(module.routes.baz, 2, 'baz should be overwritten');
578 assert.equal(module.routes.bat, 3, 'bat should not be overwritten');
579
580 assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
581 assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});
582
583 done();
584 });
585 });
586
587 it('should merge routes without modification', function(done) {
588 var module = {
589 mixins: ['mixin1', 'mixin2']
590 };
591
592 var mixins = {
593 mixin1: {routes: { foo: 1, baz: 1, bat: 1 }},
594 mixin2: {routes: { bar: 2, baz: 2, bat: 2 }}
595 };
596
597 lib.mixinExec(module, [{name: 'routes', mixins: mixins}], function() {
598 assert.equal(module.routes.foo, 1, 'foo should be written');
599 assert.equal(module.routes.bar, 2, 'bar should be written');
600 assert.equal(module.routes.baz, 2, 'baz should be overwritten');
601 assert.equal(module.routes.bat, 2, 'bat should not be overwritten');
602
603 assert.deepEqual(mixins.mixin1.routes, {foo: 1, baz: 1, bat: 1});
604 assert.deepEqual(mixins.mixin2.routes, {bar: 2, baz: 2, bat: 2});
605
606 done();
607 });
608 });
609
610 it('should merge file arrays', function(done) {
611 var module = {
612 mixins: ['mixin1', 'mixin2'],
613 scripts: [ {src: 'foo0', global: true }, {src: 'foo0.1', global: true}, 'bar0.1', 'bar0.2' ],
614 styles: [ 'foo0', 'bar0' ]
615 };
616
617 var mixins = [
618 {
619 name: '1',
620 root: 'mixin1/',
621 mixins: {
622 mixin1: {
623 scripts: [
624 {src: 'foo1.1', global: true},
625 {src: 'foo1.2', global: true},
626 'bar1.1',
627 'bar1.2',
628 {dir: 'dir!'},
629 {notAFile: true}
630 ],
631 static: [ 'baz1.1', 'baz1.2' ]
632 }
633 }
634 },
635 {
636 name: '2',
637 root: 'mixin2/',
638 mixins: {
639 mixin2: {
640 scripts: [ {src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2'],
641 styles: [ 'foo2', 'bar2' ],
642 static: [ 'baz2.1', 'baz2.2' ]
643 }
644 }
645 }
646 ];
647
648 lib.mixinExec(module, mixins, function(libraries) {
649 if (libraries.err) {
650 throw libraries.err;
651 }
652
653 mixins = libraries.mixins;
654
655 module.scripts.should.eql([
656 {src: 'mixin1/foo1.1', global: true, library: mixins.mixin1[0]}, {src: 'mixin1/foo1.2', global: true, library: mixins.mixin1[0]},
657 {src: 'mixin2/foo2.1', global: true, library: mixins.mixin2[0]}, {src: 'mixin2/foo2.2', global: true, library: mixins.mixin2[0]},
658 {src: 'foo0', global: true }, {src: 'foo0.1', global: true},
659 {src: 'mixin1/bar1.1', library: mixins.mixin1[0]}, {src: 'mixin1/bar1.2', library: mixins.mixin1[0]},
660 {dir: 'mixin1/dir!', library: mixins.mixin1[0]}, {notAFile: true, library: mixins.mixin1[0]},
661 {src: 'mixin2/bar2.1', library: mixins.mixin2[0]}, {src: 'mixin2/bar2.2', library: mixins.mixin2[0]},
662 'bar0.1', 'bar0.2'
663 ]);
664 module.styles.should.eql([
665 {src: 'mixin2/foo2', library: mixins.mixin2[0]}, {src: 'mixin2/bar2', library: mixins.mixin2[0]},
666 'foo0', 'bar0'
667 ]);
668 module.static.should.eql([
669 {src: 'mixin1/baz1.1', library: mixins.mixin1[0]}, {src: 'mixin1/baz1.2', library: mixins.mixin1[0]},
670 {src: 'mixin2/baz2.1', library: mixins.mixin2[0]}, {src: 'mixin2/baz2.2', library: mixins.mixin2[0]}
671 ]);
672
673 mixins.mixin1[0].attributes.scripts.should.eql([{src: 'foo1.1', global: true}, {src: 'foo1.2', global: true}, 'bar1.1', 'bar1.2', {dir: 'dir!'}, {notAFile: true}]);
674 mixins.mixin1[0].attributes.static.should.eql([ 'baz1.1', 'baz1.2' ]);
675
676 mixins.mixin2[0].attributes.scripts.should.eql([{src: 'foo2.1', global: true}, {src: 'foo2.2', global: true}, 'bar2.1', 'bar2.2']);
677 mixins.mixin2[0].attributes.styles.should.eql([ 'foo2', 'bar2' ]);
678 mixins.mixin2[0].attributes.static.should.eql([ 'baz2.1', 'baz2.2' ]);
679 done();
680 });
681 });
682
683 it('should allow files to be overriden', function(done) {
684 var mixinDecl = {
685 name: 'mixin1',
686 overrides: {
687 'baz1.1': 'foo',
688 'baz1.2': true,
689 'baz1.3': false
690 }
691 };
692 var module = {
693 mixins: [
694 mixinDecl,
695 'mixin2'
696 ],
697 static: [ 'baz1.1' ]
698 };
699
700 var mixins = [
701 {
702 name: '1',
703 root: 'mixin1/',
704 mixins: {
705 mixin1: {
706 static: [ 'baz1.1', 'baz1.2', 'baz1.3' ]
707 }
708 }
709 },
710 {
711 name: '2',
712 root: 'mixin2/',
713 mixins: {
714 mixin2: {
715 static: [ 'baz1.1', 'baz1.2' ]
716 }
717 }
718 }
719 ];
720
721 lib.mixinExec(module, mixins, function(libraries) {
722 mixins = libraries.mixins;
723
724 var mixin1 = _.extend({}, mixinDecl, mixins.mixin1[0]);
725
726 module.static.should.eql([
727 {src: 'foo', originalSrc: 'mixin1/baz1.1', library: mixin1},
728 {src: 'baz1.2', originalSrc: 'mixin1/baz1.2', library: mixin1},
729 {src: 'mixin2/baz1.1', library: mixins.mixin2[0]},
730 {src: 'mixin2/baz1.2', library: mixins.mixin2[0]},
731 'baz1.1'
732 ]);
733
734 mixins.mixin1[0].attributes.static.should.eql([ 'baz1.1', 'baz1.2', 'baz1.3' ]);
735 mixins.mixin2[0].attributes.static.should.eql([ 'baz1.1', 'baz1.2' ]);
736 done();
737 });
738 });
739
740 it('should allow nested files to be overriden', function(done) {
741 var mixinDecl = {
742 name: 'mixin1',
743 overrides: {
744 'baz1.1': 'foo',
745 'baz1.2': true,
746 'baz1.3': false
747 }
748 };
749 var module = {
750 mixins: [
751 'mixin2'
752 ],
753 static: [ 'baz1.1' ]
754 };
755
756 var mixins = [
757 {
758 name: '1',
759 root: 'mixin1/',
760 mixins: {
761 mixin1: {
762 static: [ 'baz1.1', 'baz1.2', 'baz1.3' ]
763 }
764 }
765 },
766 {
767 name: '2',
768 root: 'mixin2/',
769 mixins: {
770 mixin2: {
771 mixins: [
772 mixinDecl
773 ],
774 static: [ 'baz1.1', 'baz1.2' ]
775 }
776 }
777 }
778 ];
779
780 lib.mixinExec(module, mixins, function(libraries) {
781 mixins = libraries.mixins;
782
783 var mixin1 = _.extend({}, mixinDecl, mixins.mixin1[0]);
784
785 _.each(module.static, function(file) { delete file.library; });
786
787 module.static.should.eql([
788 {src: 'mixin2/foo', originalSrc: 'mixin1/baz1.1'},
789 {src: 'mixin2/baz1.2', originalSrc: 'mixin1/baz1.2'},
790 {src: 'mixin2/baz1.1'},
791 {src: 'mixin2/baz1.2'},
792 'baz1.1'
793 ]);
794
795 mixins.mixin1[0].attributes.static.should.eql([ 'baz1.1', 'baz1.2', 'baz1.3' ]);
796 mixins.mixin2[0].attributes.static.should.eql([ 'baz1.1', 'baz1.2' ]);
797 done();
798 });
799 });
800
801 it('should allow nested mixins to be overriden at the top level', function(done) {
802 var mixinDecl = {
803 name: 'mixin2',
804 overrides: {
805 'baz1.1': 'foo',
806 'baz1.2': true,
807 'baz1.3': false
808 }
809 };
810 var module = {
811 mixins: [
812 mixinDecl
813 ],
814 static: [ 'baz1.1' ]
815 };
816
817 var mixins = [
818 {
819 name: '1',
820 root: 'mixin1/',
821 mixins: {
822 mixin1: {
823 static: [ 'baz1.1', 'baz1.2', 'baz1.3' ]
824 },
825 mixin2: {
826 mixins: [
827 {
828 name: 'mixin1',
829 overrides: {
830 'baz1.1': 'foo',
831 'baz1.2': true
832 }
833 }
834 ],
835 static: [ 'baz2.1', 'baz2.2' ]
836 }
837 }
838 }
839 ];
840
841 lib.mixinExec(module, mixins, function(libraries) {
842 if (libraries.err) {
843 throw libraries.err;
844 }
845
846 mixins = libraries.mixins;
847
848 var mixin1 = _.extend({}, mixinDecl, mixins.mixin1[0]);
849
850 _.each(module.static, function(file) { delete file.library; });
851
852 module.static.should.eql([
853 {src: 'foo', originalSrc: 'mixin1/baz1.1'},
854 {src: 'baz1.2', originalSrc: 'mixin1/baz1.2'},
855 {src: 'mixin1/baz2.1'},
856 {src: 'mixin1/baz2.2'},
857 'baz1.1'
858 ]);
859
860 done();
861 });
862 });
863 });
864
865 describe('conditional include', function() {
866 var module,
867 mixins;
868 beforeEach(function() {
869 module = {
870 mixins: [
871 {'name': 'mixin1', 'platform': 'web', 'env': 'dev'},
872 {'name': 'mixin2', 'package': 'native'}
873 ],
874 bat: 3,
875 scripts: [ {src: 'foo0.1', global: true}, 'bar0.1'],
876 styles: [ 'foo0' ],
877 static: [ 'baz0.1' ]
878 };
879
880 mixins = {
881 mixin1: {
882 name: '1',
883 foo: 1,
884 scripts: [ {src: 'foo1.1', global: true}, 'bar1.1', {'module-map': true}],
885 styles: [ 'foo1' ],
886 static: [ 'baz1.1' ]
887 },
888 mixin2: {
889 name: '2',
890 bar: 2,
891 scripts: [ {src: 'foo2.1', global: true}, 'bar2.1'],
892 styles: [ 'foo2' ],
893 static: [ 'baz2.1' ]
894 }
895 };
896 });
897
898 it('should conditionally include platform mixins', function(done) {
899 lib.mixinExec(module, [{name: 'conditionally', mixins: mixins}], function() {
900 module.foo.should.eql(1, 'foo should be written');
901 module.bar.should.eql(2, 'bar should be written');
902 module.bat.should.eql(3, 'bat should not be overwritten');
903
904 stripper(module.scripts);
905 stripper(module.styles);
906 stripper(module.static);
907
908 module.scripts.should.eql([
909 {src: 'foo1.1', global: true, platform: 'web', env: 'dev'},
910 {src: 'foo2.1', global: true, package: 'native'},
911 {src: 'foo0.1', global: true},
912 {src: 'bar1.1', platform: 'web', env: 'dev'},
913 {'module-map': true, platform: 'web', env: 'dev'},
914 {src: 'bar2.1', package: 'native'},
915 'bar0.1'
916 ]);
917 module.styles.should.eql([
918 {src: 'foo1', platform: 'web', env: 'dev'},
919 {src: 'foo2', package: 'native'},
920 'foo0'
921 ]);
922 module.static.should.eql([
923 {src: 'baz1.1', platform: 'web', env: 'dev'},
924 {src: 'baz2.1', package: 'native'},
925 'baz0.1'
926 ]);
927
928 done();
929 });
930 });
931
932 it('should allow for nested mixins', function(done) {
933 var module = {
934 mixins: ['mixin1']
935 };
936
937 var mixins = {
938 mixin1: {
939 mixins: ['mixin2'],
940 routes: { foo: 1, baz: 1, bat: 1 }
941 },
942 mixin2: {mixins: [{name: 'mixin3'}]},
943 mixin3: {routes: { bar: 2, baz: 2, bat: 2 }}
944 };
945
946 lib.mixinExec(module, [{name: 'routes', mixins: mixins}], function() {
947 module.routes.foo.should.equal(1);
948 module.routes.bar.should.equal(2);
949 module.routes.baz.should.equal(1);
950 module.routes.bat.should.equal(1);
951
952 done();
953 });
954 });
955
956 it('should propagate conditional attributes for nested mixins', function(done) {
957 var module = {
958 mixins: ['mixin1']
959 };
960
961 var mixins = {
962 mixin1: {
963 mixins: [{name: 'mixin2', platform: 'foo'}],
964 scripts: [
965 '1.js'
966 ]
967 },
968 mixin2: {mixins: [{name: 'mixin3'}]},
969 mixin3: {scripts: [
970 '3.js'
971 ]
972 }
973 };
974
975 lib.mixinExec(module, [{name: 'routes', mixins: mixins}], function() {
976 stripper(module.scripts);
977 module.scripts.should.eql([
978 {'src': '3.js', platform: 'foo'},
979 {'src': '1.js'}
980 ]);
981
982 done();
983 });
984 });
985 });
986
987 describe('watch', function() {
988 var config = {};
989 lib.mockFileList(config);
990
991 var mock;
992 beforeEach(function() {
993 var readFile = fs.readFile;
994
995 mock = watch.mockWatch();
996
997 this.stub(fs, 'readFileSync', function() {
998 return JSON.stringify({
999 name: 'attr',
1000 modules: {
1001 module: {scripts: ['js/views/test.js']}
1002 },
1003 libraries: 'library'
1004 });
1005 });
1006
1007 this.stub(fs, 'readFile', function(path, callback) {
1008 if (/test.(js|foo)$/.test(path)) {
1009 return callback(undefined, 'foo');
1010 } else {
1011 return readFile.apply(this, arguments);
1012 }
1013 });
1014 });
1015 afterEach(function() {
1016 mock.cleanup();
1017 });
1018
1019
1020 function runWatchTest(srcdir, config, operations, expectedFiles, done) {
1021 watch.runWatchTest.call(this, srcdir, config, operations, expectedFiles, {}, done);
1022 }
1023
1024 it('should rebuild on config change', function(done) {
1025 var expectedFiles = ['/module.js', '/module.js'],
1026 operations = {
1027 1: function(testdir) {
1028 mock.trigger('change', testdir + 'library/lumbar.json');
1029 }
1030 };
1031
1032 runWatchTest.call(this,
1033 'test/artifacts', 'lumbar.json',
1034 operations, expectedFiles,
1035 done);
1036 });
1037 });
1038
1039 describe('integration', function() {
1040 it('should mixin all content', lib.runTest('test/artifacts/mixin.json', 'test/expected/mixin'));
1041 });
1042});
1043