OLD | NEW |
1 /* | 1 /* |
2 This file is part of the Juju GUI, which lets users view and manage Juju | 2 This file is part of the Juju GUI, which lets users view and manage Juju |
3 environments within a graphical interface (https://launchpad.net/juju-gui). | 3 environments within a graphical interface (https://launchpad.net/juju-gui). |
4 Copyright (C) 2012-2013 Canonical Ltd. | 4 Copyright (C) 2012-2013 Canonical Ltd. |
5 | 5 |
6 This program is free software: you can redistribute it and/or modify it under | 6 This program is free software: you can redistribute it and/or modify it under |
7 the terms of the GNU Affero General Public License version 3, as published by | 7 the terms of the GNU Affero General Public License version 3, as published by |
8 the Free Software Foundation. | 8 the Free Software Foundation. |
9 | 9 |
10 This program is distributed in the hope that it will be useful, but WITHOUT | 10 This program is distributed in the hope that it will be useful, but WITHOUT |
(...skipping 21 matching lines...) Expand all Loading... |
32 'juju-charm-store', | 32 'juju-charm-store', |
33 'juju-tests-utils', | 33 'juju-tests-utils', |
34 'node', | 34 'node', |
35 'node-event-simulate', | 35 'node-event-simulate', |
36 'subapp-browser-charmview', | 36 'subapp-browser-charmview', |
37 function(Y) { | 37 function(Y) { |
38 views = Y.namespace('juju.browser.views'); | 38 views = Y.namespace('juju.browser.views'); |
39 models = Y.namespace('juju.models'); | 39 models = Y.namespace('juju.models'); |
40 utils = Y.namespace('juju-tests.utils'); | 40 utils = Y.namespace('juju-tests.utils'); |
41 CharmView = views.BrowserCharmView; | 41 CharmView = views.BrowserCharmView; |
| 42 // Need the handlebars helper for the charm-token to render. |
| 43 Y.Handlebars.registerHelper( |
| 44 'charmFilePath', |
| 45 function(charmID, file) { |
| 46 return '/path/to/charm/' + file; |
| 47 }); |
42 done(); | 48 done(); |
43 }); | 49 }); |
44 }); | 50 }); |
45 | 51 |
46 beforeEach(function() { | 52 beforeEach(function() { |
47 container = Y.namespace('juju-tests.utils').makeContainer('container'); | 53 container = Y.namespace('juju-tests.utils').makeContainer('container'); |
48 var testcontent = [ | 54 var testcontent = [ |
49 '<div id=testcontent><div class="bws-view-data">', | 55 '<div id=testcontent><div class="bws-view-data">', |
50 '</div></div>' | 56 '</div></div>' |
51 ].join(); | 57 ].join(); |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 // munge the data so that scores is null. | 379 // munge the data so that scores is null. |
374 data.scores = null; | 380 data.scores = null; |
375 | 381 |
376 var processed = view._buildQAData(data); | 382 var processed = view._buildQAData(data); |
377 processed.totalAvailable.should.eql(38); | 383 processed.totalAvailable.should.eql(38); |
378 processed.totalScore.should.eql(0); | 384 processed.totalScore.should.eql(0); |
379 }); | 385 }); |
380 | 386 |
381 it('does not display qa data when there is none.', function() { | 387 it('does not display qa data when there is none.', function() { |
382 var data = utils.loadFixture('data/qa.json', true); | 388 var data = utils.loadFixture('data/qa.json', true); |
| 389 var testContainer = utils.makeContainer(); |
383 // munge the data so that scores is null. | 390 // munge the data so that scores is null. |
384 data.scores = null; | 391 data.scores = null; |
385 var fakedata = Y.JSON.stringify(data); | 392 var fakedata = Y.JSON.stringify(data); |
386 | 393 |
387 var fakeStore = new Y.juju.Charmworld2({}); | 394 var fakeStore = new Y.juju.Charmworld2({}); |
388 fakeStore.set('datasource', { | 395 fakeStore.set('datasource', { |
389 sendRequest: function(params) { | 396 sendRequest: function(params) { |
390 // Stubbing the server callback value | 397 // Stubbing the server callback value |
391 params.callback.success({ | 398 params.callback.success({ |
392 response: { | 399 response: { |
393 results: [{ | 400 results: [{ |
394 responseText: fakedata | 401 responseText: fakedata |
395 }] | 402 }] |
396 } | 403 } |
397 }); | 404 }); |
398 } | 405 } |
399 }); | 406 }); |
400 | 407 |
401 view = new CharmView({ | 408 view = new CharmView({ |
402 charm: new models.BrowserCharm({ | 409 charm: new models.BrowserCharm({ |
403 files: [], | 410 files: [], |
404 id: 'precise/ceph-9', | 411 id: 'precise/ceph-9', |
405 code_source: { location: 'lp:~foo' } | 412 code_source: { location: 'lp:~foo' } |
406 }), | 413 }), |
407 renderTo: utils.makeContainer(), | 414 renderTo: testContainer, |
408 store: fakeStore | 415 store: fakeStore |
409 }); | 416 }); |
410 | 417 |
411 view.render(); | 418 view.render(); |
412 // Force the loading of the qa div. | 419 // Force the loading of the qa div. |
413 view._loadQAContent(); | 420 view._loadQAContent(); |
414 | 421 |
415 // Because we have no score, we get the alternate content. This charm is | 422 // Because we have no score, we get the alternate content. This charm is |
416 // not approved/reviewed so we get the content explaining it will not | 423 // not approved/reviewed so we get the content explaining it will not |
417 // have quality data. | 424 // have quality data. |
418 var foundNode = view.get('container').one('.no-qa-unreviewed'); | 425 var foundNode = view.get('container').one('.no-qa-unreviewed'); |
419 assert.ok(foundNode); | 426 assert.ok(foundNode); |
420 | 427 |
421 // Change the charm to be reviewed/approved and verify we hit the other | 428 // Change the charm to be reviewed/approved and verify we hit the other |
422 // message while not showing quality scores. | 429 // message while not showing quality scores. |
423 view.get('charm').set('is_approved', true); | 430 view.get('charm').set('is_approved', true); |
424 // Force the loading of the qa div. | 431 // Force the loading of the qa div. |
425 view._loadQAContent(); | 432 view._loadQAContent(); |
426 foundNode = view.get('container').one('.no-qa-reviewed'); | 433 foundNode = view.get('container').one('.no-qa-reviewed'); |
427 assert.ok(foundNode); | 434 assert.ok(foundNode); |
| 435 // Little cleanup. |
| 436 testContainer.remove(true); |
428 }); | 437 }); |
429 | 438 |
430 it('should catch when the open log is clicked', function(done) { | 439 it('should catch when the open log is clicked', function(done) { |
431 var data = utils.loadFixture('data/browsercharm.json', true); | 440 var data = utils.loadFixture('data/browsercharm.json', true); |
432 // We don't want any files so we don't have to mock/load them. | 441 // We don't want any files so we don't have to mock/load them. |
433 data.charm.files = []; | 442 data.charm.files = []; |
434 view = new CharmView({ | 443 view = new CharmView({ |
435 charm: new models.BrowserCharm(data.charm), | 444 charm: new models.BrowserCharm(data.charm), |
436 container: utils.makeContainer() | 445 container: utils.makeContainer() |
437 }); | 446 }); |
438 | 447 |
439 // Hook up to the callback for the click event. | 448 // Hook up to the callback for the click event. |
440 view._toggleLog = function(ev) { | 449 view._toggleLog = function(ev) { |
441 ev.halt(); | 450 ev.halt(); |
442 done(); | 451 done(); |
443 }; | 452 }; |
444 | 453 |
445 view.render(); | 454 view.render(); |
446 node.one('.changelog .expand').simulate('click'); | 455 node.one('.changelog .expand').simulate('click'); |
447 }); | 456 }); |
448 | 457 |
449 it('changelog is reformatted and displayed', function() { | 458 it('changelog is reformatted and displayed', function() { |
450 var fakeStore = new Y.juju.Charmworld2({}); | |
451 var data = utils.loadFixture('data/browsercharm.json', true); | 459 var data = utils.loadFixture('data/browsercharm.json', true); |
452 // We don't want any files so we don't have to mock/load them. | 460 // We don't want any files so we don't have to mock/load them. |
453 data.charm.files = []; | 461 data.charm.files = []; |
454 view = new CharmView({ | 462 view = new CharmView({ |
455 charm: new models.BrowserCharm(data.charm), | 463 charm: new models.BrowserCharm(data.charm), |
456 container: utils.makeContainer() | 464 container: utils.makeContainer() |
457 }); | 465 }); |
458 | 466 |
459 view.render(); | 467 view.render(); |
460 // Basics that we have the right number of nodes. | 468 // Basics that we have the right number of nodes. |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 }); | 665 }); |
658 view = new CharmView({ | 666 view = new CharmView({ |
659 charm: charm | 667 charm: charm |
660 }); | 668 }); |
661 var interfaceIntro = view._getInterfaceIntroFlag( | 669 var interfaceIntro = view._getInterfaceIntroFlag( |
662 charm.get('requires'), charm.get('provides')); | 670 charm.get('requires'), charm.get('provides')); |
663 assert(Y.Object.hasKey(interfaceIntro, 'manyRequiresManyProvides')); | 671 assert(Y.Object.hasKey(interfaceIntro, 'manyRequiresManyProvides')); |
664 }); | 672 }); |
665 | 673 |
666 it('displays a provider warning due to failed tests', function() { | 674 it('displays a provider warning due to failed tests', function() { |
667 var fakeStore = new Y.juju.Charmworld2({}); | |
668 var data = utils.loadFixture('data/browsercharm.json', true); | 675 var data = utils.loadFixture('data/browsercharm.json', true); |
669 // We don't want any files so we don't have to mock/load them. | 676 // We don't want any files so we don't have to mock/load them. |
670 data.charm.files = []; | 677 data.charm.files = []; |
671 // Add a failing test to the charm data. | 678 // Add a failing test to the charm data. |
672 data.charm.tested_providers = { | 679 data.charm.tested_providers = { |
673 'ec2': 'FAILURE', | 680 'ec2': 'FAILURE', |
674 'local': 'FAILURE', | 681 'local': 'FAILURE', |
675 'openstack': 'FAILURE' | 682 'openstack': 'FAILURE' |
676 }; | 683 }; |
677 | 684 |
678 view = new CharmView({ | 685 view = new CharmView({ |
679 charm: new models.BrowserCharm(data.charm), | 686 charm: new models.BrowserCharm(data.charm), |
680 container: utils.makeContainer() | 687 container: utils.makeContainer() |
681 }); | 688 }); |
682 | 689 |
683 view.render(); | 690 view.render(); |
684 // Basics that we have the right number of nodes. | 691 // Basics that we have the right number of nodes. |
685 node.all('.provider-warning').size().should.eql(1); | 692 node.all('.provider-warning').size().should.eql(1); |
686 node.all('.provider-warning img').size().should.eql(4); | 693 node.all('.provider-warning img').size().should.eql(4); |
687 }); | 694 }); |
688 | 695 |
689 it('shows and hides an indicator', function(done) { | 696 it('shows and hides an indicator', function(done) { |
690 var hit = 0; | 697 var hit = 0; |
691 | 698 |
692 var fakeStore = new Y.juju.Charmworld2({}); | |
693 var data = utils.loadFixture('data/browsercharm.json', true); | 699 var data = utils.loadFixture('data/browsercharm.json', true); |
694 // We don't want any files so we don't have to mock/load them. | 700 // We don't want any files so we don't have to mock/load them. |
695 data.charm.files = []; | 701 data.charm.files = []; |
696 view = new CharmView({ | 702 view = new CharmView({ |
697 charm: new models.BrowserCharm(data.charm), | 703 charm: new models.BrowserCharm(data.charm), |
698 container: utils.makeContainer() | 704 container: utils.makeContainer() |
699 }); | 705 }); |
700 | 706 |
701 view.showIndicator = function() { | 707 view.showIndicator = function() { |
702 hit += 1; | 708 hit += 1; |
703 }; | 709 }; |
704 view.hideIndicator = function() { | 710 view.hideIndicator = function() { |
705 hit += 1; | 711 hit += 1; |
706 hit.should.equal(2); | 712 hit.should.equal(2); |
707 done(); | 713 done(); |
708 }; | 714 }; |
709 view.render(); | 715 view.render(); |
710 }); | 716 }); |
711 | 717 |
712 it('sets a category icon if available', function() { | 718 it('sets a category icon if available', function() { |
713 var fakeStore = new Y.juju.Charmworld2({}); | |
714 var data = utils.loadFixture('data/browsercharm.json', true); | 719 var data = utils.loadFixture('data/browsercharm.json', true); |
715 // We don't want any files so we don't have to mock/load them. | 720 // We don't want any files so we don't have to mock/load them. |
716 data.charm.files = []; | 721 data.charm.files = []; |
717 // Add a category manually to get a category icon to display. | 722 // Add a category manually to get a category icon to display. |
718 data.charm.categories = ['app-servers']; | 723 data.charm.categories = ['app-servers']; |
719 view = new CharmView({ | 724 view = new CharmView({ |
720 charm: new models.BrowserCharm(data.charm), | 725 charm: new models.BrowserCharm(data.charm), |
721 container: utils.makeContainer() | 726 container: utils.makeContainer() |
722 }); | 727 }); |
723 | 728 |
724 view.render(); | 729 view.render(); |
725 var iconNode = view.get('container').one('.category-icon'); | 730 var iconNode = view.get('container').one('.category-icon'); |
726 assert.equal(iconNode.hasClass('charm-app-servers-160'), true); | 731 assert.equal(iconNode.hasClass('charm-app-servers-160'), true); |
727 }); | 732 }); |
728 | 733 |
729 it('selects the proper tab when given one', function() { | 734 it('selects the proper tab when given one', function() { |
730 var fakeStore = new Y.juju.Charmworld2({}); | |
731 var data = utils.loadFixture('data/browsercharm.json', true); | 735 var data = utils.loadFixture('data/browsercharm.json', true); |
732 // We don't want any files so we don't have to mock/load them. | 736 // We don't want any files so we don't have to mock/load them. |
733 data.charm.files = []; | 737 data.charm.files = []; |
734 | 738 |
735 view = new CharmView({ | 739 view = new CharmView({ |
736 activeTab: '#bws-interfaces', | 740 activeTab: '#bws-interfaces', |
737 charm: new models.BrowserCharm(data.charm), | 741 charm: new models.BrowserCharm(data.charm), |
738 container: utils.makeContainer() | 742 container: utils.makeContainer() |
739 }); | 743 }); |
740 | 744 |
741 view.render(); | 745 view.render(); |
742 | 746 |
743 // We've selected the activeTab specified. | 747 // We've selected the activeTab specified. |
744 var selected = view.get('container').one('.yui3-tab-selected a'); | 748 var selected = view.get('container').one('.yui3-tab-selected a'); |
745 assert.equal(selected.getAttribute('href'), '#bws-interfaces'); | 749 assert.equal(selected.getAttribute('href'), '#bws-interfaces'); |
746 }); | 750 }); |
747 | 751 |
| 752 it('renders out the related charms correctly', function(done) { |
| 753 var data = utils.loadFixture('data/browsercharm.json', true).charm; |
| 754 var testContainer = utils.makeContainer(); |
| 755 // We don't want any files so we don't have to mock/load them. |
| 756 data.files = []; |
| 757 |
| 758 var fakeStore = new Y.juju.Charmworld2({}); |
| 759 fakeStore.set('datasource', { |
| 760 sendRequest: function(params) { |
| 761 // Stubbing the server callback value |
| 762 params.callback.success({ |
| 763 response: { |
| 764 results: [{ |
| 765 responseText: utils.loadFixture('data/related.json') |
| 766 }] |
| 767 } |
| 768 }); |
| 769 } |
| 770 }); |
| 771 |
| 772 view = new CharmView({ |
| 773 charm: new models.BrowserCharm(data), |
| 774 isFullscreen: true, |
| 775 renderTo: testContainer, |
| 776 store: fakeStore |
| 777 }); |
| 778 view.render(); |
| 779 |
| 780 // We've selected the activeTab specified. |
| 781 var tokens = view.get('container').all('.charm-token'); |
| 782 assert.equal(5, tokens.size()); |
| 783 |
| 784 // And clicking on one of those charms navigates correctly. |
| 785 view.on('viewNavigate', function(ev) { |
| 786 ev.halt(); |
| 787 // Just make sure we've got an id. The order will vary some depending |
| 788 // on the browser due to many charms with the same score of 10 in the |
| 789 // sample data.. |
| 790 assert(ev.change.charmID); |
| 791 testContainer.remove(true); |
| 792 done(); |
| 793 }); |
| 794 view.get('container').one('.charm-token').simulate('click'); |
| 795 }); |
748 }); | 796 }); |
749 | 797 |
750 })(); | 798 })(); |
OLD | NEW |