├── .gitignore ├── README.md ├── bower.json ├── karma.conf.js ├── package.json ├── src ├── controller.js ├── directives.js ├── factories.js ├── http.js ├── providers.js └── timeout.js └── test ├── controllers.mocha.js ├── directives.mocha.js ├── factories.mocha.js ├── http.mocha.js ├── providers.mocha.js └── timeouts.mocha.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | coverage/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | smashing-article 2 | ================ 3 | 4 | ![](http://fabfunny.com/wp-content/uploads/2011/04/funny-celebrity-pictures-and-in-that-moment-we-were-smashing.gif) 5 | 6 | Smashing ! 7 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smashing-article", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Sebastien " 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "angular": "~1.2.20" 17 | }, 18 | "devDependencies": { 19 | "angular-mocks": "~1.2.20" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Mon Jul 21 2014 11:48:34 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'sinon-chai'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'bower_components/angular/angular.js', 19 | 'bower_components/angular-mocks/angular-mocks.js', 20 | 'src/*.js', 21 | 'test/*.mocha.js' 22 | ], 23 | 24 | 25 | // list of files to exclude 26 | exclude: [ 27 | ], 28 | 29 | 30 | // preprocess matching files before serving them to the browser 31 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 32 | preprocessors: { 33 | 'src/*.js': ['coverage'] 34 | }, 35 | 36 | coverageReporter: { 37 | // type : 'html', 38 | type : 'text-summary', 39 | dir : 'coverage/' 40 | }, 41 | 42 | 43 | // test results reporter to use 44 | // possible values: 'dots', 'progress' 45 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 46 | reporters: ['progress', 'coverage'], 47 | 48 | 49 | // web server port 50 | port: 9876, 51 | 52 | 53 | // enable / disable colors in the output (reporters and logs) 54 | colors: true, 55 | 56 | 57 | // level of logging 58 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 59 | logLevel: config.LOG_INFO, 60 | 61 | 62 | // enable / disable watching file and executing tests whenever any file changes 63 | autoWatch: true, 64 | 65 | 66 | // start these browsers 67 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 68 | browsers: ['PhantomJS'], 69 | 70 | 71 | // Continuous Integration mode 72 | // if true, Karma captures browsers, runs the tests and exits 73 | singleRun: false 74 | }); 75 | }; 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smashing-article", 3 | "version": "0.0.0", 4 | "description": "smashing-article ================", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "karma-coverage": "~0.2.4", 8 | "karma-mocha": "~0.1.6", 9 | "karma-phantomjs-launcher": "^0.1.4", 10 | "karma-sinon-chai": "~0.2.0", 11 | "mocha": "~1.20.1" 12 | }, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "ssh://git@github-ipsum.com/lorem--ipsum/smashing-article.git" 19 | }, 20 | "author": "", 21 | "license": "ISC", 22 | "directories": { 23 | "test": "test" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/controller.js: -------------------------------------------------------------------------------- 1 | angular.module('textEditor', []) 2 | 3 | .controller('EditionCtrl', ['$scope', function($scope) { 4 | $scope.state = {toolbarVisible: true, documentSaved: true}; 5 | $scope.document = {text: 'Some text'}; 6 | 7 | $scope.$watch('document.text', function(value) { 8 | $scope.state.documentSaved = false; 9 | }, true); 10 | 11 | $scope.saveDocument = function() { 12 | $scope.sendHTTP($scope.document.text); 13 | $scope.state.documentSaved = true; 14 | }; 15 | 16 | $scope.sendHTTP = function(content) { 17 | // payload creation, HTTP request, etc. 18 | }; 19 | }]); 20 | -------------------------------------------------------------------------------- /src/directives.js: -------------------------------------------------------------------------------- 1 | angular.module('myDirectives', []) 2 | .directive('superButton', function() { 3 | return { 4 | scope: {label: '=', callback: '&onClick'}, 5 | replace: true, 6 | restrict: 'E', 7 | link: function(scope, element, attrs) { 8 | 9 | }, 10 | template: '
' + 11 | '
{{label}}
' + 12 | '' + 13 | '
' 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /src/factories.js: -------------------------------------------------------------------------------- 1 | angular.module('factories', []) 2 | .factory('chimp', ['$log', function($log) { 3 | return { 4 | ook: function() { 5 | $log.warn('Ook.'); 6 | } 7 | }; 8 | }]); 9 | -------------------------------------------------------------------------------- /src/http.js: -------------------------------------------------------------------------------- 1 | angular.module('factories_2', []) 2 | .factory('chimp', ['$http', function($http) { 3 | return { 4 | sendMessage: function() { 5 | $http.post('http://chimps.org/messages', {message: 'Ook.'}); 6 | } 7 | }; 8 | }]); 9 | -------------------------------------------------------------------------------- /src/providers.js: -------------------------------------------------------------------------------- 1 | angular.module('myProviders', []) 2 | 3 | .provider('coffeeMaker', function() { 4 | var useFrenchPress = false; 5 | this.useFrenchPress = function(value) { 6 | if (value !== undefined) { 7 | useFrenchPress = !!value; 8 | } 9 | 10 | return useFrenchPress; 11 | }; 12 | 13 | this.$get = function () { 14 | return { 15 | brew: function() { 16 | return useFrenchPress ? 'Le café.' : 'A coffee.'; 17 | } 18 | }; 19 | }; 20 | }); 21 | -------------------------------------------------------------------------------- /src/timeout.js: -------------------------------------------------------------------------------- 1 | angular.module('timeouts', []) 2 | 3 | .factory('waiter', ['$timeout', function($timeout) { 4 |   return { 5 |     brieflySetSomethingToTrue: function(target, property) { 6 |       var oldValue = target[property]; 7 | 8 |       target[property] = true; 9 | 10 |       $timeout(function() { 11 |         target[property] = oldValue; 12 |       }, 100); 13 |     } 14 |   }; 15 | }]); 16 | -------------------------------------------------------------------------------- /test/controllers.mocha.js: -------------------------------------------------------------------------------- 1 | describe('saving a document', function() { 2 | 3 |   var scope; 4 |   var ctrl; 5 | 6 |   beforeEach(module('textEditor')); 7 | 8 |   beforeEach(inject(function($rootScope, $controller) { 9 |     scope = $rootScope.$new(); 10 |     ctrl = $controller('EditionCtrl', {$scope: scope}); 11 |   })); 12 | 13 |   it('should have an initial documentSaved state', function(){ 14 |     expect(scope.state.documentSaved).to.equal(true); 15 |   }); 16 | 17 |   describe('documentSaved property', function() { 18 |     beforeEach(function() { 19 |       // We don't want extra HTTP requests to be sent 20 |       // and that's not what we're testing here. 21 |       sinon.stub(scope, 'sendHTTP', function() {}); 22 | 23 |       // A call to $apply() must be performed, otherwise the 24 |       // scope's watchers won't be ran through. 25 |       scope.$apply(function () { 26 |         scope.document.text += ' And some more text'; 27 |       }); 28 |     }); 29 | 30 |     it('should watch for document.text changes', function() { 31 |       expect(scope.state.documentSaved).to.equal(false); 32 |     }); 33 | 34 |     describe('when calling the saveDocument function', function() { 35 |       beforeEach(function() { 36 |         scope.saveDocument(); 37 |       }); 38 | 39 |       it('should be set to true again', function() { 40 |         expect(scope.state.documentSaved).to.equal(true); 41 |       }); 42 | 43 |       afterEach(function() { 44 |         expect(scope.sendHTTP.callCount).to.equal(1); 45 |         expect(scope.sendHTTP.args[0][0]).to.equal(scope.document.text); 46 |       }); 47 |     }); 48 |   }); 49 | }); 50 | -------------------------------------------------------------------------------- /test/directives.mocha.js: -------------------------------------------------------------------------------- 1 | describe('directives', function() { 2 | 3 |   beforeEach(module('myDirectives')); 4 | 5 |   var element; 6 |   var outerScope; 7 |   var innerScope; 8 | 9 |   beforeEach(inject(function($rootScope, $compile) { 10 |     element = angular.element(''); 11 | 12 |     outerScope = $rootScope; 13 |     $compile(element)(outerScope); 14 | 15 |     innerScope = element.isolateScope(); 16 | 17 |     outerScope.$digest(); 18 |   })); 19 | 20 |   describe('label', function() { 21 |     beforeEach(function() { 22 |       outerScope.$apply(function() { 23 |         outerScope.myLabel = "Hello world."; 24 |       }); 25 |     }) 26 | 27 |     it('should be rendered', function() { 28 |       expect(element[0].children[0].innerHTML).to.equal('Hello world.'); 29 |     }); 30 |   }); 31 | 32 |   describe('click callback', function() { 33 |     var mySpy; 34 | 35 |     beforeEach(function() { 36 |       mySpy = sinon.spy(); 37 |       outerScope.$apply(function() { 38 |         outerScope.myCallback = mySpy; 39 |       }); 40 |     }); 41 | 42 |     describe('when the directive is clicked', function() { 43 |       beforeEach(function() { 44 |         var event = document.createEvent("MouseEvent"); 45 |         event.initMouseEvent("click", true, true); 46 |         element[0].children[1].dispatchEvent(event); 47 |       }); 48 | 49 |       it('should be called', function() { 50 |         expect(mySpy.callCount).to.equal(1); 51 |       }); 52 |     }); 53 |   }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/factories.mocha.js: -------------------------------------------------------------------------------- 1 | describe('factories', function() { 2 | 3 |   beforeEach(module('factories')); 4 | 5 |   var chimp; 6 |   var $log; 7 | 8 |   beforeEach(inject(function(_chimp_, _$log_) { 9 |     chimp = _chimp_; 10 |     $log = _$log_; 11 |     sinon.stub($log, 'warn', function() {}); 12 |   })); 13 | 14 |   describe('when invoked', function() { 15 | 16 |     beforeEach(function() { 17 |       chimp.ook(); 18 |     }); 19 | 20 |     it('should say Ook', function() { 21 |       expect($log.warn.callCount).to.equal(1); 22 |       expect($log.warn.args[0][0]).to.equal('Ook.'); 23 |     }); 24 |   }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/http.mocha.js: -------------------------------------------------------------------------------- 1 | describe('http', function() { 2 | 3 |   beforeEach(module('factories_2')); 4 | 5 |   var chimp; 6 |   var $httpBackend; 7 | 8 |   beforeEach(inject(function(_chimp_, _$httpBackend_) { 9 |     chimp = _chimp_; 10 |     $httpBackend = _$httpBackend_; 11 |   })); 12 | 13 |   describe('when sending a message', function() { 14 |     beforeEach(function() { 15 |       $httpBackend.expectPOST('http://chimps.org/messages', {message: 'Ook.'}) 16 |       .respond(200, {message: 'Ook.', id: 0}); 17 | 18 |       chimp.sendMessage(); 19 |       $httpBackend.flush(); 20 |     }); 21 | 22 |     it('should send an HTTP POST request', function() { 23 |       $httpBackend.verifyNoOutstandingExpectation(); 24 |       $httpBackend.verifyNoOutstandingRequest(); 25 |     }); 26 |   }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/providers.mocha.js: -------------------------------------------------------------------------------- 1 | describe('coffee maker provider', function() { 2 |   var coffeeProvider; 3 | 4 |   beforeEach(function() { 5 |     // Here we create a fake module just to intercept and store the provider 6 |     // when it's injected, i.e. during the config phase. 7 |     angular.module('dummyModule', function() {}) 8 |       .config(['coffeeMakerProvider', function(coffeeMakerProvider) { 9 |         coffeeProvider = coffeeMakerProvider; 10 |       }]); 11 | 12 |     module('myProviders', 'dummyModule'); 13 | 14 |     // This actually triggers the injection into dummyModule 15 |     inject(function(){}); 16 |   }); 17 | 18 |   describe('with french press', function() { 19 |     beforeEach(function() { 20 |       coffeeProvider.useFrenchPress(true); 21 |     }); 22 | 23 |     it('should remember the value', function() { 24 |       expect(coffeeProvider.useFrenchPress()).to.equal(true); 25 |     }); 26 | 27 |     it('should make some coffee', inject(function(coffeeMaker) { 28 |       expect(coffeeMaker.brew()).to.equal('Le café.'); 29 |     })); 30 |   }); 31 | 32 |   describe('without french press', function() { 33 |     beforeEach(function() { 34 |       coffeeProvider.useFrenchPress(false); 35 |     }); 36 | 37 |     it('should remember the value', function() { 38 |       expect(coffeeProvider.useFrenchPress()).to.equal(false); 39 |     }); 40 | 41 |     it('should make some coffee', inject(function(coffeeMaker) { 42 |       expect(coffeeMaker.brew()).to.equal('A coffee.'); 43 |     })); 44 |   }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/timeouts.mocha.js: -------------------------------------------------------------------------------- 1 | describe('timeouts', function() { 2 | 3 |   beforeEach(module('timeouts')); 4 | 5 |   var waiter; 6 |   var $timeout; 7 | 8 |   beforeEach(inject(function(_waiter_, _$timeout_) { 9 |     waiter = _waiter_; 10 |     $timeout = _$timeout_; 11 |   })); 12 | 13 |   describe('brieflySetSomethingToTrue method', function() { 14 |     var anyObject; 15 | 16 |     beforeEach(function() { 17 |       anyObject = {foo: 42}; 18 |       waiter.brieflySetSomethingToTrue(anyObject, 'foo'); 19 |     }); 20 | 21 |     it('should briefly set something to true', function() { 22 |       expect(anyObject.foo).to.equal(true); 23 |       $timeout.flush(); 24 |       expect(anyObject.foo).to.equal(42); 25 |     }); 26 |   }); 27 | }); 28 | --------------------------------------------------------------------------------