diff --git a/.jshintrc b/.jshintrc index 2683e48..64d8459 100644 --- a/.jshintrc +++ b/.jshintrc @@ -7,7 +7,7 @@ "eqeqeq": true, "immed": true, "indent": 2, - "latedef": true, + "latedef": false, "newcap": true, "noarg": true, "quotmark": "single", @@ -30,6 +30,8 @@ "beforeEach": false, "after": false, "afterEach": false, - "expect": false + "expect": false, + // Lodash + "_": false } } diff --git a/README.md b/README.md index c94b1cc..463c131 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,22 @@ devices sync - `angular-templatecache` - all HTML partials will be converted to JS to be bundled in the application +`Protractor` is using `Google Chrome` to execute tests. You 
should make sure you +have `Chrome` installed or switch to another browser in 
`protractor.conf.js`. +Note that a browser change in the config requires 
additional dependencies in +`package.json` if the browser driver is not installed. + +`Karma` is using `PhantomJS` for testing which is automatically installed by +`npm install`. + +## Replace favicon + +The favicons for this boilerplate were generated using +[favicon-generator](http://www.favicon-generator.org). In order to replace the +current favicon all you have to do is access the mentioned website, generate +your own favicon images set and replace it with the current one in the +`src/favicon` folder. + ## Style Guide ### Directory structure @@ -96,56 +112,56 @@ functionality and lower-level divisions by component types: ``` . ├── src/app -│   ├── app.js +│   ├── index.module.js │   ├── common │   │   ├── controllers │   │   ├── directives │   │   ├── filters │   │   └── services │   ├── home -│   │   ├── controllers -│   │   │   ├── FirstCtrl.js -│   │   │   └── SecondCtrl.js +│   │   ├── home.module.js +│   │   ├── home.controller.js +│   │   ├── home.template.html │   │   ├── directives -│   │   │   └── directive1.js +│   │   │   ├── directive-name-1 +│   │   │ │ ├── directive-name-1.directive.js +│   │   │ │ ├── directive-name-1.controller.js +│   │   │ │ └── directive-name-1.template.html +│   │   │   └── directive-name-2 +│   │   │ └── ... │   │   ├── filters -│   │   │   ├── filter1.js -│   │   │   └── filter2.js +│   │   │   ├── filter-name-1.js +│   │   │   └── filter-name-2.js │   │   └── services -│   │   ├── service1.js -│   │   └── service2.js +│   │   ├── service-name-1.js +│   │   └── service-name-2.js │   └── about -│   ├── controllers -│   │   └── ThirdCtrl.js +│   ├── about.module.js +│   ├── about.controller.js +│   ├── about.template.html │   ├── directives -│   │   ├── directive2.js -│   │   └── directive3.js +│      │   ├── directive-name-3 +│      │ │ ├── directive-name-3.directive.js +│      │ │ ├── directive-name-3.controller.js +│      │ │ └── directive-name-3.template.html +│      │   └── directive-name-4 │   ├── filters -│   │   └── filter3.js +│   │   └── filter-name-3.js │   └── services -│   └── service3.js +│   └── service-name-3.js ├── src/assets -├── src/partials -└── e2e -    ├── home -    │   ├── FirstCtrl.spec.js -    │   ├── SecondCtrl.spec.js -    ├── about -    │   └── ThirdCtrl.spec.js -    └── about +└── tests +    ├── e2e + │ ├── home.po.js + │ ├── home.spec.js +    │   ├── about.po.js +    │   └── about.spec.js +    └── unit + ├── home.controller.spec.js + └── about.controller.spec.js ``` -- In case the directory name contains multiple words, use lisp-case syntax: - -``` -src/app - ├── app.js - └── my-complex-module -    ├── controllers -    ├── directives -    ├── filters -    └── services -``` +- In case the directory name contains multiple words, use lisp-case syntax. - When creating directives it may be useful to put all the files associated with the given directive files (templates, CSS/SASS files, JavaScript) in @@ -153,15 +169,16 @@ a single folder. Be consistent and use it everywhere along your project. ``` src/app -└── directives - ├── directive-category - │   ├── category.html - │   ├── category.js - │   └── category.sass - └── directive-product - ├── product.html - ├── product.js - └── product.sass +└── page + └── directives + ├── directive-category + │   ├── category.html + │   ├── category.js + │   └── category.sass + └── directive-product + ├── product.html + ├── product.js + └── product.sass ``` ### Markup @@ -176,7 +193,7 @@ This way is easy to look to the code and understand: ``` -- Other HTML atributes should follow the Code Guide's +- Other HTML attributes should follow the Code Guide's [recommendation](http://mdo.github.io/code-guide/#html-attribute-order) ### Optimize the digest cycle diff --git a/bower.json b/bower.json index 852b148..0a2f86f 100644 --- a/bower.json +++ b/bower.json @@ -2,17 +2,18 @@ "name": "angular-boilerplate", "version": "0.0.0", "dependencies": { - "angular-touch": "~1.4.0", - "restangular": "~1.4.0", - "angular-ui-router": "~0.2.13", - "bootstrap-sass-official": "~3.3.1", - "angular-bootstrap": "~0.12.1", - "angular": "~1.3.13" + "angular": "~1.3.20", + "angular-bootstrap": "~0.13.4", + "restangular": "~1.5.1", + "angular-touch": "~1.3.20", + "angular-ui-router": "~0.2.15", + "bootstrap-sass": "3.3.3", + "angular-mocks": "~1.3.20" }, "devDependencies": { - "angular-mocks": "~1.3.13" + "jquery": "~2.2.0" }, "resolutions": { - "angular": "~1.3.13" + "angular": "~1.3.20" } } diff --git a/gulp/build.js b/gulp/build.js index 2c6c0c9..fc33f97 100644 --- a/gulp/build.js +++ b/gulp/build.js @@ -19,7 +19,7 @@ gulp.task('partials', function () { quotes: true })) .pipe($.angularTemplatecache('templateCacheHtml.js', { - module: 'test' + module: 'app' })) .pipe(gulp.dest(paths.tmp + '/partials/')); }); @@ -46,7 +46,7 @@ gulp.task('html', ['inject', 'partials'], function () { .pipe($.uglify({preserveComments: $.uglifySaveLicense})) .pipe(jsFilter.restore()) .pipe(cssFilter) - .pipe($.replace('../bootstrap-sass-official/assets/fonts/bootstrap', 'fonts')) + .pipe($.replace('../bower_components/bootstrap-sass/assets/fonts/bootstrap', 'fonts')) .pipe($.csso()) .pipe(cssFilter.restore()) .pipe(assets.restore()) @@ -70,14 +70,14 @@ gulp.task('images', function () { gulp.task('fonts', function () { return gulp.src($.mainBowerFiles()) - .pipe($.filter('**/*.{eot,svg,ttf,woff}')) + .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) .pipe($.flatten()) .pipe(gulp.dest(paths.dist + '/fonts/')); }); gulp.task('misc', function () { - return gulp.src(paths.src + '/**/*.ico') - .pipe(gulp.dest(paths.dist + '/')); + return gulp.src(paths.src + '/favicons/*') + .pipe(gulp.dest(paths.dist + '/favicons/')); }); gulp.task('clean', function (done) { diff --git a/gulp/e2e-tests.js b/gulp/e2e-tests.js index 99ab2c5..bc266ab 100644 --- a/gulp/e2e-tests.js +++ b/gulp/e2e-tests.js @@ -1,32 +1,26 @@ 'use strict'; var gulp = require('gulp'); - -var $ = require('gulp-load-plugins')(); - +var protractor = require("gulp-protractor").protractor; var browserSync = require('browser-sync'); - var paths = gulp.paths; // Downloads the selenium webdriver -gulp.task('webdriver-update', $.protractor.webdriver_update); - -gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); +gulp.task('webdriver-update', protractor.webdriver_update); +gulp.task('webdriver-standalone', protractor.webdriver_standalone); function runProtractor (done) { - - gulp.src(paths.e2e + '/**/*.js') - .pipe($.protractor.protractor({ - configFile: 'protractor.conf.js', + gulp.src('tests/e2e/**/*.js') + .pipe(protractor({ + configFile: 'protractor.conf.js' })) .on('error', function (err) { // Make sure failed tests cause gulp to exit non-zero throw err; }) - .on('end', function () { - // Close browser sync server - browserSync.exit(); + .on('end', function() { done(); + browserSync.exit(); }); } diff --git a/gulp/inject.js b/gulp/inject.js index 4a277b8..4ab3020 100644 --- a/gulp/inject.js +++ b/gulp/inject.js @@ -28,7 +28,7 @@ gulp.task('inject', ['styles'], function () { var wiredepOptions = { directory: 'bower_components', - exclude: [/bootstrap-sass-official/, /bootstrap\.css/, /bootstrap\.css/, /foundation\.css/] + exclude: [/bootstrap-sass/, /bootstrap\.css/, /bootstrap\.css/, /foundation\.css/] }; return gulp.src(paths.src + '/*.html') diff --git a/gulp/unit-tests.js b/gulp/unit-tests.js index f13a9c0..bae7222 100644 --- a/gulp/unit-tests.js +++ b/gulp/unit-tests.js @@ -1,33 +1,18 @@ 'use strict'; var gulp = require('gulp'); - -var $ = require('gulp-load-plugins')(); - -var wiredep = require('wiredep'); - -var paths = gulp.paths; +var karma = require('gulp-karma'); function runTests (singleRun, done) { - var bowerDeps = wiredep({ - directory: 'bower_components', - exclude: ['bootstrap-sass-official'], - dependencies: true, - devDependencies: true - }); - - var testFiles = bowerDeps.js.concat([ - paths.src + '/{app,components}/**/*.js' - ]); - - gulp.src(testFiles) - .pipe($.karma({ + return gulp.src('./imaginary-path') + .pipe(karma({ configFile: 'karma.conf.js', action: (singleRun)? 'run': 'watch' })) - .on('error', function (err) { + .on('error', function(err) { // Make sure failed tests cause gulp to exit non-zero - throw err; + console.log(err); + this.emit('end'); //instead of erroring the stream, end it }); } diff --git a/karma.conf.js b/karma.conf.js index 12e3ff3..f916f67 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,17 +1,69 @@ 'use strict'; module.exports = function(config) { - config.set({ - autoWatch : false, + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine'], - browsers : ['PhantomJS'], + // list of files / patterns to load in the browser + // loading order is important + files: [ + // load angular and angular-mocks + 'bower_components/angular/angular.js', + 'bower_components/angular-mocks/angular-mocks.js', + + // load modules first + 'src/app/**/*.module.js', + // load other app files + 'src/app/**/*.js', + + // load unit tests + 'tests/unit/**/*.js' + ], + + // list of files to exclude + exclude: [ + + ], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + + }, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['spec'], + + // web server port + port: 9876, + // enable / disable colors in the output (reporters and logs) + colors: true, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: [ + 'PhantomJS' + // , 'Chrome' + // , 'Firefox' + // , 'Safari' + ], + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, - plugins : [ - 'karma-phantomjs-launcher', - 'karma-jasmine' - ] + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false }); }; diff --git a/package.json b/package.json index faf4964..890e5fb 100644 --- a/package.json +++ b/package.json @@ -3,46 +3,53 @@ "version": "0.0.0", "dependencies": {}, "devDependencies": { - "gulp": "~3.8.11", - "gulp-autoprefixer": "~2.1.0", + "browser-sync": "~1.9.1", + "chalk": "^1.0.0", + "del": "^2.2.0", + "graceful-fs": "^4.1.3", + "gulp": "^3.9.1", + "gulp-angular-filesort": "~1.1.1", "gulp-angular-templatecache": "~1.5.0", - "del": "~1.1.0", + "gulp-autoprefixer": "~2.1.0", "gulp-consolidate": "~0.1.2", "gulp-csso": "~1.0.0", "gulp-filter": "~2.0.2", "gulp-flatten": "~0.0.4", - "gulp-jshint": "~1.9.0", + "gulp-inject": "~1.2.0", "gulp-jscs": "~1.4.0", - "gulp-load-plugins": "~0.8.1", - "gulp-size": "~1.2.1", - "gulp-uglify": "~1.1.0", - "gulp-useref": "~1.1.1", + "gulp-jshint": "~1.9.0", + "gulp-karma": "0.0.5", + "gulp-load-plugins": "^1.2.2", + "gulp-minify-html": "~1.0.1", "gulp-ng-annotate": "~0.5.2", "gulp-param": "^0.6.3", - "gulp-replace": "~0.5.0", + "gulp-protractor": "^2.3.0", "gulp-rename": "~1.2.0", + "gulp-replace": "~0.5.0", "gulp-rev": "~3.0.1", "gulp-rev-replace": "~0.4.0", - "gulp-minify-html": "~1.0.1", - "gulp-inject": "~1.2.0", - "gulp-protractor": "~0.0.11", - "gulp-karma": "~0.0.4", - "gulp-sass": "~1.1.0", - "gulp-angular-filesort": "~1.1.1", - "main-bower-files": "~2.5.0", - "jshint-stylish": "~1.0.0", - "wiredep": "~2.2.0", - "karma-jasmine": "~0.3.1", - "karma-phantomjs-launcher": "~0.1.4", + "gulp-sass": "^2.3.1", + "gulp-size": "~1.2.1", + "gulp-uglify": "~1.1.0", + "gulp-useref": "~1.1.1", + "http-proxy": "~1.8.1", + "jshint-stylish": "^2.1.0", + "karma": "^0.13.22", "karma-firefox-launcher": "~0.1.4", + "karma-jasmine": "~0.3.1", + "karma-phantomjs-launcher": "^1.0.0", + "karma-spec-reporter": "0.0.26", + "main-bower-files": "~2.5.0", + "node-sass": "^3.6.0", + "phantomjs-prebuilt": "^2.1.7", "require-dir": "~0.1.0", - "browser-sync": "~1.9.1", - "http-proxy": "~1.8.1", - "chalk": "~1.0.0", - "protractor": "~1.8.0", - "uglify-save-license": "~0.4.1" + "uglify-save-license": "~0.4.1", + "wiredep": "~2.2.0" }, "engines": { "node": ">=0.10.0" + }, + "scripts": { + "postinstall": "./node_modules/gulp-protractor/node_modules/protractor/bin/webdriver-manager update" } } diff --git a/protractor.conf.js b/protractor.conf.js index e1fbcdd..5f87ee1 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -1,9 +1,5 @@ 'use strict'; -var paths = { - e2e: 'ete' -}; - // An example configuration file. exports.config = { // The address of a running selenium server. @@ -12,16 +8,17 @@ exports.config = { // Capabilities to be passed to the webdriver instance. capabilities: { - 'browserName': 'firefox' + 'browserName': 'phantomjs', + 'phantomjs.binary.path': 'node_modules/phantomjs-prebuilt/bin/phantomjs' }, // Spec patterns are relative to the current working directly when // protractor is called. - specs: [paths.e2e + '/**/*.js'], + specs: ['test/e2e/**/*.js'], // Options to be passed to Jasmine-node. jasmineNodeOpts: { showColors: true, - defaultTimeoutInterval: 30000 + defaultTimeoutInterval: 15000 } }; diff --git a/src/app/index.js b/src/app/index.js deleted file mode 100644 index c4a6386..0000000 --- a/src/app/index.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -angular.module('test', ['ngTouch', 'restangular', 'ui.router', 'ui.bootstrap']) - .config(function($stateProvider, $urlRouterProvider) { - $stateProvider - .state('home', { - url: '/', - templateUrl: 'app/main/main.html', - controller: 'MainCtrl' - }); - - $urlRouterProvider.otherwise('/'); - }) -; diff --git a/src/app/index.module.js b/src/app/index.module.js new file mode 100644 index 0000000..f50e4ec --- /dev/null +++ b/src/app/index.module.js @@ -0,0 +1,32 @@ +(function indexIIFE() { + 'use strict'; + + angular + .module('app', [ + 'ngTouch', + 'restangular', + 'ui.router', + 'ui.bootstrap', + + 'app.testPage' + ]) + .config(appConfigFunc) + .run(appRunFunc); + + appConfigFunc.$inject = ['$stateProvider', '$urlRouterProvider']; + + function appConfigFunc($stateProvider, $urlRouterProvider) { + $stateProvider + .state('home', { + url: '/', + templateUrl: 'app/testPage/test-page.template.html', + controller: 'TestPageCtrl' + }); + + $urlRouterProvider.otherwise('/'); + } + + function appRunFunc() { + + } +})(); diff --git a/src/app/testPage/directives/navbar/navbar.controller.js b/src/app/testPage/directives/navbar/navbar.controller.js new file mode 100644 index 0000000..ed50645 --- /dev/null +++ b/src/app/testPage/directives/navbar/navbar.controller.js @@ -0,0 +1,16 @@ +/** + * Created by rares on 19/04/16. + */ +(function navbarCtrlIIFE() { + 'use strict'; + + angular + .module('app.testPage') + .controller('NavbarCtrl', NavbarCtrlFunc); + + NavbarCtrlFunc.$inject = ['$scope']; + + function NavbarCtrlFunc($scope) { + $scope.date = new Date(); + } +})(); diff --git a/src/app/testPage/directives/navbar/navbar.directive.js b/src/app/testPage/directives/navbar/navbar.directive.js new file mode 100644 index 0000000..48b3e5e --- /dev/null +++ b/src/app/testPage/directives/navbar/navbar.directive.js @@ -0,0 +1,15 @@ +(function navbarDirectiveIIFE() { + 'use strict'; + + angular + .module('app.testPage') + .directive('navbar', navbarFunc); + + function navbarFunc() { + return { + restrict: 'E', + controller: 'NavbarCtrl', + templateUrl: 'app/testPage/directives/navbar/navbar.template.html' + }; + } +})(); diff --git a/src/components/navbar/navbar.html b/src/app/testPage/directives/navbar/navbar.template.html similarity index 88% rename from src/components/navbar/navbar.html rename to src/app/testPage/directives/navbar/navbar.template.html index 046e696..169563d 100644 --- a/src/components/navbar/navbar.html +++ b/src/app/testPage/directives/navbar/navbar.template.html @@ -1,4 +1,4 @@ -