diff --git a/.bowerrc b/.bowerrc index 5bdbb80..69fad35 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,3 @@ { - "directory" : "vendor" -} \ No newline at end of file + "directory": "bower_components" +} diff --git a/.gitignore b/.gitignore index aec7f25..82d38a2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,13 +15,5 @@ npm-debug.log test/test-results.xml -vendor/angular-cookies/ -vendor/angular-mocks/ -vendor/angular-resource/ -vendor/angular-sanitize/ -vendor/angular/ -vendor/bootstrap-less-themes/ -vendor/bootstrap/ -vendor/console-polyfill/ -vendor/font-awesome/ -vendor/jquery/ +# Bower stuff. +bower_components/ diff --git a/README.md b/README.md index 139fb3a..cbd6f7a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ [AngularJS](http://angularjs.org) + [Brunch](http://brunch.io) +#### ** MAJOR UPDATES ** +v0.4.1 Brings with it some major changes. If you're upgrading from a previous release, +please run `./scripts/init.sh` and remove any bower components from `vendor`. Bower +now uses the `bower_components` directory. + Features: * Coffeescript / Jade / Less / Stylus automatically compiled on save * auto-reload during development saves you from manually refreshing the page @@ -10,6 +15,26 @@ Features: * [karma](https://github.com/karma-runner/karma) integration for unit tests * Bootstrap integration with themes. +* Source map support +* Modularized code, see /app/sections +* angular/ui-router for more flexible routing + +## Why modularize? + +This "modularized" version is intended to be as simple as possible while laying down patterns that, if followed, will create an easily-maintained complex application. The original Angular-Seed entices one down the path of code segregated by type (controllers, views, etc.) rather than by feature (todo, view1, view2). Misko recommends organizing code around features (see [this](http://www.youtube.com/watch?feature=player_embedded&v=E87rXWE62WU#t=106s) 10/27/13 presentation). + +Modularized code is better for +* unit testing +* working with larger teams (to not step on each others’ work) +* preparing for the future because modules will be able to be lazy-loaded and so this structure will be either required or firmly recommended + +## What, exactly, is different in the modularized code? +Differences +* Instead of one controller, one partials folder, one module, there are several + * top level ones under /app + * lower-level ones under /app/sections + * (to make that work, karma.conf.js and config.coffee had to be changed, to pick up and integrate the files from more locations) +* Instead of using the $routeProvider, it uses angular-ui-router to allow output to multiple named views, nested views, etc. Routing and ng-view was mentioned by many online as pain points for larger apps. This arrangement should be much better. ## Alternate Versions @@ -22,6 +47,9 @@ Features: - [brunch-on-asteroids](https://github.com/exlee/brunch-on-asteroids) by [@exlee](https://github.com/exlee) - A minimalistic version that adds Generators, Bootswatch themes, D3, and more. +- [angular-brunch-seed-modularized](https://github.com/sanfordredlich/angular-brunch-seed-modularized) + by [@sanfordredlich](https://github.com/sanfordredlich) - Demonstrates a modular + design, consistent with best practices and better suited for larger projects ## How to use angular-brunch-seed @@ -32,7 +60,7 @@ Features: Or if you have **Brunch** installed run: -`brunch new myapp --skeleton https://github.com/scotch/angular-brunch-seed` +`brunch new https://github.com/scotch/angular-brunch-seed myapp` You must also install packages using bower. Either @@ -41,7 +69,7 @@ bower install ``` or ``` -./node_modules/.bin/bower +./node_modules/.bin/bower install ``` *NOTE:* Depending upon your connection and processor speed the build can take @@ -110,11 +138,10 @@ and run `bower install`. The component will be added to the `vendor` directory. ### Running unit tests * `./scripts/test.sh` to run unit tests with [karma](https://github.com/karma-runner/karma) -* Open the browser you would like to test to [http://localhost:3334](http://localhost:3334) Notes: -- Testacular will run tests on save. To insure that changes are saved be sure +- Karma will run tests on save. To insure that changes are saved be sure to have `./script/server.sh` or `./script/development.sh` running in the console. - Set the browsers that you would like to target in the `/test/karma.conf.js` file E.g. `browser = ["ChromeCanary", "Firefox"]` @@ -155,8 +182,6 @@ git pull origin master assets --> a place for static assets. These files will be copied to the public directory un-modified. - font/ --> [fontawesome](http://fortawesome.github.com/Font-Awesome/) rendering icons - fontawesome-webfont.* img/ --> image files partials/ --> angular view partials (partial HTML templates) nav.html If you are using HTML you may modify these files directly. @@ -186,6 +211,9 @@ git pull origin master index.jade --> Index file. This will be converted to assets/index.html on save init.coffee --> application bootstrap + bower_components/ --> The bower_components dirctory is populated by Bower. + It contains Angular, Bootstrap Font-Awesome + and other utility files. node_modules --> NodeJS modules scripts/ --> handy shell scripts @@ -207,14 +235,13 @@ git pull origin master filters.spec.js --> specs for filters services.spec.js --> specs for services vendor/ - test-results.xml --> Testacular test resuls - karma-e2e.conf.js --> Testacular end-to-end tests config - karma.conf.js --> Testacular unit tests config + test-results.xml --> Karma test resuls + karma-e2e.conf.js --> Karma end-to-end tests config + karma.conf.js --> Karma unit tests config - vendor/ --> The vendor dirctory is populated by Bower. - It contains Angular, Bootstrap Font-Awesome - and other utility files. - component.json --> Bower component config + vendor/ --> The vendor directory is can be used for 3rd Party libraries. + Any files located in this directory will be included in js/vendor.js + bower.json --> Bower component config config.coffee --> Brunch config package.json --> node modules config diff --git a/app/app.coffee b/app/app.coffee index 9f9029d..c83adb8 100644 --- a/app/app.coffee +++ b/app/app.coffee @@ -1,31 +1,55 @@ + 'use strict' # Declare app level module which depends on filters, and services App = angular.module('app', [ + #used for angular-ui-router + 'ui.state' + 'ngCookies' 'ngResource' 'app.controllers' 'app.directives' 'app.filters' 'app.services' - 'partials' + 'navbar.partials' + 'todo.partials' + 'app.todo.controllers' + 'view1.partials' + 'app.view1.controllers' + 'view2.partials' + 'app.view2.controllers' ]) App.config([ - '$routeProvider' - '$locationProvider' + '$stateProvider' + '$urlRouterProvider' -($routeProvider, $locationProvider, config) -> + ($stateProvider, $urlRouterProvider) -> - $routeProvider + # default to the todo page + $urlRouterProvider.otherwise("/todo") + + $stateProvider - .when('/todo', {templateUrl: '/partials/todo.html'}) - .when('/view1', {templateUrl: '/partials/partial1.html'}) - .when('/view2', {templateUrl: '/partials/partial2.html'}) + .state('todo', + url: "/todo" + views: + "main-content": + templateUrl: "/todo/todo.html" + ) - # Catch all - .otherwise({redirectTo: '/todo'}) + .state('view1', + url: "/view1" + views: + "main-content": + templateUrl: "/view1/partial1.html" + ) - # Without server side support html5 must be disabled. - $locationProvider.html5Mode(false) + .state('view2', + url: "/view2" + views: + "main-content": + templateUrl: "/view2/partial2.html" + ) ]) diff --git a/app/index.jade b/app/index.jade index 6c2b039..7969f58 100644 --- a/app/index.jade +++ b/app/index.jade @@ -8,20 +8,7 @@ html(lang='en', ng-app='app') meta(name='author', content='') title(ng-bind-template='{{pageTitle}}') link(rel='stylesheet', href='/css/app.css') - //-script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js') - //if lte IE 7 - script(src='http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js') - //if lte IE 8 - script(src='//html5shiv.googlecode.com/svn/trunk/html5.js') - script - window.brunch = window.brunch || {}; - window.brunch['auto-reload'] = { - enabled: true - }; - script(src='/js/auto-reload.js') - script(src='/js/vendor.js') - script(src='/js/partials.js') - script(src='/js/app.js') + body(ng-controller='AppCtrl') .wrapper .navbar.navbar-static-top @@ -33,9 +20,9 @@ html(lang='en', ng-app='app') span.icon-bar a(href='/').brand Angular Brunch Seed .nav-collapse - div(ng-include="'/partials/nav.html'") + div(ng-include="'/navbar/nav.html'") .container.main-content - div(ng-view) + div(ui-view="main-content") div Angular Brunch seed app: v .push @@ -43,4 +30,22 @@ html(lang='en', ng-app='app') .container p small - a(href='https://github.com/scotch/angular-brunch-seed') angular-brunch-seed | source + a(href='https://github.com/scotch/angular-brunch-seed.git') angular-brunch-seed (modularized) | source + + //-script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js') + //if lte IE 7 + script(src='http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js') + //if lte IE 8 + script(src='//html5shiv.googlecode.com/svn/trunk/html5.js') + script. + window.brunch = window.brunch || {}; + window.brunch['auto-reload'] = { + enabled: true + }; + script(src='/js/auto-reload.js') + script(src='/js/vendor.js') + script(src='/js/navbar.partials.js') + script(src='/js/todo.partials.js') + script(src='/js/view1.partials.js') + script(src='/js/view2.partials.js') + script(src='/js/app.js') diff --git a/app/scripts/controllers.coffee b/app/scripts/controllers.coffee index 5c6ce68..0b5130b 100644 --- a/app/scripts/controllers.coffee +++ b/app/scripts/controllers.coffee @@ -11,6 +11,8 @@ angular.module('app.controllers', []) '$rootScope' ($scope, $location, $resource, $rootScope) -> + + $scope.appData = {} # Uses the url to determine if the selected # menu item should have the class active. @@ -32,54 +34,4 @@ angular.module('app.controllers', []) return 'active' else return '' -]) - -.controller('MyCtrl1', [ - '$scope' - -($scope) -> - $scope.onePlusOne = 2 -]) - -.controller('MyCtrl2', [ - '$scope' - -($scope) -> - $scope -]) - -.controller('TodoCtrl', [ - '$scope' - -($scope) -> - - $scope.todos = [ - text: "learn angular" - done: true - , - text: "build an angular app" - done: false - ] - - $scope.addTodo = -> - $scope.todos.push - text: $scope.todoText - done: false - - $scope.todoText = "" - - $scope.remaining = -> - count = 0 - angular.forEach $scope.todos, (todo) -> - count += (if todo.done then 0 else 1) - - count - - $scope.archive = -> - oldTodos = $scope.todos - $scope.todos = [] - angular.forEach oldTodos, (todo) -> - $scope.todos.push todo unless todo.done - -]) - +]) \ No newline at end of file diff --git a/app/partials/todo.jade b/app/sections/home/partials/todo.jade similarity index 100% rename from app/partials/todo.jade rename to app/sections/home/partials/todo.jade diff --git a/app/sections/home/scripts/home.controllers.coffee b/app/sections/home/scripts/home.controllers.coffee new file mode 100644 index 0000000..e0e2860 --- /dev/null +++ b/app/sections/home/scripts/home.controllers.coffee @@ -0,0 +1,37 @@ +angular.module('app.home.controllers', []) + +.controller('TodoCtrl', [ + '$scope' + +($scope) -> + + $scope.todos = [ + text: "learn angular" + done: true + , + text: "build an angular app" + done: false + ] + + $scope.addTodo = -> + $scope.todos.push + text: $scope.todoText + done: false + + $scope.todoText = "" + + $scope.remaining = -> + count = 0 + angular.forEach $scope.todos, (todo) -> + count += (if todo.done then 0 else 1) + + count + + $scope.archive = -> + oldTodos = $scope.todos + $scope.todos = [] + angular.forEach oldTodos, (todo) -> + $scope.todos.push todo unless todo.done + +]) + diff --git a/app/partials/nav.jade b/app/sections/navbar/partials/nav.jade similarity index 100% rename from app/partials/nav.jade rename to app/sections/navbar/partials/nav.jade diff --git a/app/sections/todo/partials/todo.jade b/app/sections/todo/partials/todo.jade new file mode 100644 index 0000000..2d24528 --- /dev/null +++ b/app/sections/todo/partials/todo.jade @@ -0,0 +1,16 @@ +div(ng-app='ng-app') + h2 Todo + div(ng-controller='TodoCtrl') + span {{remaining()}} of {{todos.length}} remaining + | [ + a(href='', ng-click='archive()') archive + | ] + ul.unstyled + li(ng-repeat='todo in todos') + label(class='checkbox inline') + input(type='checkbox', ng-model='todo.done') + span(class='done{{todo.done}}') {{todo.text}} + form(class='form-inline', ng-submit='addTodo()') + p + input(type='text', ng-model='todoText', size='30', placeholder='add new todo here') + input.btn.btn-primary(type='submit', value='add') diff --git a/app/sections/todo/scripts/todo.controllers.coffee b/app/sections/todo/scripts/todo.controllers.coffee new file mode 100644 index 0000000..943899b --- /dev/null +++ b/app/sections/todo/scripts/todo.controllers.coffee @@ -0,0 +1,37 @@ +angular.module('app.todo.controllers', []) + +.controller('TodoCtrl', [ + '$scope' + +($scope) -> + + $scope.todos = [ + text: "learn angular" + done: true + , + text: "build an angular app" + done: false + ] + + $scope.addTodo = -> + $scope.todos.push + text: $scope.todoText + done: false + + $scope.todoText = "" + + $scope.remaining = -> + count = 0 + angular.forEach $scope.todos, (todo) -> + count += (if todo.done then 0 else 1) + + count + + $scope.archive = -> + oldTodos = $scope.todos + $scope.todos = [] + angular.forEach oldTodos, (todo) -> + $scope.todos.push todo unless todo.done + +]) + diff --git a/app/sections/top/partials/nav.jade b/app/sections/top/partials/nav.jade new file mode 100644 index 0000000..fc31234 --- /dev/null +++ b/app/sections/top/partials/nav.jade @@ -0,0 +1,7 @@ +ul.nav + li(ng-class="getClass('/todo')") + a(ng-href='#/todo') todo + li(ng-class="getClass('/view1')") + a(ng-href='#/view1') view1 + li(ng-class="getClass('/view2')") + a(ng-href='#/view2') view2 diff --git a/app/partials/partial1.jade b/app/sections/view1/partials/partial1.jade similarity index 100% rename from app/partials/partial1.jade rename to app/sections/view1/partials/partial1.jade diff --git a/app/sections/view1/scripts/view1.controllers.coffee b/app/sections/view1/scripts/view1.controllers.coffee new file mode 100644 index 0000000..c234419 --- /dev/null +++ b/app/sections/view1/scripts/view1.controllers.coffee @@ -0,0 +1,10 @@ +'use strict' + +angular.module('app.view1.controllers', []) + +.controller('MyCtrl1', [ + '$scope' + +($scope) -> + $scope.onePlusOne = 2 +]) \ No newline at end of file diff --git a/app/partials/partial2.jade b/app/sections/view2/partials/partial2.jade similarity index 68% rename from app/partials/partial2.jade rename to app/sections/view2/partials/partial2.jade index eb8129a..52b9138 100644 --- a/app/partials/partial2.jade +++ b/app/sections/view2/partials/partial2.jade @@ -1,4 +1,4 @@ p This is the partial for view 2. p - | Showing of 'interpolate' filter: + | Demonstrating an 'interpolate' filter: | {{ 'Current version is v%VERSION%.' | interpolate }} diff --git a/app/sections/view2/scripts/view2.controllers.coffee b/app/sections/view2/scripts/view2.controllers.coffee new file mode 100644 index 0000000..71825fb --- /dev/null +++ b/app/sections/view2/scripts/view2.controllers.coffee @@ -0,0 +1,9 @@ +angular.module('app.view2.controllers', []) + +.controller('MyCtrl2', [ + '$scope' + +($scope) -> + $scope.twoPlusTwo = 4 +]) + diff --git a/app/styles/app.less b/app/styles/app.less index 7cc9e3a..32519d5 100644 --- a/app/styles/app.less +++ b/app/styles/app.less @@ -1,5 +1,5 @@ /*! - * Bootstrap v2.3.0 + * Bootstrap v2.3.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 @@ -9,7 +9,7 @@ */ // CSS Reset -@import "/vendor/bootstrap/less/reset.less"; +@import "/bower_components/bootstrap-less/less/reset.less"; // Theme variables // Uncomment the theme you would like to use. Themes may include @@ -17,87 +17,87 @@ // override.less file to the bottom of this file. // Bootstrap default -// @import "/vendor/bootstrap-less-themes/themes/default/variables.less"; +// @import "/bower_components/bootstrap-less-themes/themes/default/variables.less"; // Sapling default -// @import "/vendor/bootstrap-less-themes/themes/sapling/variables.less"; +@import "/bower_components/bootstrap-less-themes/themes/sapling/variables.less"; // Your custom theme @import "_variables.less"; // Core variables and mixins -@import "/vendor/bootstrap/less/mixins.less"; +@import "/bower_components/bootstrap-less/less/mixins.less"; // Grid system and page structure -@import "/vendor/bootstrap/less/scaffolding.less"; -@import "/vendor/bootstrap/less/grid.less"; -@import "/vendor/bootstrap/less/layouts.less"; +@import "/bower_components/bootstrap-less/less/scaffolding.less"; +@import "/bower_components/bootstrap-less/less/grid.less"; +@import "/bower_components/bootstrap-less/less/layouts.less"; // Base CSS -@import "/vendor/bootstrap/less/type.less"; -@import "/vendor/bootstrap/less/code.less"; -@import "/vendor/bootstrap/less/forms.less"; -@import "/vendor/bootstrap/less/tables.less"; +@import "/bower_components/bootstrap-less/less/type.less"; +@import "/bower_components/bootstrap-less/less/code.less"; +@import "/bower_components/bootstrap-less/less/forms.less"; +@import "/bower_components/bootstrap-less/less/tables.less"; // vendor: common -@import "/vendor/bootstrap/less/sprites.less"; +@import "/bower_components/bootstrap-less/less/sprites.less"; -@import "/vendor/font-awesome/less/font-awesome.less"; +// @import "/bower_components/font-awesome/less/font-awesome.less"; -@import "/vendor/bootstrap/less/dropdowns.less"; -@import "/vendor/bootstrap/less/wells.less"; -@import "/vendor/bootstrap/less/component-animations.less"; -@import "/vendor/bootstrap/less/close.less"; +@import "/bower_components/bootstrap-less/less/dropdowns.less"; +@import "/bower_components/bootstrap-less/less/wells.less"; +@import "/bower_components/bootstrap-less/less/component-animations.less"; +@import "/bower_components/bootstrap-less/less/close.less"; // vendor: Buttons & Alerts -@import "/vendor/bootstrap/less/buttons.less"; -@import "/vendor/bootstrap/less/button-groups.less"; -@import "/vendor/bootstrap/less/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less +@import "/bower_components/bootstrap-less/less/buttons.less"; +@import "/bower_components/bootstrap-less/less/button-groups.less"; +@import "/bower_components/bootstrap-less/less/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less // vendor: Nav -@import "/vendor/bootstrap/less/navs.less"; -@import "/vendor/bootstrap/less/navbar.less"; -@import "/vendor/bootstrap/less/breadcrumbs.less"; -@import "/vendor/bootstrap/less/pagination.less"; -@import "/vendor/bootstrap/less/pager.less"; +@import "/bower_components/bootstrap-less/less/navs.less"; +@import "/bower_components/bootstrap-less/less/navbar.less"; +@import "/bower_components/bootstrap-less/less/breadcrumbs.less"; +@import "/bower_components/bootstrap-less/less/pagination.less"; +@import "/bower_components/bootstrap-less/less/pager.less"; // vendor: Popovers -@import "/vendor/bootstrap/less/modals.less"; -@import "/vendor/bootstrap/less/tooltip.less"; -@import "/vendor/bootstrap/less/popovers.less"; +@import "/bower_components/bootstrap-less/less/modals.less"; +@import "/bower_components/bootstrap-less/less/tooltip.less"; +@import "/bower_components/bootstrap-less/less/popovers.less"; // vendor: Misc -@import "/vendor/bootstrap/less/thumbnails.less"; -@import "/vendor/bootstrap/less/media.less"; -@import "/vendor/bootstrap/less/labels-badges.less"; -@import "/vendor/bootstrap/less/progress-bars.less"; -@import "/vendor/bootstrap/less/accordion.less"; -@import "/vendor/bootstrap/less/carousel.less"; -@import "/vendor/bootstrap/less/hero-unit.less"; +@import "/bower_components/bootstrap-less/less/thumbnails.less"; +@import "/bower_components/bootstrap-less/less/media.less"; +@import "/bower_components/bootstrap-less/less/labels-badges.less"; +@import "/bower_components/bootstrap-less/less/progress-bars.less"; +@import "/bower_components/bootstrap-less/less/accordion.less"; +@import "/bower_components/bootstrap-less/less/carousel.less"; +@import "/bower_components/bootstrap-less/less/hero-unit.less"; // Componets: Footer -@import "/vendor/bootstrap-less-themes/themes/sapling/sticky-footer.less"; +@import "/bower_components/bootstrap-less-themes/themes/sapling/sticky-footer.less"; // Responsive -@import "/vendor/bootstrap/less/responsive-utilities.less"; -@import "/vendor/bootstrap/less/responsive-1200px-min.less"; -@import "/vendor/bootstrap/less/responsive-768px-979px.less"; -@import "/vendor/bootstrap/less/responsive-767px-max.less"; -@import "/vendor/bootstrap/less/responsive-navbar.less"; +@import "/bower_components/bootstrap-less/less/responsive-utilities.less"; +@import "/bower_components/bootstrap-less/less/responsive-1200px-min.less"; +@import "/bower_components/bootstrap-less/less/responsive-768px-979px.less"; +@import "/bower_components/bootstrap-less/less/responsive-767px-max.less"; +@import "/bower_components/bootstrap-less/less/responsive-navbar.less"; // AngularJS -@import "/vendor/bootstrap-less-themes/themes/angular/forms.less"; +@import "/bower_components/bootstrap-less-themes/themes/angular/forms.less"; // Utility classes -@import "/vendor/bootstrap/less/utilities.less"; // Has to be last to override when necessary +@import "/bower_components/bootstrap-less/less/utilities.less"; // Has to be last to override when necessary // Theme Overrides // Bootstrap default -// @import "/vendor/bootstrap-less-themes/themes/default/overrides.less"; +// @import "/bower_components/bootstrap-less-themes/themes/default/overrides.less"; // Sapling default -// @import "/vendor/bootstrap-less-themes/themes/sapling/overrides.less"; +@import "/bower_components/bootstrap-less-themes/themes/sapling/overrides.less"; // Your custom theme @import "_overrides.less"; diff --git a/bower.json b/bower.json index f826fc2..e1d800f 100644 --- a/bower.json +++ b/bower.json @@ -1,20 +1,34 @@ { "name": "angular-brunch-seed", + "repo": "scotch/angular-brunch-seed", "version": "0.3.0", - "main": [], + "main": "_public/js/app.js", + "ignore": [ + "**/.*", + "node_modules", + "components" + ], "dependencies": { - "console-polyfill": "*", - - "jquery": "1.8.3", - - "bootstrap": "~2.3.1", - "bootstrap-less-themes": "git://github.com/angular-brunch/bootstrap-less-themes.git", - "font-awesome": "3.0.2", - - "angular": "1.0.6", - "angular-sanitize": "1.0.6", - "angular-resource": "1.0.6", - "angular-cookies": "1.0.6", - "angular-mocks": "1.0.6" + "console-polyfill": "~0.1.0", + "jquery": "~2.0.3", + "bootstrap-less": "~2.3.2", + "bootstrap-less-themes": "https://github.com/angular-brunch/bootstrap-less-themes.git", + "angular-bootstrap": "~0.4.0", + "angular": "1.0.7", + "angular-sanitize": "1.0.7", + "angular-resource": "1.0.7", + "angular-cookies": "1.0.7", + "angular-mocks": "1.0.7", + "angular-ui-router": "0.0.1" + }, + "overrides": { + "bootstrap-less": { + "ignore": [ + "*" + ] + }, + "angular-mocks": { + "main": "README.md" + } } } diff --git a/config.coffee b/config.coffee index f8ce2c7..6d112f9 100644 --- a/config.coffee +++ b/config.coffee @@ -1,7 +1,6 @@ exports.config = # See docs at http://brunch.readthedocs.org/en/latest/config.html. conventions: - ignored: /(^vendor\\.*\.less)|(^vendor\/.*\.less)|(^|\/)node_modules\/|(^|\/)_/ assets: /^app\/assets\// modules: definition: false @@ -12,22 +11,11 @@ exports.config = javascripts: joinTo: 'js/app.js': /^app/ - 'js/vendor.js': /^vendor/ - 'test/scenarios.js': /^test(\/|\\)e2e/ - order: - before: [ - 'vendor/console-polyfill/index.js' - 'vendor/jquery/jquery.js' - 'vendor/angular/angular.js' - 'vendor/angular-resource/angular-resource.js' - 'vendor/angular-cookies/angular-cookies.js' - 'vendor/angular-sanitize/angular-sanitize.js' - 'vendor/bootstrap/docs/assets/js/bootstrap.js' - ] + 'js/vendor.js': /^(bower_components|vendor)/ stylesheets: joinTo: - 'css/app.css': /^(app|vendor)/ + 'css/app.css': /^(app|vendor|bower_components)/ order: before: [ 'app/styles/app.less' @@ -44,15 +32,5 @@ exports.config = modules_folder: 'partials' locals: {} - bower: - extend: - "bootstrap" : 'vendor/bootstrap/docs/assets/js/bootstrap.js' - "angular-mocks": [] - "styles": [] - asserts: - "img" : /bootstrap(\\|\/)img/ - "font": /font-awesome(\\|\/)font/ - - # Enable or disable minifying of result js / css files. # minify: true diff --git a/package.json b/package.json index d84e2f3..21f3a30 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,40 @@ { - "author": "Kyle Finley ", - "name": "sapling-seed", - "description": "AngularJS + Brunch", - "version": "0.3.0", - "homepage": "https://github.com/scotch/angular-brunch-seed", + "author": "Your Name", + "name": "package-name", + "description": "Package description", + "version": "0.0.1", + "homepage": "", "repository": { "type": "git", - "url": "https://github.com/scotch/angular-brunch-seed" - }, - "engines": { - "node": "~0.6.10 || 0.8 || 0.9" + "url": "" }, "scripts": { "start": "node_modules/.bin/brunch watch --server", "test": "node_modules/.bin/karma start test/karma.conf.js" }, "dependencies": { - "jade": ">= 0.28", - "coffee-script": ">= 1.4", - "brunch": ">= 1.5 < 1.6", + "jade": "~0.33", + "coffee-script": "~1.6", + "brunch": "~1.7", - "coffee-script-brunch": ">= 1.5 < 1.6", + "javascript-brunch": ">= 1.0 < 1.8", + "coffee-script-brunch": ">= 1.0 < 1.8", - "less-brunch": ">= 1.5 < 1.6", - "stylus-brunch": ">= 1.5 < 1.6", + "css-brunch": ">= 1.0 < 1.8", + "less-brunch": ">= 1.0 < 1.8", + "stylus-brunch": ">= 1.0 < 1.8", - "auto-reload-brunch": ">= 1.5 < 1.7", + "auto-reload-brunch": ">= 1.0 < 1.8", - "uglify-js-brunch": ">= 1.5 < 1.6", - "clean-css-brunch": ">= 1.5 < 1.6", + "uglify-js-brunch": ">= 1.0 < 1.8", + "clean-css-brunch": ">= 1.0 < 1.8", - "bower-stylesheet-brunch": "git://github.com/angular-brunch/bower-stylesheet-brunch/#master", - "bower-javascript-brunch": "git://github.com/angular-brunch/bower-javascript-brunch/#master", - "bower-asserts-brunch": "git://github.com/angular-brunch/bower-assets-brunch/#master", - "bower": "~0.9.2", + "bower": "~1.0", - "jade-angularjs-brunch": ">= 0.0.5 <= 0.1", + "jade-angularjs-brunch": "~0.0.5", - "karma": ">= 0.8.4 < 0.9.0" + "karma": "~0.9.4", + "karma-coffee-preprocessor": "~0.0.2", + "karma-ng-scenario": "~0.0.2" } } diff --git a/scripts/development.sh b/scripts/development.sh index ede6be7..80b174f 100755 --- a/scripts/development.sh +++ b/scripts/development.sh @@ -1,4 +1,4 @@ #!/bin/bash rm -rf _public -node_modules/.bin/brunch watch +node_modules/.bin/brunch watch --server diff --git a/scripts/init.bat b/scripts/init.bat index a67fec0..c75c50f 100644 --- a/scripts/init.bat +++ b/scripts/init.bat @@ -1,3 +1,4 @@ rd /s /q node_modules +rd /s /q bower_components npm install ./node_modules/.bin/bower install diff --git a/scripts/init.sh b/scripts/init.sh index 7c569da..65f876f 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -1,5 +1,5 @@ #!/bin/bash -rm -rf node_modules +rm -rf node_modules bower_components npm install ./node_modules/.bin/bower install diff --git a/test/e2e/app/scenario.coffee b/test/e2e/app/scenario.coffee index 7e4bc78..3e810e1 100644 --- a/test/e2e/app/scenario.coffee +++ b/test/e2e/app/scenario.coffee @@ -5,46 +5,63 @@ describe "my app", -> beforeEach -> browser().navigateTo "/" - it "should automatically redirect to /todo when location hash/fragment is empty", -> - expect(browser().location().url()).toBe "/todo" + NEW_ITEM_LABEL = "test newly added item" - it "should navigate to /view1 when the View 1 link in nav is clicked", -> + switchToToDo = -> + element(".nav a[href=\"#/todo\"]").click() + expect(browser().location().url()).toBe "/todo" + + switchToView1 = -> element(".nav a[href=\"#/view1\"]").click() expect(browser().location().url()).toBe "/view1" + it "should automatically redirect to /todo when location hash/fragment is empty", -> + expect(browser().location().url()).toBe "/todo" + describe "todo", -> + addToDoItem = -> + input("todoText").enter NEW_ITEM_LABEL + element("input[type=\"submit\"]").click() + expect(repeater("[ui-view] ul li").count()).toEqual 3 + expect(element("[ui-view] ul li:last span").text()).toEqual NEW_ITEM_LABEL + expect(input("todoText").val()).toEqual "" + it "should list 2 items", -> - expect(repeater("[ng-view] ul li").count()).toEqual 2 + expect(repeater("[ui-view] ul li").count()).toEqual 2 it "should display checked items with a line-through", -> - expect(element("[ng-view] ul li input:checked + span").css("text-decoration")).toEqual "line-through" + expect(element("[ui-view] ul li input:checked + span").css("text-decoration")).toEqual "line-through" it "should sync done status with checkbox state", -> - element("[ng-view] ul li input:not(:checked)").click() - expect(element("[ng-view] ul li span").attr("class")).toEqual "donetrue" - element("[ng-view] ul li input:checked").click() - expect(element("[ng-view] ul li span").attr("class")).toEqual "donefalse" + element("[ui-view] ul li input:not(:checked)").click() + expect(element("[ui-view] ul li span").attr("class")).toEqual "donetrue" + element("[ui-view] ul li input:checked").click() + expect(element("[ui-view] ul li span").attr("class")).toEqual "donefalse" it "should remove checked items when the archive link is clicked", -> - element("[ng-view] a[ng-click=\"archive()\"]").click() - expect(repeater("[ng-view] ul li").count()).toEqual 1 - - it "should add a newly submitted item to the end of the list and empty the text input", -> - newItemLabel = "test newly added item" - input("todoText").enter newItemLabel - element("[ng-view] input[type=\"submit\"]").click() - expect(repeater("[ng-view] ul li").count()).toEqual 3 - expect(element("[ng-view] ul li:last span").text()).toEqual newItemLabel - expect(input("todoText").val()).toEqual "" + element("[ui-view] a[ng-click=\"archive()\"]").click() + expect(repeater("[ui-view] ul li").count()).toEqual 1 + + it "should add a newly submitted item to the end of the list and empty the text input", addToDoItem + it "should still have a newly submitted item after switching views", -> + addToDoItem + switchToView1 + switchToToDo + expect(repeater("[ui-view] ul li").count()).toEqual 3 + expect(element("[ui-view] ul li:last span").text()).toEqual NEW_ITEM_LABEL + + + it "should navigate to /view1 when the View 1 link in nav is clicked", -> + switchToView1 describe "view1", -> beforeEach -> browser().navigateTo "#/view1" it "should render view1 when user navigates to /view1", -> - expect(element("[ng-view] p:first").text()).toMatch /partial for view 1/ + expect(element("p:first").text()).toMatch /partial for view 1/ describe "view2", -> @@ -52,4 +69,4 @@ describe "my app", -> browser().navigateTo "#/view2" it "should render view2 when user navigates to /view2", -> - expect(element("[ng-view] p:first").text()).toMatch /partial for view 2/ + expect(element("p:first").text()).toMatch /partial for view 2/ diff --git a/test/karma-e2e.conf.js b/test/karma-e2e.conf.js index b8dc3f6..806e6d8 100644 --- a/test/karma-e2e.conf.js +++ b/test/karma-e2e.conf.js @@ -1,25 +1,86 @@ -basePath = '../'; +// Karma configuration -files = [ - ANGULAR_SCENARIO, - ANGULAR_SCENARIO_ADAPTER, - 'test/e2e/**/*.js', - 'test/e2e/**/*.coffee' -]; +module.exports = function(karma) { + karma.configure({ -autoWatch = false; + // base path, that will be used to resolve files and exclude + basePath: '../', -browsers = ['Chrome']; -singleRun = true; + // frameworks to use + frameworks: ['ng-scenario'], -urlRoot = '/__karma/'; -proxies = { - '/': 'http://localhost:3333/' -}; + // list of files / patterns to load in the browser + files: [ + 'test/e2e/**/*.js', + 'test/e2e/**/*.coffee' + ], + + // list of files to exclude + exclude: [ + // 'vendor/angular-mocks/angular-mocks.min.js', + ], + + + // test results reporter to use + // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' + reporters: ['progress'], + + + // web server port + port: 9876, + + + // cli runner port + runnerPort: 9100, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG + logLevel: karma.LOG_INFO, + + + urlRoot: '/__karma/', + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['Chrome'], + + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000, + + + // Plugins to load + plugins: [ + 'karma-ng-scenario', + 'karma-coffee-preprocessor', + 'karma-chrome-launcher' + ], + + + proxies: { + '/': 'http://localhost:3333/' + }, -// compile coffee scripts -preprocessors = { - '**/*.coffee': 'coffee' + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + }); }; diff --git a/test/karma.conf.js b/test/karma.conf.js index 3f0aeb5..9e3e000 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -1,92 +1,88 @@ // Karma configuration +module.exports = function(karma) { + karma.configure({ -// base path, that will be used to resolve files and exclude -basePath = '../'; + // base path, that will be used to resolve files and exclude + basePath: '../', -// list of files / patterns to load in the browser -files = [ - JASMINE, - JASMINE_ADAPTER, - // Application Code // - 'vendor/jquery/jquery.js', - 'vendor/angular/angular.js', - 'vendor/angular-*/angular-*.js', - 'vendor/bootstrap/docs/assets/js/bootstrap.js', + // frameworks to use + frameworks: ['jasmine'], - //'app/scripts/**/*.js', - 'app/scripts/**/*.coffee', - // Specs // + // list of files / patterns to load in the browser + files: [ - // CoffeeScript // - 'test/unit/**/*.spec.coffee' + // Program files + '_public/js/vendor.js', + '_public/js/app.js', - // Javascript // - // 'test/unit/**/*.spec.js' -]; + // Specs -// list of files to exclude -exclude = [ - 'vendor/angular-mocks/angular-mocks.min.js', -]; + // Load mocks directly from bower + 'bower_components/angular-mocks/angular-mocks.js', -// use dots reporter, as travis terminal does not support escaping sequences -// possible values: 'dots', 'progress', 'junit' -// CLI --reporters progress -reporters = ['progress', 'junit']; + 'test/unit/**/*.spec.*' + ], + + + // list of files to exclude + exclude: [ + ], + + + // test results reporter to use + // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' + reporters: ['progress'], + + + // web server port + port: 9876, + + + // cli runner port + runnerPort: 9100, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG + logLevel: karma.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['Chrome'], + + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000, + + + // Plugins to load + plugins: [ + 'karma-jasmine', + 'karma-coffee-preprocessor', + 'karma-chrome-launcher' + ], -junitReporter = { - // will be resolved to basePath (in the same way as files/exclude patterns) - outputFile: 'test/test-results.xml' -}; -// web server port -// CLI --port 3334 -port = 3334; - -// cli runner port -// CLI --runner-port 9100 -runnerPort = 9100; - -// enable / disable colors in the output (reporters and logs) -// CLI --colors --no-colors -colors = true; - -// level of logging -// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG -// CLI --log-level debug -logLevel = LOG_INFO; - -// enable / disable watching file and executing tests whenever any file changes -// CLI --auto-watch --no-auto-watch -autoWatch = true; - -// Start these browsers, currently available: -// - Chrome -// - ChromeCanary -// - Firefox -// - Opera -// - Safari (only Mac) -// - PhantomJS -// - IE (only Windows) -// CLI --browsers Chrome,Firefox,Safari -browsers = []; - -// If browser does not capture in given timeout [ms], kill it -// CLI --capture-timeout 5000 -captureTimeout = 5000; - -// Auto run tests on start (when browsers are captured) and exit -// CLI --single-run --no-single-run -singleRun = false; - -// report which specs are slower than 500ms -// CLI --report-slower-than 500 -reportSlowerThan = 500; - -// compile coffee scripts -preprocessors = { - '**/*.coffee': 'coffee' + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + }); }; diff --git a/test/unit/contoller.spec.coffee b/test/unit/contoller.spec.coffee index a14ac3e..c24735e 100644 --- a/test/unit/contoller.spec.coffee +++ b/test/unit/contoller.spec.coffee @@ -3,18 +3,3 @@ # jasmine specs for controllers go here # TODO figure out how to test Controllers that use modules -describe "controllers", -> - - beforeEach(module "app.controllers") - - describe "MyCtrl1", -> - - it "should make scope testable", inject ($rootScope, $controller) -> - scope = $rootScope.$new() - ctrl = $controller "MyCtrl1", - $scope: scope, - expect(scope.onePlusOne).toEqual(2) - - describe "MyCtrl2", -> - - it "should..." diff --git a/test/unit/sections/view1/view1.controller.spec.coffee b/test/unit/sections/view1/view1.controller.spec.coffee new file mode 100644 index 0000000..6ac5020 --- /dev/null +++ b/test/unit/sections/view1/view1.controller.spec.coffee @@ -0,0 +1,11 @@ +describe "controllers", -> + + beforeEach(module "app.view1.controllers") + + describe "MyCtrl1", -> + + it "should make scope testable", inject ($rootScope, $controller) -> + scope = $rootScope.$new() + ctrl = $controller "MyCtrl1", + $scope: scope, + expect(scope.onePlusOne).toEqual(2) \ No newline at end of file diff --git a/test/unit/sections/view2/view2.controller.spec.coffee b/test/unit/sections/view2/view2.controller.spec.coffee new file mode 100644 index 0000000..c96acde --- /dev/null +++ b/test/unit/sections/view2/view2.controller.spec.coffee @@ -0,0 +1,11 @@ +describe "controllers", -> + + beforeEach(module "app.view2.controllers") + + describe "MyCtrl2", -> + + it "should make scope testable", inject ($rootScope, $controller) -> + scope = $rootScope.$new() + ctrl = $controller "MyCtrl2", + $scope: scope, + expect(scope.twoPlusTwo).toEqual(4) \ No newline at end of file