From 102078dda98d2db9aacb9eb67d5d45ed0dbb1af9 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Mon, 25 Aug 2014 01:06:36 -0600 Subject: [PATCH 001/201] use more restrictive matching for serve-favicon version --- app/templates/_package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 36256461c..e32849740 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -7,7 +7,7 @@ "morgan": "~1.0.0", "body-parser": "~1.5.0", "method-override": "~1.0.0", - "serve-favicon": "^2.0.1", + "serve-favicon": "~2.0.1", "cookie-parser": "~1.0.1", "express-session": "~1.0.2", "errorhandler": "~1.0.0", From 6aecdf7fc8929fe4853280d0e8ac878f3e2a20fd Mon Sep 17 00:00:00 2001 From: Patrick Baker Date: Tue, 26 Aug 2014 18:01:38 -0400 Subject: [PATCH 002/201] feat(auth): make crypto async - Update tests and add new test for changed password - User.authenticate() User.makeSalt() and User.encryptPassword() public API remains same - User.authenticate() User.makeSalt() and User.encryptPassword() callbacks are optional - Change User schema from hashedPassword to password - Remove unnecessary virtual attribute User.password, getters and setters are not async --- app/templates/server/.jshintrc | 1 + .../server/api/user(auth)/user.controller.js | 26 +++-- .../server/api/user(auth)/user.model.js | 104 +++++++++++++----- .../server/api/user(auth)/user.model.spec.js | 49 +++++++-- .../server/auth(auth)/local/passport.js | 14 ++- 5 files changed, 141 insertions(+), 53 deletions(-) diff --git a/app/templates/server/.jshintrc b/app/templates/server/.jshintrc index d7b958e7c..42fea558a 100644 --- a/app/templates/server/.jshintrc +++ b/app/templates/server/.jshintrc @@ -1,4 +1,5 @@ { + "expr": true, "node": true, "esnext": true, "bitwise": true, diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index f4cd10c29..17e6e0e04 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -14,7 +14,7 @@ var validationError = function(res, err) { * restriction: 'admin' */ exports.index = function(req, res) { - User.find({}, '-salt -hashedPassword', function (err, users) { + User.find({}, '-salt -password', function (err, users) { if(err) return res.send(500, err); res.json(200, users); }); @@ -67,15 +67,19 @@ exports.changePassword = function(req, res, next) { var newPass = String(req.body.newPassword); User.findById(userId, function (err, user) { - if(user.authenticate(oldPass)) { - user.password = newPass; - user.save(function(err) { - if (err) return validationError(res, err); - res.send(200); - }); - } else { - res.send(403); - } + user.authenticate(oldPass, function(authErr, authenticated) { + if (authErr) res.send(403); + + if (authenticated) { + user.password = newPass; + user.save(function(err) { + if (err) return validationError(res, err); + res.send(200); + }); + } else { + res.send(403); + } + }); }); }; @@ -86,7 +90,7 @@ exports.me = function(req, res, next) { var userId = req.user._id; User.findOne({ _id: userId - }, '-salt -hashedPassword', function(err, user) { // don't ever give out the password or salt + }, '-salt -password', function(err, user) { // don't ever give out the password or salt if (err) return next(err); if (!user) return res.json(401); res.json(user); diff --git a/app/templates/server/api/user(auth)/user.model.js b/app/templates/server/api/user(auth)/user.model.js index cc8d59263..b3497f859 100644 --- a/app/templates/server/api/user(auth)/user.model.js +++ b/app/templates/server/api/user(auth)/user.model.js @@ -12,7 +12,7 @@ var UserSchema = new Schema({ type: String, default: 'user' }, - hashedPassword: String, + password: String, provider: String, salt: String<% if (filters.oauth) { %>,<% if (filters.facebookAuth) { %> facebook: {},<% } %><% if (filters.twitterAuth) { %> @@ -24,16 +24,6 @@ var UserSchema = new Schema({ /** * Virtuals */ -UserSchema - .virtual('password') - .set(function(password) { - this._password = password; - this.salt = this.makeSalt(); - this.hashedPassword = this.encryptPassword(password); - }) - .get(function() { - return this._password; - }); // Public profile information UserSchema @@ -69,10 +59,10 @@ UserSchema // Validate empty password UserSchema - .path('hashedPassword') - .validate(function(hashedPassword) {<% if (filters.oauth) { %> + .path('password') + .validate(function(password) {<% if (filters.oauth) { %> if (authTypes.indexOf(this.provider) !== -1) return true;<% } %> - return hashedPassword.length; + return password.length; }, 'Password cannot be blank'); // Validate email is not taken @@ -99,12 +89,26 @@ var validatePresenceOf = function(value) { */ UserSchema .pre('save', function(next) { - if (!this.isNew) return next(); - - if (!validatePresenceOf(this.hashedPassword)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) - next(new Error('Invalid password')); - else + // Handle new/update passwords + if (this.password) { + if (!validatePresenceOf(this.password)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) + next(new Error('Invalid password')); + + // Make salt with a callback + var _this = this; + this.makeSalt(function(saltErr, salt) { + if (saltErr) next(saltErr); + _this.salt = salt; + // Async hash + _this.encryptPassword(_this.password, function(encryptErr, hashedPassword) { + if (encryptErr) next(encryptErr); + _this.password = hashedPassword; + next(); + }); + }); + } else { next(); + } }); /** @@ -115,34 +119,82 @@ UserSchema.methods = { * Authenticate - check if the passwords are the same * * @param {String} plainText + * @callback {callback} Optional callback * @return {Boolean} * @api public */ - authenticate: function(plainText) { - return this.encryptPassword(plainText) === this.hashedPassword; + authenticate: function(password, callback) { + if (!callback) + return this.password === this.encryptPassword(password); + + var _this = this; + this.encryptPassword(password, function(err, pwdGen) { + if (err) callback(err); + + if (_this.password === pwdGen) { + callback(null, true); + } else { + callback(null, false); + } + }); }, /** * Make salt * + * @param {Number} byteSize Optional salt byte size, default to 16 + * @callback {callback} Optional callback * @return {String} * @api public */ - makeSalt: function() { - return crypto.randomBytes(16).toString('base64'); + makeSalt: function(byteSize, callback) { + var defaultByteSize = 16; + + if (typeof arguments[0] === 'function') { + callback = arguments[0]; + byteSize = defaultByteSize; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + + if (!byteSize) { + byteSize = defaultByteSize; + } + + if (!callback) { + return crypto.randomBytes(byteSize).toString('base64'); + } + + return crypto.randomBytes(byteSize, function(err, salt) { + if (err) callback(err); + return callback(null, salt.toString('base64')); + }); }, /** * Encrypt password * * @param {String} password + * @callback {callback} Optional callback * @return {String} * @api public */ - encryptPassword: function(password) { - if (!password || !this.salt) return ''; + encryptPassword: function(password, callback) { + if (!password || !this.salt) { + return null; + } + + var defaultIterations = 10000; + var defaultKeyLength = 64; var salt = new Buffer(this.salt, 'base64'); - return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64'); + + if (!callback) + return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength).toString('base64'); + + return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, function(err, key) { + if (err) callback(err); + return callback(null, key.toString('base64')); + }); } }; diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index 257c95b7c..95e8bfbd8 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -4,14 +4,9 @@ var should = require('should'); var app = require('../../app'); var User = require('./user.model'); -var user = new User({ - provider: 'local', - name: 'Fake User', - email: 'test@test.com', - password: 'password' -}); - describe('User Model', function() { + var user; + before(function(done) { // Clear users before testing User.remove().exec().then(function() { @@ -20,6 +15,15 @@ describe('User Model', function() { }); afterEach(function(done) { + // Start from scratch + user = new User({ + provider: 'local', + name: 'Fake User', + email: 'test@test.com', + password: 'password' + }); + + // Clear all users User.remove().exec().then(function() { done(); }); @@ -50,11 +54,34 @@ describe('User Model', function() { }); }); - it("should authenticate user if password is valid", function() { - return user.authenticate('password').should.be.true; + it("should authenticate user if password is valid", function(done) { + user.save(function(err, newUser) { + newUser.authenticate('password', function(authErr, authenticated) { + authenticated.should.be.true; + done(); + }); + }); + }); + + it("should not authenticate user if password is invalid", function(done) { + user.save(function(err, newUser) { + newUser.authenticate('invalidPassword', function(authErr, authenticated) { + authenticated.should.not.be.true; + done(); + }); + }); }); - it("should not authenticate user if password is invalid", function() { - return user.authenticate('blah').should.not.be.true; + it("should authenticate after updating password", function(done) { + user.save(function(err, newUser) { + newUser.password = 'newPassword'; + newUser.save(function() { + newUser.authenticate('newPassword', function(authErr, authenticated) { + authenticated.should.be.true; + done(); + }); + }); + }); }); + }); diff --git a/app/templates/server/auth(auth)/local/passport.js b/app/templates/server/auth(auth)/local/passport.js index ac82b42a2..4221f8786 100644 --- a/app/templates/server/auth(auth)/local/passport.js +++ b/app/templates/server/auth(auth)/local/passport.js @@ -15,11 +15,15 @@ exports.setup = function (User, config) { if (!user) { return done(null, false, { message: 'This email is not registered.' }); } - if (!user.authenticate(password)) { - return done(null, false, { message: 'This password is not correct.' }); - } - return done(null, user); + user.authenticate(password, function(authError, authenticated) { + if (authError) return done(authError); + if (!authenticated) { + return done(null, false, { message: 'This password is not correct.' }); + } else { + return done(null, user); + } + }); }); } )); -}; \ No newline at end of file +}; From de5c36ca3003ea9ef149eb26ca8393d6ab2d8a4a Mon Sep 17 00:00:00 2001 From: kingcody Date: Fri, 29 Aug 2014 11:05:05 -0400 Subject: [PATCH 003/201] refactor(server-tests): use sinon-chai and `mocha.conf.js` Changes: - add `mocha.conf.js` and use it as a `require` in `mochaTest` task - switch `should.js` for `mocha-chai` - change server-side test assertions to user chai assertions Breaking Changes: - should.js is no longer included, chai assertions should be used instead. --- app/templates/Gruntfile.js | 3 ++- app/templates/_package.json | 3 ++- app/templates/mocha.conf.js | 12 +++++++++++ app/templates/server/api/thing/thing.spec.js | 3 +-- .../server/api/user(auth)/user.model.spec.js | 20 ++++++++----------- endpoint/templates/name.spec.js | 5 ++--- test/fixtures/package.json | 3 ++- 7 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 app/templates/mocha.conf.js diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 998ca5620..d98992888 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -486,7 +486,8 @@ module.exports = function (grunt) { mochaTest: { options: { - reporter: 'spec' + reporter: 'spec', + require: 'mocha.conf.js' }, src: ['server/**/*.spec.js'] }, diff --git a/app/templates/_package.json b/app/templates/_package.json index e32849740..7b2cf48d5 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -30,6 +30,7 @@ "socketio-jwt": "^2.0.2"<% } %> }, "devDependencies": { + "chai-as-promised": "^4.1.1", "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-wiredep": "~1.8.0", @@ -86,7 +87,7 @@ "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", "supertest": "~0.11.0", - "should": "~3.3.1" + "sinon-chai": "^2.5.0" }, "engines": { "node": ">=0.10.0" diff --git a/app/templates/mocha.conf.js b/app/templates/mocha.conf.js new file mode 100644 index 000000000..7bfaa573f --- /dev/null +++ b/app/templates/mocha.conf.js @@ -0,0 +1,12 @@ +'use strict'; + +var chai = require('chai'); +var sinon = require('sinon'); +var sinonChai = require('sinon-chai'); +var chaiAsPromised = require('chai-as-promised'); + +global.expect = chai.expect; +global.assert = chai.assert; +chai.should(); +chai.use(sinonChai); +chai.use(chaiAsPromised); diff --git a/app/templates/server/api/thing/thing.spec.js b/app/templates/server/api/thing/thing.spec.js index 17c8c6cd0..3f135445b 100644 --- a/app/templates/server/api/thing/thing.spec.js +++ b/app/templates/server/api/thing/thing.spec.js @@ -1,6 +1,5 @@ 'use strict'; -var should = require('should'); var app = require('../../app'); var request = require('supertest'); @@ -13,7 +12,7 @@ describe('GET /api/things', function() { .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); - res.body.should.be.instanceof(Array); + res.body.should.be.instanceOf(Array); done(); }); }); diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index 257c95b7c..8960ca859 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -1,6 +1,5 @@ 'use strict'; -var should = require('should'); var app = require('../../app'); var User = require('./user.model'); @@ -12,17 +11,14 @@ var user = new User({ }); describe('User Model', function() { - before(function(done) { - // Clear users before testing - User.remove().exec().then(function() { - done(); - }); + + // Clear users before testing + before(function() { + return User.remove().exec(); }); - afterEach(function(done) { - User.remove().exec().then(function() { - done(); - }); + afterEach(function() { + return User.remove().exec(); }); it('should begin with no users', function(done) { @@ -36,7 +32,7 @@ describe('User Model', function() { user.save(function() { var userDup = new User(user); userDup.save(function(err) { - should.exist(err); + err.should.be.instanceOf(Error); done(); }); }); @@ -45,7 +41,7 @@ describe('User Model', function() { it('should fail when saving without an email', function(done) { user.email = ''; user.save(function(err) { - should.exist(err); + err.should.be.instanceOf(Error); done(); }); }); diff --git a/endpoint/templates/name.spec.js b/endpoint/templates/name.spec.js index fcad73ebd..d287bafe5 100644 --- a/endpoint/templates/name.spec.js +++ b/endpoint/templates/name.spec.js @@ -1,6 +1,5 @@ 'use strict'; -var should = require('should'); var app = require('../../app'); var request = require('supertest'); @@ -13,8 +12,8 @@ describe('GET <%= route %>', function() { .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); - res.body.should.be.instanceof(Array); + res.body.should.be.instanceOf(Array); done(); }); }); -}); \ No newline at end of file +}); diff --git a/test/fixtures/package.json b/test/fixtures/package.json index ce4df22f9..9bdfd30ff 100644 --- a/test/fixtures/package.json +++ b/test/fixtures/package.json @@ -30,6 +30,7 @@ "socketio-jwt": "^2.0.2" }, "devDependencies": { + "chai-as-promised": "^4.1.1", "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-wiredep": "~1.8.0", @@ -86,7 +87,7 @@ "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", "supertest": "~0.11.0", - "should": "~3.3.1" + "sinon-chai": "^2.5.0" }, "engines": { "node": ">=0.10.0" From dbbaa20b47629be60de8ce5f31a7c91abf9bdaef Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 30 Aug 2014 07:53:03 -0400 Subject: [PATCH 004/201] feat(server-tests): code coverage and e2e Changes: - split server tests into `unit` and `e2e` type test - adjust `mochaTest` and `test:server` tasks to reflect the two types of tests - implement `grunt-mocha-istanbul` task for server-side code coverage - add `test:coverage` task - improve `mocha.conf.js` - add sinon, expect, and assert as globals to `server/.jshintrc-spec` - add `proxyquire` to the app for better stubbing in unit tests - improve test to reflect recent changes and to lay ground work for more coverage Grunt Task `test`: The grunt 'test' task now has a 'coverage' target. Used like so `grunt test:coverage`. This task will run istanbul for the server unit tests and e2e test separately. The resulting coverage reports will be placed in `coverage/(unit|e2e)`. There is also an option for the `test:coverage` task, possibilities for option are: - `unit` - `e2e` - `check` `test:coverage:check` will check the coverage reports for both `unit` and `e2e` and report whether or not they meet the required coverage. --- app/templates/Gruntfile.js | 94 +++++++++++- app/templates/_package.json | 4 +- app/templates/mocha.conf.js | 2 + app/templates/server/.jshintrc-spec | 5 +- app/templates/server/api/thing/index.js | 2 +- app/templates/server/api/thing/index.spec.js | 85 +++++++++++ .../server/api/thing/thing.controller.js | 2 +- app/templates/server/api/thing/thing.e2e.js | 135 ++++++++++++++++++ .../server/api/thing/thing.model(mongoose).js | 2 +- .../api/thing/thing.socket(socketio).js | 2 +- app/templates/server/api/thing/thing.spec.js | 19 --- app/templates/server/api/user(auth)/index.js | 1 - .../server/api/user(auth)/index.spec.js | 95 ++++++++++++ .../server/api/user(auth)/user.e2e.js | 68 +++++++++ .../server/api/user(auth)/user.model.spec.js | 66 +++++---- endpoint/templates/index.spec.js | 85 +++++++++++ endpoint/templates/name.e2e.js | 135 ++++++++++++++++++ endpoint/templates/name.spec.js | 19 --- test/fixtures/package.json | 2 + 19 files changed, 748 insertions(+), 75 deletions(-) create mode 100644 app/templates/server/api/thing/index.spec.js create mode 100644 app/templates/server/api/thing/thing.e2e.js delete mode 100644 app/templates/server/api/thing/thing.spec.js create mode 100644 app/templates/server/api/user(auth)/index.spec.js create mode 100644 app/templates/server/api/user(auth)/user.e2e.js create mode 100644 endpoint/templates/index.spec.js create mode 100644 endpoint/templates/name.e2e.js delete mode 100644 endpoint/templates/name.spec.js diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index d98992888..26866c21d 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -169,14 +169,14 @@ module.exports = function (grunt) { }, src: [ 'server/**/*.js', - '!server/**/*.spec.js' + '!server/**/*.{spec,e2e}.js' ] }, serverTest: { options: { jshintrc: 'server/.jshintrc-spec' }, - src: ['server/**/*.spec.js'] + src: ['server/**/*.{spec,e2e}.js'] }, all: [ '<%%= yeoman.client %>/{app,components}/**/*.js', @@ -489,7 +489,57 @@ module.exports = function (grunt) { reporter: 'spec', require: 'mocha.conf.js' }, - src: ['server/**/*.spec.js'] + unit: { + src: ['server/**/*.spec.js'] + }, + e2e: { + src: ['server/**/*.e2e.js'] + } + }, + + mocha_istanbul: { + unit: { + options: { + excludes: [ + '**/*.spec.js', + '**/*.mock.js', + '**/*.e2e.js' + ], + reporter: 'spec', + require: ['mocha.conf.js'], + mask: '**/*.spec.js', + coverageFolder: 'coverage/unit' + }, + src: 'server' + }, + e2e: { + options: { + excludes: [ + '**/*.spec.js', + '**/*.mock.js', + '**/*.e2e.js' + ], + reporter: 'spec', + require: ['mocha.conf.js'], + mask: '**/*.e2e.js', + coverageFolder: 'coverage/e2e' + }, + src: 'server' + } + }, + + istanbul_check_coverage: { + default: { + options: { + coverageFolder: 'coverage/*', + check: { + lines: 80, + statements: 80, + branches: 80, + functions: 80 + } + } + } }, protractor: { @@ -770,7 +820,8 @@ module.exports = function (grunt) { return grunt.task.run([ 'env:all', 'env:test', - 'mochaTest' + 'mochaTest:unit', + 'mochaTest:e2e' ]); } @@ -805,6 +856,41 @@ module.exports = function (grunt) { ]); } + else if (target === 'coverage') { + + if (option === 'unit') { + return grunt.task.run([ + 'env:all', + 'env:test', + 'mocha_istanbul:unit' + ]); + } + + else if (option === 'e2e') { + return grunt.task.run([ + 'env:all', + 'env:test', + 'mocha_istanbul:e2e' + ]); + } + + else if (option === 'check') { + return grunt.task.run([ + 'istanbul_check_coverage' + ]); + } + + else { + return grunt.task.run([ + 'env:all', + 'env:test', + 'mocha_istanbul', + 'istanbul_check_coverage' + ]); + } + + } + else grunt.task.run([ 'test:server', 'test:client' diff --git a/app/templates/_package.json b/app/templates/_package.json index 7b2cf48d5..9dfdadc5d 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -62,7 +62,8 @@ "grunt-asset-injector": "^0.1.0", "grunt-karma": "~0.8.2", "grunt-build-control": "DaftMonk/grunt-build-control", - "grunt-mocha-test": "~0.10.2",<% if(filters.sass) { %> + "grunt-mocha-test": "~0.10.2", + "grunt-mocha-istanbul": "^2.0.0",<% if(filters.sass) { %> "grunt-contrib-sass": "^0.7.3",<% } %><% if(filters.stylus) { %> "grunt-contrib-stylus": "latest",<% } %> "jit-grunt": "^0.5.0", @@ -86,6 +87,7 @@ "karma-phantomjs-launcher": "~0.1.4", "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", + "proxyquire": "^1.0.1", "supertest": "~0.11.0", "sinon-chai": "^2.5.0" }, diff --git a/app/templates/mocha.conf.js b/app/templates/mocha.conf.js index 7bfaa573f..497d43b2c 100644 --- a/app/templates/mocha.conf.js +++ b/app/templates/mocha.conf.js @@ -7,6 +7,8 @@ var chaiAsPromised = require('chai-as-promised'); global.expect = chai.expect; global.assert = chai.assert; +global.sinon = sinon; + chai.should(); chai.use(sinonChai); chai.use(chaiAsPromised); diff --git a/app/templates/server/.jshintrc-spec b/app/templates/server/.jshintrc-spec index b6b55cbf9..b9390c374 100644 --- a/app/templates/server/.jshintrc-spec +++ b/app/templates/server/.jshintrc-spec @@ -6,6 +6,9 @@ "before": true, "beforeEach": true, "after": true, - "afterEach": true + "afterEach": true, + "expect": true, + "assert": true, + "sinon": true } } diff --git a/app/templates/server/api/thing/index.js b/app/templates/server/api/thing/index.js index 242ed5901..e77e80c5b 100644 --- a/app/templates/server/api/thing/index.js +++ b/app/templates/server/api/thing/index.js @@ -12,4 +12,4 @@ router.put('/:id', controller.update); router.patch('/:id', controller.update); router.delete('/:id', controller.destroy);<% } %> -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js new file mode 100644 index 000000000..0fbfb1029 --- /dev/null +++ b/app/templates/server/api/thing/index.spec.js @@ -0,0 +1,85 @@ +'use strict'; + +var proxyquire = require('proxyquire').noPreserveCache(); + + /* thing.controller stub */ +var thingCtrl = { + index: 'thingCtrl.index'<% if(filters.mongoose) { %>, + show: 'thingCtrl.show', + create: 'thingCtrl.create', + update: 'thingCtrl.update', + destroy: 'thingCtrl.destroy'<% } %> + }, + /* express.Router().router stub */ + router = { + get: sinon.spy()<% if(filters.mongoose) { %>, + put: sinon.spy(), + patch: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy()<% } %> + }, + /* stubbed thing router */ + index = proxyquire('./index.js', { + 'express': { + Router: function() { + return router; + } + }, + './thing.controller': thingCtrl + }); + +describe('Thing API Router:', function() { + + it('should return an express router instance', function() { + index.should.equal(router); + }); + + describe('GET /api/things', function() { + + it('should route to thing.controller.index', function() { + return router.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; + }); + + });<% if(filters.mongoose) { %> + + describe('GET /api/things/:id', function() { + + it('should route to thing.controller.show', function() { + return router.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; + }); + + }); + + describe('POST /api/things', function() { + + it('should route to thing.controller.create', function() { + return router.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; + }); + + }); + + describe('PUT /api/things/:id', function() { + + it('should route to thing.controller.update', function() { + return router.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + }); + + }); + + describe('PATCH /api/things/:id', function() { + + it('should route to thing.controller.update', function() { + return router.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + }); + + }); + + describe('DELETE /api/things/:id', function() { + + it('should route to thing.controller.destroy', function() { + return router.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; + }); + + });<% } %> + +}); diff --git a/app/templates/server/api/thing/thing.controller.js b/app/templates/server/api/thing/thing.controller.js index ba84d6fc9..72a678cf4 100644 --- a/app/templates/server/api/thing/thing.controller.js +++ b/app/templates/server/api/thing/thing.controller.js @@ -86,4 +86,4 @@ exports.destroy = function(req, res) { function handleError(res, err) { return res.send(500, err); -}<% } %> \ No newline at end of file +}<% } %> diff --git a/app/templates/server/api/thing/thing.e2e.js b/app/templates/server/api/thing/thing.e2e.js new file mode 100644 index 000000000..1140df7e9 --- /dev/null +++ b/app/templates/server/api/thing/thing.e2e.js @@ -0,0 +1,135 @@ +'use strict'; + +var app = require('../../app'); +var request = require('supertest');<% if(filters.mongoose) { %> + +var newThing;<% } %> + +describe('Thing API:', function() { + + describe('GET /api/things', function() { + var things; + + beforeEach(function(done) { + request(app) + .get('/api/things') + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + things = res.body; + done(); + }); + }); + + it('should respond with JSON array', function() { + things.should.be.instanceOf(Array); + }); + + });<% if(filters.mongoose) { %> + + describe('POST /api/things', function() { + beforeEach(function(done) { + request(app) + .post('/api/things') + .send({ + name: 'New Thing', + info: 'This is the brand new thing!!!' + }) + .expect(201) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + newThing = res.body; + done(); + }); + }); + + it('should respond with the newly created thing', function() { + newThing.name.should.equal('New Thing'); + newThing.info.should.equal('This is the brand new thing!!!'); + }); + + }); + + describe('GET /api/things/:id', function() { + var thing; + + beforeEach(function(done) { + request(app) + .get('/api/things/' + newThing._id) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + thing = res.body; + done(); + }); + }); + + afterEach(function() { + thing = {}; + }); + + it('should respond with the requested thing', function() { + thing.name.should.equal('New Thing'); + thing.info.should.equal('This is the brand new thing!!!'); + }); + + }); + + describe('PUT /api/things/:id', function() { + var updatedThing + + beforeEach(function(done) { + request(app) + .put('/api/things/' + newThing._id) + .send({ + name: 'Updated Thing', + info: 'This is the updated thing!!!' + }) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + updatedThing = res.body; + done(); + }); + }); + + afterEach(function() { + updatedThing = {}; + }); + + it('should respond with the updated thing', function() { + updatedThing.name.should.equal('Updated Thing'); + updatedThing.info.should.equal('This is the updated thing!!!'); + }); + + }); + + describe('DELETE /api/things/:id', function() { + + it('should respond with 204 on successful removal', function(done) { + request(app) + .delete('/api/things/' + newThing._id) + .expect(204) + .end(function(err, res) { + if (err) return done(err); + done(); + }); + }); + + it('should respond with 404 when thing does not exsist', function(done) { + request(app) + .delete('/api/things/' + newThing._id) + .expect(404) + .end(function(err, res) { + if (err) return done(err); + done(); + }); + }); + + });<% } %> + +}); diff --git a/app/templates/server/api/thing/thing.model(mongoose).js b/app/templates/server/api/thing/thing.model(mongoose).js index ed857cd3b..92a791e70 100644 --- a/app/templates/server/api/thing/thing.model(mongoose).js +++ b/app/templates/server/api/thing/thing.model(mongoose).js @@ -9,4 +9,4 @@ var ThingSchema = new Schema({ active: Boolean }); -module.exports = mongoose.model('Thing', ThingSchema); \ No newline at end of file +module.exports = mongoose.model('Thing', ThingSchema); diff --git a/app/templates/server/api/thing/thing.socket(socketio).js b/app/templates/server/api/thing/thing.socket(socketio).js index 79d327695..dbf3e2fe7 100644 --- a/app/templates/server/api/thing/thing.socket(socketio).js +++ b/app/templates/server/api/thing/thing.socket(socketio).js @@ -21,4 +21,4 @@ function onSave(socket, doc, cb) { function onRemove(socket, doc, cb) { socket.emit('thing:remove', doc); -} \ No newline at end of file +} diff --git a/app/templates/server/api/thing/thing.spec.js b/app/templates/server/api/thing/thing.spec.js deleted file mode 100644 index 3f135445b..000000000 --- a/app/templates/server/api/thing/thing.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -var app = require('../../app'); -var request = require('supertest'); - -describe('GET /api/things', function() { - - it('should respond with JSON array', function(done) { - request(app) - .get('/api/things') - .expect(200) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) return done(err); - res.body.should.be.instanceOf(Array); - done(); - }); - }); -}); diff --git a/app/templates/server/api/user(auth)/index.js b/app/templates/server/api/user(auth)/index.js index 48567e485..be6fd3af3 100644 --- a/app/templates/server/api/user(auth)/index.js +++ b/app/templates/server/api/user(auth)/index.js @@ -2,7 +2,6 @@ var express = require('express'); var controller = require('./user.controller'); -var config = require('../../config/environment'); var auth = require('../../auth/auth.service'); var router = express.Router(); diff --git a/app/templates/server/api/user(auth)/index.spec.js b/app/templates/server/api/user(auth)/index.spec.js new file mode 100644 index 000000000..5bcd4c2c0 --- /dev/null +++ b/app/templates/server/api/user(auth)/index.spec.js @@ -0,0 +1,95 @@ +'use strict'; + +var proxyquire = require('proxyquire').noPreserveCache(); + + /* user.controller stub */ +var userCtrl = { + index: 'userCtrl.index', + destroy: 'userCtrl.destroy', + me: 'userCtrl.me', + changePassword: 'userCtrl.changePassword', + show: 'userCtrl.show', + create: 'userCtrl.create' + }, + /* auth.service stub */ + authService = { + isAuthenticated: function() { + return 'authService.isAuthenticated'; + }, + hasRole: function(role) { + return 'authService.hasRole.' + role; + } + }, + /* express.Router().router stub */ + router = { + get: sinon.spy(), + put: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy() + }, + /* stubbed user router */ + index = proxyquire('./index', { + 'express': { + Router: function() { + return router; + } + }, + './user.controller': userCtrl, + '../../auth/auth.service': authService + }); + +describe('User API Router:', function() { + + it('should return an express router instance', function() { + index.should.equal(router); + }); + + describe('GET /api/users', function() { + + it('should verify admin role and route to user.controller.index', function() { + return router.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; + }); + + }); + + describe('DELETE /api/users/:id', function() { + + it('should verify admin role and route to user.controller.destroy', function() { + return router.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; + }); + + }); + + describe('GET /api/users/me', function() { + + it('should be authenticated and route to user.controller.me', function() { + return router.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; + }); + + }); + + describe('PUT /api/users/:id/password', function() { + + it('should be authenticated and route to user.controller.changePassword', function() { + return router.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; + }); + + }); + + describe('GET /api/users/:id', function() { + + it('should be authenticated and route to user.controller.show', function() { + return router.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; + }); + + }); + + describe('POST /api/users', function() { + + it('should route to user.controller.create', function() { + return router.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; + }); + + }); + +}); diff --git a/app/templates/server/api/user(auth)/user.e2e.js b/app/templates/server/api/user(auth)/user.e2e.js new file mode 100644 index 000000000..917acedd9 --- /dev/null +++ b/app/templates/server/api/user(auth)/user.e2e.js @@ -0,0 +1,68 @@ +'use strict'; + +var app = require('../../app'); +var User = require('./user.model'); +var request = require('supertest'); + +describe('User API:', function() { + var user; + + // Clear users before testing + before(function(done) { + User.remove(function() { + user = new User({ + name: 'Fake User', + email: 'test@test.com', + password: 'password' + }); + + user.save(function(err) { + if (err) return done(err); + done(); + }); + }); + }); + + // Clear users after testing + after(function() { + return User.remove().exec(); + }); + + describe('GET /api/users/me', function() { + var token; + + before(function(done) { + request(app) + .post('/auth/local') + .send({ + email: 'test@test.com', + password: 'password' + }) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + token = res.body.token; + done(); + }); + }); + + it('should respond with a user profile when authenticated', function(done) { + request(app) + .get('/api/users/me') + .set('authorization', 'Bearer ' + token) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + res.body._id.should.equal(user._id.toString()); + done(); + }); + }); + + it('should respond with a 401 when not authenticated', function(done) { + request(app) + .get('/api/users/me') + .expect(401) + .end(done); + }); + }); +}); diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index 8960ca859..0df9a2d5b 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -10,47 +10,61 @@ var user = new User({ password: 'password' }); -describe('User Model', function() { +describe('User Model:', function() { // Clear users before testing before(function() { return User.remove().exec(); }); - afterEach(function() { - return User.remove().exec(); - }); + describe('User (schema)', function() { - it('should begin with no users', function(done) { - User.find({}, function(err, users) { - users.should.have.length(0); - done(); + it('should begin with no users', function() { + return User.find({}).exec().should.eventually.have.length(0); }); + }); - it('should fail when saving a duplicate user', function(done) { - user.save(function() { - var userDup = new User(user); - userDup.save(function(err) { - err.should.be.instanceOf(Error); - done(); + describe('user (instance)', function() { + + describe('.save()', function() { + // Clear users after tests + afterEach(function() { + return User.remove().exec(); }); + + it('should fail when saving a duplicate user', function(done) { + user.save(function() { + var userDup = new User(user); + userDup.save(function(err) { + err.should.be.instanceOf(Error); + done(); + }); + }); + }); + + it('should fail when saving without an email', function(done) { + user.email = ''; + user.save(function(err) { + err.should.be.instanceOf(Error); + done(); + }); + }); + }); - }); - it('should fail when saving without an email', function(done) { - user.email = ''; - user.save(function(err) { - err.should.be.instanceOf(Error); - done(); + describe('.authenticate()', function() { + + it("should authenticate user if password is valid", function() { + return user.authenticate('password').should.be.true; + }); + + it("should not authenticate user if password is invalid", function() { + return user.authenticate('blah').should.not.be.true; + }); + }); - }); - it("should authenticate user if password is valid", function() { - return user.authenticate('password').should.be.true; }); - it("should not authenticate user if password is invalid", function() { - return user.authenticate('blah').should.not.be.true; - }); }); diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js new file mode 100644 index 000000000..62caed5dc --- /dev/null +++ b/endpoint/templates/index.spec.js @@ -0,0 +1,85 @@ +'use strict'; + +var proxyquire = require('proxyquire').noPreserveCache(); + + /* <%= name %>.controller stub */ +var <%= name %>Ctrl = { + index: '<%= name %>Ctrl.index'<% if(filters.mongoose) { %>, + show: '<%= name %>Ctrl.show', + create: '<%= name %>Ctrl.create', + update: '<%= name %>Ctrl.update', + destroy: '<%= name %>Ctrl.destroy'<% } %> + }, + /* express.Router().router stub */ + router = { + get: sinon.spy()<% if(filters.mongoose) { %>, + put: sinon.spy(), + patch: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy()<% } %> + }, + /* stubbed <%= name %> router */ + index = proxyquire('./index.js', { + 'express': { + Router: function() { + return router; + } + }, + './<%= name %>.controller': <%= name %>Ctrl + }); + +describe('<%= classedName %> API Router:', function() { + + it('should return an express router instance', function() { + index.should.equal(router); + }); + + describe('GET <%= route %>', function() { + + it('should route to <%= name %>.controller.index', function() { + return router.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; + }); + + });<% if(filters.mongoose) { %> + + describe('GET <%= route %>/:id', function() { + + it('should route to <%= name %>.controller.show', function() { + return router.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; + }); + + }); + + describe('POST <%= route %>', function() { + + it('should route to <%= name %>.controller.create', function() { + return router.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; + }); + + }); + + describe('PUT <%= route %>/:id', function() { + + it('should route to <%= name %>.controller.update', function() { + return router.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + }); + + }); + + describe('PATCH <%= route %>/:id', function() { + + it('should route to <%= name %>.controller.update', function() { + return router.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + }); + + }); + + describe('DELETE <%= route %>/:id', function() { + + it('should route to <%= name %>.controller.destroy', function() { + return router.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; + }); + + });<% } %> + +}); diff --git a/endpoint/templates/name.e2e.js b/endpoint/templates/name.e2e.js new file mode 100644 index 000000000..5960b40a2 --- /dev/null +++ b/endpoint/templates/name.e2e.js @@ -0,0 +1,135 @@ +'use strict'; + +var app = require('../../app'); +var request = require('supertest');<% if(filters.mongoose) { %> + +var new<%= classedName %>;<% } %> + +describe('<%= classedName %> API:', function() { + + describe('GET <%= route %>', function() { + var <%= name %>s; + + beforeEach(function(done) { + request(app) + .get('<%= route %>') + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + <%= name %>s = res.body; + done(); + }); + }); + + it('should respond with JSON array', function() { + <%= name %>s.should.be.instanceOf(Array); + }); + + });<% if(filters.mongoose) { %> + + describe('POST <%= route %>', function() { + beforeEach(function(done) { + request(app) + .post('<%= route %>') + .send({ + name: 'New <%= classedName %>', + info: 'This is the brand new <%= name %>!!!' + }) + .expect(201) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + new<%= classedName %> = res.body; + done(); + }); + }); + + it('should respond with the newly created <%= name %>', function() { + new<%= classedName %>.name.should.equal('New <%= classedName %>'); + new<%= classedName %>.info.should.equal('This is the brand new <%= name %>!!!'); + }); + + }); + + describe('GET <%= route %>/:id', function() { + var <%= name %>; + + beforeEach(function(done) { + request(app) + .get('<%= route %>/' + new<%= classedName %>._id) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + <%= name %> = res.body; + done(); + }); + }); + + afterEach(function() { + <%= name %> = {}; + }); + + it('should respond with the requested <%= name %>', function() { + <%= name %>.name.should.equal('New <%= classedName %>'); + <%= name %>.info.should.equal('This is the brand new <%= name %>!!!'); + }); + + }); + + describe('PUT <%= route %>/:id', function() { + var updated<%= classedName %> + + beforeEach(function(done) { + request(app) + .put('<%= route %>/' + new<%= classedName %>._id) + .send({ + name: 'Updated <%= classedName %>', + info: 'This is the updated <%= name %>!!!' + }) + .expect(200) + .expect('Content-Type', /json/) + .end(function(err, res) { + if (err) return done(err); + updated<%= classedName %> = res.body; + done(); + }); + }); + + afterEach(function() { + updated<%= classedName %> = {}; + }); + + it('should respond with the updated <%= name %>', function() { + updated<%= classedName %>.name.should.equal('Updated <%= classedName %>'); + updated<%= classedName %>.info.should.equal('This is the updated <%= name %>!!!'); + }); + + }); + + describe('DELETE <%= route %>/:id', function() { + + it('should respond with 204 on successful removal', function(done) { + request(app) + .delete('<%= route %>/' + new<%= classedName %>._id) + .expect(204) + .end(function(err, res) { + if (err) return done(err); + done(); + }); + }); + + it('should respond with 404 when <%= name %> does not exsist', function(done) { + request(app) + .delete('<%= route %>/' + new<%= classedName %>._id) + .expect(404) + .end(function(err, res) { + if (err) return done(err); + done(); + }); + }); + + });<% } %> + +}); diff --git a/endpoint/templates/name.spec.js b/endpoint/templates/name.spec.js deleted file mode 100644 index d287bafe5..000000000 --- a/endpoint/templates/name.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -var app = require('../../app'); -var request = require('supertest'); - -describe('GET <%= route %>', function() { - - it('should respond with JSON array', function(done) { - request(app) - .get('<%= route %>') - .expect(200) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) return done(err); - res.body.should.be.instanceOf(Array); - done(); - }); - }); -}); diff --git a/test/fixtures/package.json b/test/fixtures/package.json index 9bdfd30ff..2304c008e 100644 --- a/test/fixtures/package.json +++ b/test/fixtures/package.json @@ -63,6 +63,7 @@ "grunt-karma": "~0.8.2", "grunt-build-control": "DaftMonk/grunt-build-control", "grunt-mocha-test": "~0.10.2", + "grunt-mocha-istanbul": "^2.0.0", "grunt-contrib-sass": "^0.7.3", "grunt-contrib-stylus": "latest", "jit-grunt": "^0.5.0", @@ -86,6 +87,7 @@ "karma-phantomjs-launcher": "~0.1.4", "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", + "proxyquire": "^1.0.1", "supertest": "~0.11.0", "sinon-chai": "^2.5.0" }, From 5198685150001a138230c888691d52fcec3e7a6c Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 30 Aug 2014 15:26:37 -0400 Subject: [PATCH 005/201] fix(server-tests): `test:coverage` task Changes: - add missing `option` argument from `test` task - define `istanbul_check_coverage` with `jit-grunt` - place server coverage reports in their own folder: `coverage/server` --- app/templates/Gruntfile.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 26866c21d..a72f42dae 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -17,7 +17,8 @@ module.exports = function (grunt) { cdnify: 'grunt-google-cdn', protractor: 'grunt-protractor-runner', injector: 'grunt-asset-injector', - buildcontrol: 'grunt-build-control' + buildcontrol: 'grunt-build-control', + istanbul_check_coverage: 'grunt-mocha-istanbul' }); // Time how long tasks take. Can help when optimizing build times @@ -508,7 +509,7 @@ module.exports = function (grunt) { reporter: 'spec', require: ['mocha.conf.js'], mask: '**/*.spec.js', - coverageFolder: 'coverage/unit' + coverageFolder: 'coverage/server/unit' }, src: 'server' }, @@ -522,7 +523,7 @@ module.exports = function (grunt) { reporter: 'spec', require: ['mocha.conf.js'], mask: '**/*.e2e.js', - coverageFolder: 'coverage/e2e' + coverageFolder: 'coverage/server/e2e' }, src: 'server' } @@ -531,7 +532,7 @@ module.exports = function (grunt) { istanbul_check_coverage: { default: { options: { - coverageFolder: 'coverage/*', + coverageFolder: 'coverage/**', check: { lines: 80, statements: 80, @@ -815,7 +816,7 @@ module.exports = function (grunt) { grunt.task.run(['serve']); }); - grunt.registerTask('test', function(target) { + grunt.registerTask('test', function(target, option) { if (target === 'server') { return grunt.task.run([ 'env:all', From c0b0c6f41672986c66a4c9e729b97f1ceae9121c Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 30 Aug 2014 14:49:38 -0400 Subject: [PATCH 006/201] docs(server-tests): update readme.md for new `test:coverage` task Changes: - add documentation for `grunt test:coverage` --- readme.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/readme.md b/readme.md index da6a851d1..a9997f528 100644 --- a/readme.md +++ b/readme.md @@ -338,6 +338,19 @@ To setup protractor e2e tests, you must first run Use `grunt test:e2e` to have protractor go through tests located in the `e2e` folder. +**Code Coverage** + +Use `grunt test:coverage` to run mocha-istanbul and generate code coverage reports. + +`coverage/server` will be populated with `e2e` and `unit` folders containing the `lcov` reports. + +The coverage taget has 3 available options: +- `test:coverage:unit` generate server unit test coverage +- `test:coverage:e2e` generate server e2e test coverage +- `test:coverage:check` combine the coverage reports and check against predefined thresholds + +* *when no option is given `test:coverage` runs all options in the above order* + ## Environment Variables Keeping your app secrets and other sensitive information in source control isn't a good idea. To have grunt launch your app with specific environment variables, add them to the git ignored environment config file: `server/config/local.env.js`. From 7045907c849427a16c3aacaf5fd70d14430be09d Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 31 Aug 2014 20:48:46 -0600 Subject: [PATCH 007/201] fix user model test --- app/templates/server/api/user(auth)/user.model.spec.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index 952fc5461..afe8af882 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -64,12 +64,5 @@ describe('User Model:', function() { }); }); - - it("should authenticate user if password is valid", function() { - return user.authenticate('password').should.be.true; - }); - - it("should not authenticate user if password is invalid", function() { - return user.authenticate('blah').should.not.be.true; }); }); From 1ca7448fc05c369180c667077918cc2156c308a9 Mon Sep 17 00:00:00 2001 From: Rafael Almeida Date: Mon, 25 Aug 2014 17:40:12 +1200 Subject: [PATCH 008/201] feat (mongoose): use mongoose-bird to promisify the mongoose API --- app/templates/_package.json | 6 +- app/templates/server/api/thing/index.spec.js | 12 +- .../server/api/thing/thing.controller.js | 114 ++++++++++++------ .../server/api/thing/thing.model(mongoose).js | 2 +- .../server/api/user(auth)/index.spec.js | 12 +- .../server/api/user(auth)/user.controller.js | 95 +++++++++------ .../server/api/user(auth)/user.model.js | 31 +++-- .../server/api/user(auth)/user.model.spec.js | 68 ++++------- app/templates/server/app.js | 4 +- .../server/auth(auth)/auth.service.js | 30 +++-- app/templates/server/config/express.js | 4 +- app/templates/server/config/seed(mongoose).js | 83 +++++++------ endpoint/templates/index.spec.js | 12 +- endpoint/templates/name.controller.js | 114 ++++++++++++------ endpoint/templates/name.model(mongoose).js | 4 +- 15 files changed, 342 insertions(+), 249 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 9dfdadc5d..2d8337b71 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -15,7 +15,9 @@ "lodash": "~2.4.1",<% if(filters.jade) { %> "jade": "~1.2.0",<% } %><% if(filters.html) { %> "ejs": "~0.8.4",<% } %><% if(filters.mongoose) { %> - "mongoose": "~3.8.8",<% } %><% if(filters.auth) { %> + "mongoose": "~3.8.8", + "mongoose-bird": "~0.0.1", + <% } %><% if(filters.auth) { %> "jsonwebtoken": "^0.3.0", "express-jwt": "^0.1.3", "passport": "~0.2.0", @@ -46,7 +48,7 @@ "grunt-contrib-watch": "~0.6.1",<% if(filters.coffee) { %> "grunt-contrib-coffee": "^0.10.1",<% } %><% if(filters.jade) { %> "grunt-contrib-jade": "^0.11.0",<% } %><% if(filters.less) { %> - "grunt-contrib-less": "^0.11.0",<% } %> + "grunt-contrib-less": "^0.11.4",<% } %> "grunt-google-cdn": "~0.4.0", "grunt-newer": "~0.7.0", "grunt-ng-annotate": "^0.2.3", diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js index 0fbfb1029..e62feff60 100644 --- a/app/templates/server/api/thing/index.spec.js +++ b/app/templates/server/api/thing/index.spec.js @@ -37,7 +37,7 @@ describe('Thing API Router:', function() { describe('GET /api/things', function() { it('should route to thing.controller.index', function() { - return router.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; + router.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; }); });<% if(filters.mongoose) { %> @@ -45,7 +45,7 @@ describe('Thing API Router:', function() { describe('GET /api/things/:id', function() { it('should route to thing.controller.show', function() { - return router.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; + router.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; }); }); @@ -53,7 +53,7 @@ describe('Thing API Router:', function() { describe('POST /api/things', function() { it('should route to thing.controller.create', function() { - return router.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; + router.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; }); }); @@ -61,7 +61,7 @@ describe('Thing API Router:', function() { describe('PUT /api/things/:id', function() { it('should route to thing.controller.update', function() { - return router.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + router.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; }); }); @@ -69,7 +69,7 @@ describe('Thing API Router:', function() { describe('PATCH /api/things/:id', function() { it('should route to thing.controller.update', function() { - return router.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + router.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; }); }); @@ -77,7 +77,7 @@ describe('Thing API Router:', function() { describe('DELETE /api/things/:id', function() { it('should route to thing.controller.destroy', function() { - return router.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; + router.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; }); });<% } %> diff --git a/app/templates/server/api/thing/thing.controller.js b/app/templates/server/api/thing/thing.controller.js index 72a678cf4..4d5abca05 100644 --- a/app/templates/server/api/thing/thing.controller.js +++ b/app/templates/server/api/thing/thing.controller.js @@ -7,10 +7,57 @@ * DELETE /things/:id -> destroy */ -'use strict'; +'use strict';<% if (filters.mongoose) { %> -var _ = require('lodash');<% if (filters.mongoose) { %> -var Thing = require('./thing.model');<% } %> +var _ = require('lodash'); +var Thing = require('./thing.model'); + +function handleError(res, statusCode){ + statusCode = statusCode || 500; + return function(err){ + res.send(statusCode, err); + }; +} + +function responseWithResult(res, statusCode){ + statusCode = statusCode || 200; + return function(entity){ + if(entity){ + return res.json(statusCode, entity); + } + }; +} + +function handleEntityNotFound(res){ + return function(entity){ + if(!entity){ + res.send(404); + return null; + } + return entity; + }; +} + +function saveUpdates(updates){ + return function(entity){ + var updated = _.merge(entity, updates); + return updated.saveAsync() + .then(function () { + return updated; + }); + }; +} + +function removeEntity(res){ + return function (entity) { + if(entity){ + return entity.removeAsync() + .then(function() { + return res.send(204); + }); + } + }; +}<% } %> // Get list of things exports.index = function(req, res) {<% if (!filters.mongoose) { %> @@ -34,56 +81,43 @@ exports.index = function(req, res) {<% if (!filters.mongoose) { %> name : 'Deployment Ready', info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift subgenerators' } - ]);<% } %><% if (filters.mongoose) { %> - Thing.find(function (err, things) { - if(err) { return handleError(res, err); } - return res.json(200, things); - });<% } %> + ]);<% } if (filters.mongoose) { %> + Thing.findAsync() + .then(responseWithResult(res)) + .catch(handleError(res));<% } %> };<% if (filters.mongoose) { %> // Get a single thing exports.show = function(req, res) { - Thing.findById(req.params.id, function (err, thing) { - if(err) { return handleError(res, err); } - if(!thing) { return res.send(404); } - return res.json(thing); - }); + Thing.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(responseWithResult(res)) + .catch(handleError(res)); }; // Creates a new thing in the DB. exports.create = function(req, res) { - Thing.create(req.body, function(err, thing) { - if(err) { return handleError(res, err); } - return res.json(201, thing); - }); + Thing.createAsync(req.body) + .then(responseWithResult(res, 201)) + .catch(handleError(res)); }; // Updates an existing thing in the DB. exports.update = function(req, res) { - if(req.body._id) { delete req.body._id; } - Thing.findById(req.params.id, function (err, thing) { - if (err) { return handleError(res, err); } - if(!thing) { return res.send(404); } - var updated = _.merge(thing, req.body); - updated.save(function (err) { - if (err) { return handleError(res, err); } - return res.json(200, thing); - }); - }); + if(req.body._id) { + delete req.body._id; + } + Thing.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(saveUpdates(req.body)) + .then(responseWithResult(res)) + .catch(handleError(res)); }; // Deletes a thing from the DB. exports.destroy = function(req, res) { - Thing.findById(req.params.id, function (err, thing) { - if(err) { return handleError(res, err); } - if(!thing) { return res.send(404); } - thing.remove(function(err) { - if(err) { return handleError(res, err); } - return res.send(204); - }); - }); -}; - -function handleError(res, err) { - return res.send(500, err); -}<% } %> + Thing.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(removeEntity(res)) + .catch(handleError(res)); +};<% } %> diff --git a/app/templates/server/api/thing/thing.model(mongoose).js b/app/templates/server/api/thing/thing.model(mongoose).js index 92a791e70..a44bc710e 100644 --- a/app/templates/server/api/thing/thing.model(mongoose).js +++ b/app/templates/server/api/thing/thing.model(mongoose).js @@ -1,6 +1,6 @@ 'use strict'; -var mongoose = require('mongoose'), +var mongoose = require('mongoose-bird')(), Schema = mongoose.Schema; var ThingSchema = new Schema({ diff --git a/app/templates/server/api/user(auth)/index.spec.js b/app/templates/server/api/user(auth)/index.spec.js index 5bcd4c2c0..30b786fb3 100644 --- a/app/templates/server/api/user(auth)/index.spec.js +++ b/app/templates/server/api/user(auth)/index.spec.js @@ -47,7 +47,7 @@ describe('User API Router:', function() { describe('GET /api/users', function() { it('should verify admin role and route to user.controller.index', function() { - return router.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; + router.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; }); }); @@ -55,7 +55,7 @@ describe('User API Router:', function() { describe('DELETE /api/users/:id', function() { it('should verify admin role and route to user.controller.destroy', function() { - return router.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; + router.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; }); }); @@ -63,7 +63,7 @@ describe('User API Router:', function() { describe('GET /api/users/me', function() { it('should be authenticated and route to user.controller.me', function() { - return router.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; + router.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; }); }); @@ -71,7 +71,7 @@ describe('User API Router:', function() { describe('PUT /api/users/:id/password', function() { it('should be authenticated and route to user.controller.changePassword', function() { - return router.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; + router.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; }); }); @@ -79,7 +79,7 @@ describe('User API Router:', function() { describe('GET /api/users/:id', function() { it('should be authenticated and route to user.controller.show', function() { - return router.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; + router.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; }); }); @@ -87,7 +87,7 @@ describe('User API Router:', function() { describe('POST /api/users', function() { it('should route to user.controller.create', function() { - return router.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; + router.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; }); }); diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index 17e6e0e04..28e30199a 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -5,19 +5,37 @@ var passport = require('passport'); var config = require('../../config/environment'); var jwt = require('jsonwebtoken'); -var validationError = function(res, err) { - return res.json(422, err); +var validationError = function(res, statusCode) { + statusCode = statusCode || 422; + return function(err){ + res.json(statusCode, err); + }; }; +function handleError(res, statusCode){ + statusCode = statusCode || 500; + return function(err){ + res.send(statusCode, err); + }; +} + +function respondWith(res, statusCode){ + statusCode = statusCode || 200; + return function(){ + res.send(statusCode); + }; +} + /** * Get list of users * restriction: 'admin' */ exports.index = function(req, res) { - User.find({}, '-salt -password', function (err, users) { - if(err) return res.send(500, err); - res.json(200, users); - }); + User.findAsync({}, '-salt -hashedPassword') + .then(function (users) { + res.json(200, users); + }) + .catch(handleError(res)); }; /** @@ -27,11 +45,12 @@ exports.create = function (req, res, next) { var newUser = new User(req.body); newUser.provider = 'local'; newUser.role = 'user'; - newUser.save(function(err, user) { - if (err) return validationError(res, err); - var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresInMinutes: 60*5 }); - res.json({ token: token }); - }); + newUser.saveAsync() + .then(function(user) { + var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresInMinutes: 60*5 }); + res.json({ token: token }); + }) + .catch(validationError(res)); }; /** @@ -40,11 +59,16 @@ exports.create = function (req, res, next) { exports.show = function (req, res, next) { var userId = req.params.id; - User.findById(userId, function (err, user) { - if (err) return next(err); - if (!user) return res.send(401); - res.json(user.profile); - }); + User.findByIdAsync(userId) + .then(function (user) { + if(!user) { + return res.send(401); + } + res.json(user.profile); + }) + .catch(function(err){ + return next(err); + }); }; /** @@ -52,10 +76,9 @@ exports.show = function (req, res, next) { * restriction: 'admin' */ exports.destroy = function(req, res) { - User.findByIdAndRemove(req.params.id, function(err, user) { - if(err) return res.send(500, err); - return res.send(204); - }); + User.findByIdAndRemoveAsync(req.params.id) + .then(respondWith(res, 204)) + .catch(handleError(res)); }; /** @@ -66,21 +89,17 @@ exports.changePassword = function(req, res, next) { var oldPass = String(req.body.oldPassword); var newPass = String(req.body.newPassword); - User.findById(userId, function (err, user) { - user.authenticate(oldPass, function(authErr, authenticated) { - if (authErr) res.send(403); - - if (authenticated) { + User.findByIdAsync(userId) + .then(function(user) { + if(user.authenticate(oldPass)) { user.password = newPass; - user.save(function(err) { - if (err) return validationError(res, err); - res.send(200); - }); + return user.saveAsync() + .then(respondWith(res, 200)) + .catch(validationError(res)); } else { - res.send(403); + return res.send(403); } }); - }); }; /** @@ -88,13 +107,13 @@ exports.changePassword = function(req, res, next) { */ exports.me = function(req, res, next) { var userId = req.user._id; - User.findOne({ - _id: userId - }, '-salt -password', function(err, user) { // don't ever give out the password or salt - if (err) return next(err); - if (!user) return res.json(401); - res.json(user); - }); + + User.findOneAsync({ _id: userId }, '-salt -hashedPassword') + .then(function(user) { // don't ever give out the password or salt + if (!user) { return res.json(401); } + res.json(user); + }) + .catch(function(err){ return next(err); }); }; /** diff --git a/app/templates/server/api/user(auth)/user.model.js b/app/templates/server/api/user(auth)/user.model.js index b3497f859..b90386886 100644 --- a/app/templates/server/api/user(auth)/user.model.js +++ b/app/templates/server/api/user(auth)/user.model.js @@ -1,6 +1,6 @@ 'use strict'; -var mongoose = require('mongoose'); +var mongoose = require('mongoose-bird')(); var Schema = mongoose.Schema; var crypto = require('crypto');<% if(filters.oauth) { %> var authTypes = ['github', 'twitter', 'facebook', 'google'];<% } %> @@ -53,7 +53,9 @@ UserSchema UserSchema .path('email') .validate(function(email) {<% if (filters.oauth) { %> - if (authTypes.indexOf(this.provider) !== -1) return true;<% } %> + if (authTypes.indexOf(this.provider) !== -1){ + return true; + } <% } %> return email.length; }, 'Email cannot be blank'); @@ -61,7 +63,9 @@ UserSchema UserSchema .path('password') .validate(function(password) {<% if (filters.oauth) { %> - if (authTypes.indexOf(this.provider) !== -1) return true;<% } %> + if (authTypes.indexOf(this.provider) !== -1){ + return true; + } <% } %> return password.length; }, 'Password cannot be blank'); @@ -70,14 +74,19 @@ UserSchema .path('email') .validate(function(value, respond) { var self = this; - this.constructor.findOne({email: value}, function(err, user) { - if(err) throw err; - if(user) { - if(self.id === user.id) return respond(true); - return respond(false); - } - respond(true); - }); + return this.constructor.findOneAsync({email: value}) + .then(function(user) { + if(user) { + if(self.id === user.id) { + return respond(true); + } + return respond(false); + } + return respond(true); + }) + .catch(function(err){ + throw err; + }); }, 'The specified email address is already in use.'); var validatePresenceOf = function(value) { diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index afe8af882..fe51ea2ea 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -10,59 +10,39 @@ var user = new User({ password: 'password' }); -describe('User Model:', function() { - - // Clear users before testing +describe('User Model', function() { before(function() { + // Clear users before testing return User.remove().exec(); }); - describe('User (schema)', function() { - - it('should begin with no users', function() { - return User.find({}).exec().should.eventually.have.length(0); - }); - + afterEach(function() { + return User.remove().exec(); }); - describe('user (instance)', function() { - - describe('.save()', function() { - // Clear users after tests - afterEach(function() { - return User.remove().exec(); - }); - - it('should fail when saving a duplicate user', function(done) { - user.save(function() { - var userDup = new User(user); - userDup.save(function(err) { - err.should.be.instanceOf(Error); - done(); - }); - }); - }); - - it('should fail when saving without an email', function(done) { - user.email = ''; - user.save(function(err) { - err.should.be.instanceOf(Error); - done(); - }); - }); - - }); + it('should begin with no users', function() { + return User.findAsync({}) + .should.eventually.have.length(0); + }); - describe('.authenticate()', function() { + it('should fail when saving a duplicate user', function() { + return user.saveAsync() + .then(function() { + var userDup = new User(user); + return userDup.saveAsync(); + }).should.be.rejected; + }); - it("should authenticate user if password is valid", function() { - return user.authenticate('password').should.be.true; - }); + it('should fail when saving without an email', function() { + user.email = ''; + return user.saveAsync().should.be.rejected; + }); - it("should not authenticate user if password is invalid", function() { - return user.authenticate('blah').should.not.be.true; - }); + it("should authenticate user if password is valid", function() { + user.authenticate('password').should.be.true; + }); - }); + it("should not authenticate user if password is invalid", function() { + user.authenticate('blah').should.not.be.true; }); }); diff --git a/app/templates/server/app.js b/app/templates/server/app.js index 08b942f43..5369e94ef 100644 --- a/app/templates/server/app.js +++ b/app/templates/server/app.js @@ -8,7 +8,7 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development'; var express = require('express');<% if (filters.mongoose) { %> -var mongoose = require('mongoose');<% } %> +var mongoose = require('mongoose-bird')();<% } %> var config = require('./config/environment'); <% if (filters.mongoose) { %> // Connect to database @@ -34,4 +34,4 @@ server.listen(config.port, config.ip, function () { }); // Expose app -exports = module.exports = app; \ No newline at end of file +exports = module.exports = app; diff --git a/app/templates/server/auth(auth)/auth.service.js b/app/templates/server/auth(auth)/auth.service.js index 38ec34302..101dcc5c5 100644 --- a/app/templates/server/auth(auth)/auth.service.js +++ b/app/templates/server/auth(auth)/auth.service.js @@ -1,6 +1,6 @@ 'use strict'; -var mongoose = require('mongoose'); +var mongoose = require('mongoose-bird')(); var passport = require('passport'); var config = require('../config/environment'); var jwt = require('jsonwebtoken'); @@ -25,13 +25,17 @@ function isAuthenticated() { }) // Attach user to request .use(function(req, res, next) { - User.findById(req.user._id, function (err, user) { - if (err) return next(err); - if (!user) return res.send(401); - - req.user = user; - next(); - }); + User.findByIdAsync(req.user._id) + .then(function (user) { + if (!user) { + return res.send(401); + } + req.user = user; + next(); + }) + .catch(function(err){ + return next(err); + }); }); } @@ -39,7 +43,9 @@ function isAuthenticated() { * Checks if the user role meets the minimum requirements of the route */ function hasRole(roleRequired) { - if (!roleRequired) throw new Error('Required role needs to be set'); + if (!roleRequired) { + throw new Error('Required role needs to be set'); + } return compose() .use(isAuthenticated()) @@ -64,7 +70,9 @@ function signToken(id) { * Set token cookie directly for oAuth strategies */ function setTokenCookie(req, res) { - if (!req.user) return res.json(404, { message: 'Something went wrong, please try again.'}); + if (!req.user) { + return res.json(404, { message: 'Something went wrong, please try again.'}); + } var token = signToken(req.user._id, req.user.role); res.cookie('token', JSON.stringify(token)); res.redirect('/'); @@ -73,4 +81,4 @@ function setTokenCookie(req, res) { exports.isAuthenticated = isAuthenticated; exports.hasRole = hasRole; exports.signToken = signToken; -exports.setTokenCookie = setTokenCookie; \ No newline at end of file +exports.setTokenCookie = setTokenCookie; diff --git a/app/templates/server/config/express.js b/app/templates/server/config/express.js index 2243a7779..2403780f1 100644 --- a/app/templates/server/config/express.js +++ b/app/templates/server/config/express.js @@ -17,7 +17,7 @@ var config = require('./environment');<% if (filters.auth) { %> var passport = require('passport');<% } %><% if (filters.twitterAuth) { %> var session = require('express-session'); var mongoStore = require('connect-mongo')(session); -var mongoose = require('mongoose');<% } %> +var mongoose = require('mongoose-bird')();<% } %> module.exports = function(app) { var env = app.get('env'); @@ -57,4 +57,4 @@ module.exports = function(app) { app.use(morgan('dev')); app.use(errorHandler()); // Error handler - has to be last } -}; \ No newline at end of file +}; diff --git a/app/templates/server/config/seed(mongoose).js b/app/templates/server/config/seed(mongoose).js index 27ab19417..6d56010b6 100644 --- a/app/templates/server/config/seed(mongoose).js +++ b/app/templates/server/config/seed(mongoose).js @@ -6,44 +6,51 @@ 'use strict'; var Thing = require('../api/thing/thing.model'); -<% if (filters.auth) { %>var User = require('../api/user/user.model');<% } %> +<% if (filters.auth) { %> +var User = require('../api/user/user.model'); +<% } %> -Thing.find({}).remove(function() { - Thing.create({ - name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' - }, { - name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' - }, { - name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. Automatic injection of scripts and styles into your index.html' - }, { - name : 'Modular Structure', - info : 'Best practice client and server structures allow for more code reusability and maximum scalability' - }, { - name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript payload, minifies your scripts/css/images, and rewrites asset names for caching.' - },{ - name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift subgenerators' +Thing.find({}).removeAsync() + .then(function() { + Thing.create({ + name : 'Development Tools', + info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' + }, { + name : 'Server and Client integration', + info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' + }, { + name : 'Smart Build System', + info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. Automatic injection of scripts and styles into your index.html' + }, { + name : 'Modular Structure', + info : 'Best practice client and server structures allow for more code reusability and maximum scalability' + }, { + name : 'Optimized Build', + info : 'Build process packs up your templates as a single JavaScript payload, minifies your scripts/css/images, and rewrites asset names for caching.' + },{ + name : 'Deployment Ready', + info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift subgenerators' + }); }); -});<% if (filters.auth) { %> -User.find({}).remove(function() { - User.create({ - provider: 'local', - name: 'Test User', - email: 'test@test.com', - password: 'test' - }, { - provider: 'local', - role: 'admin', - name: 'Admin', - email: 'admin@admin.com', - password: 'admin' - }, function() { - console.log('finished populating users'); - } - ); -});<% } %> \ No newline at end of file +<% if (filters.auth) { %> + +User.find({}).removeAsync() + .then(function() { + User.create({ + provider: 'local', + name: 'Test User', + email: 'test@test.com', + password: 'test' + }, { + provider: 'local', + role: 'admin', + name: 'Admin', + email: 'admin@admin.com', + password: 'admin' + }, function() { + console.log('finished populating users'); + } + ); + }); +<% } %> diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 62caed5dc..b5bfb3a41 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -37,7 +37,7 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>', function() { it('should route to <%= name %>.controller.index', function() { - return router.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; + router.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; }); });<% if(filters.mongoose) { %> @@ -45,7 +45,7 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>/:id', function() { it('should route to <%= name %>.controller.show', function() { - return router.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; + router.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; }); }); @@ -53,7 +53,7 @@ describe('<%= classedName %> API Router:', function() { describe('POST <%= route %>', function() { it('should route to <%= name %>.controller.create', function() { - return router.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; + router.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; }); }); @@ -61,7 +61,7 @@ describe('<%= classedName %> API Router:', function() { describe('PUT <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - return router.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + router.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; }); }); @@ -69,7 +69,7 @@ describe('<%= classedName %> API Router:', function() { describe('PATCH <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - return router.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + router.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; }); }); @@ -77,7 +77,7 @@ describe('<%= classedName %> API Router:', function() { describe('DELETE <%= route %>/:id', function() { it('should route to <%= name %>.controller.destroy', function() { - return router.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; + router.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; }); });<% } %> diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 1d9da544e..5851a1338 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -1,60 +1,94 @@ -'use strict'; +'use strict';<% if (filters.mongoose) { %> -var _ = require('lodash');<% if (filters.mongoose) { %> -var <%= classedName %> = require('./<%= name %>.model');<% } %> +var _ = require('lodash'); +var <%= classedName %> = require('./<%= name %>.model'); + +function handleError(res, statusCode){ + statusCode = statusCode || 500; + return function(err){ + res.send(statusCode, err); + }; +} + +function responseWithResult(res, statusCode){ + statusCode = statusCode || 200; + return function(entity){ + if(entity){ + return res.json(statusCode, entity); + } + }; +} + +function handleEntityNotFound(res){ + return function(entity){ + if(!entity){ + res.send(404); + return null; + } + return entity; + }; +} + +function saveUpdates(updates){ + return function(entity){ + var updated = _.merge(entity, updates); + return updated.saveAsync() + .then(function () { + return updated; + }); + }; +} + +function removeEntity(res){ + return function (entity) { + if(entity){ + return entity.removeAsync() + .then(function() { + return res.send(204); + }); + } + }; +}<% } %> // Get list of <%= name %>s exports.index = function(req, res) {<% if (!filters.mongoose) { %> - res.json([]);<% } %><% if (filters.mongoose) { %> - <%= classedName %>.find(function (err, <%= name %>s) { - if(err) { return handleError(res, err); } - return res.json(200, <%= name %>s); - });<% } %> + res.json([]);<% } if (filters.mongoose) { %> + <%= classedName %>.findAsync() + .then(responseWithResult(res)) + .catch(handleError(res));<% } %> };<% if (filters.mongoose) { %> // Get a single <%= name %> exports.show = function(req, res) { - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { - if(err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - return res.json(<%= name %>); - }); + <%= classedName %>.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(responseWithResult(res)) + .catch(handleError(res)); }; // Creates a new <%= name %> in the DB. exports.create = function(req, res) { - <%= classedName %>.create(req.body, function(err, <%= name %>) { - if(err) { return handleError(res, err); } - return res.json(201, <%= name %>); - }); + <%= classedName %>.createAsync(req.body) + .then(responseWithResult(res, 201)) + .catch(handleError(res)); }; // Updates an existing <%= name %> in the DB. exports.update = function(req, res) { - if(req.body._id) { delete req.body._id; } - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { - if (err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - var updated = _.merge(<%= name %>, req.body); - updated.save(function (err) { - if (err) { return handleError(res, err); } - return res.json(200, <%= name %>); - }); - }); + if(req.body._id) { + delete req.body._id; + } + <%= classedName %>.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(saveUpdates(req.body)) + .then(responseWithResult(res)) + .catch(handleError(res)); }; // Deletes a <%= name %> from the DB. exports.destroy = function(req, res) { - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { - if(err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - <%= name %>.remove(function(err) { - if(err) { return handleError(res, err); } - return res.send(204); - }); - }); -}; - -function handleError(res, err) { - return res.send(500, err); -}<% } %> \ No newline at end of file + <%= classedName %>.findByIdAsync(req.params.id) + .then(handleEntityNotFound(res)) + .then(removeEntity(res)) + .catch(handleError(res)); +};<% } %> diff --git a/endpoint/templates/name.model(mongoose).js b/endpoint/templates/name.model(mongoose).js index 89e0dfaa7..9b23d9d41 100644 --- a/endpoint/templates/name.model(mongoose).js +++ b/endpoint/templates/name.model(mongoose).js @@ -1,6 +1,6 @@ 'use strict'; -var mongoose = require('mongoose'), +var mongoose = require('mongoose-bird')(), Schema = mongoose.Schema; var <%= classedName %>Schema = new Schema({ @@ -9,4 +9,4 @@ var <%= classedName %>Schema = new Schema({ active: Boolean }); -module.exports = mongoose.model('<%= classedName %>', <%= classedName %>Schema); \ No newline at end of file +module.exports = mongoose.model('<%= classedName %>', <%= classedName %>Schema); From 49d5bbdf5c8a59812e8f72ad5b95309894bea5ca Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 6 Sep 2014 22:11:53 -0400 Subject: [PATCH 009/201] fix(gen): filter `client/components/socket` js files Changes: - add `(js)` filter to the js files in `client/components/socket` Closes #530 --- .../socket(socketio)/{socket.mock.js => socket.mock(js).js} | 0 .../socket(socketio)/{socket.service.js => socket.service(js).js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename app/templates/client/components/socket(socketio)/{socket.mock.js => socket.mock(js).js} (100%) rename app/templates/client/components/socket(socketio)/{socket.service.js => socket.service(js).js} (100%) diff --git a/app/templates/client/components/socket(socketio)/socket.mock.js b/app/templates/client/components/socket(socketio)/socket.mock(js).js similarity index 100% rename from app/templates/client/components/socket(socketio)/socket.mock.js rename to app/templates/client/components/socket(socketio)/socket.mock(js).js diff --git a/app/templates/client/components/socket(socketio)/socket.service.js b/app/templates/client/components/socket(socketio)/socket.service(js).js similarity index 100% rename from app/templates/client/components/socket(socketio)/socket.service.js rename to app/templates/client/components/socket(socketio)/socket.service(js).js From c2ab8ae922ec0f2e377e560e937d09091e596b07 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 6 Sep 2014 21:53:07 -0400 Subject: [PATCH 010/201] test(gen): make tests more strict and DRY Changes: - `genFiles(ops)` creates an array of expected files based on options given - test for generated files on every set of tests - test for unexpected files - use testExec to be more DRY Exposes a bug with `client/components/socket`: `socket.service.js` and `socket.mock.js` are not filtered. See #530 --- package.json | 1 + test/test-file-creation.js | 416 +++++++++++++++++++++++++------------ 2 files changed, 287 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index cab669526..394f5e6d1 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "marked": "~0.2.8", "mocha": "~1.21.0", "q": "^1.0.1", + "recursive-readdir": "^1.2.0", "semver": "~2.2.1", "shelljs": "^0.3.0", "underscore.string": "^2.3.3" diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 2dc0ee548..2ea172b2e 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -1,11 +1,12 @@ /*global describe, beforeEach, it */ 'use strict'; var path = require('path'); +var fs = require('fs-extra'); +var exec = require('child_process').exec; var helpers = require('yeoman-generator').test; var chai = require('chai'); var expect = chai.expect; -var fs = require('fs-extra'); -var exec = require('child_process').exec; +var recursiveReadDir = require('recursive-readdir'); describe('angular-fullstack generator', function () { var gen, defaultOptions = { @@ -32,6 +33,201 @@ describe('angular-fullstack generator', function () { }); } + function assertOnlyFiles(expectedFiles, done, path, skip) { + path = path || './'; + skip = skip || ['e2e', 'node_modules', 'client/bower_components']; + + recursiveReadDir(path, skip, function(err, files) { + if (err) { return done(err); } + + for (var i = 0, expectedFilesLength = expectedFiles.length; i < expectedFilesLength; i++) { + var index = files.indexOf(expectedFiles[i]); + files.splice(index, 1); + } + + if (files.length !== 0) { + err = new Error('unexpected files found'); + err.expected = ''; + err.actual = files.join('\n'); + return done(err); + } + + done(); + }); + } + + function runTest(type, self, cb, timeout) { + self.timeout(timeout || 60000); + gen.run({}, function() { + exec(type, function(error, stdout, stderr) { + switch(type) { + case 'grunt test:client': + expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); + break; + case 'grunt jshint': + expect(stdout).to.contain('Done, without errors.'); + break; + case 'grunt test:server': + expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); + break; + default: + expect(stderr).to.be.empty; + } + + cb(); + }); + }); + } + + function genFiles(ops) { + var mapping = { + stylesheet: { + sass: 'scss', + stylus: 'styl', + less: 'less', + css: 'css' + }, + markup: { + jade: 'jade', + html: 'html' + }, + script: { + js: 'js', + coffee: 'coffee' + } + }, + files = []; + + var oauthFiles = function(type) { + return [ + 'server/auth/' + type + '/index.js', + 'server/auth/' + type + '/passport.js', + ]; + }; + + + var script = mapping.script[ops.script], + markup = mapping.markup[ops.markup], + stylesheet = mapping.stylesheet[ops.stylesheet]; + + files = files.concat([ + 'client/.htaccess', + 'client/.jshintrc', + 'client/favicon.ico', + 'client/robots.txt', + 'client/index.html', + 'client/app/app.' + script, + 'client/app/app.' + stylesheet, + 'client/app/main/main.' + script, + 'client/app/main/main.' + markup, + 'client/app/main/main.' + stylesheet, + 'client/app/main/main.controller.' + script, + 'client/app/main/main.controller.spec.' + script, + 'client/assets/images/yeoman.png', + 'client/components/navbar/navbar.' + markup, + 'client/components/navbar/navbar.controller.' + script, + 'server/.jshintrc', + 'server/.jshintrc-spec', + 'server/app.js', + 'server/routes.js', + 'server/api/thing/index.js', + 'server/api/thing/index.spec.js', + 'server/api/thing/thing.controller.js', + 'server/api/thing/thing.e2e.js', + 'server/components/errors/index.js', + 'server/config/local.env.js', + 'server/config/local.env.sample.js', + 'server/config/express.js', + 'server/config/environment/index.js', + 'server/config/environment/development.js', + 'server/config/environment/production.js', + 'server/config/environment/test.js', + 'server/views/404.' + markup, + '.bowerrc', + '.buildignore', + '.editorconfig', + '.gitattributes', + '.gitignore', + '.travis.yml', + '.yo-rc.json', + 'Gruntfile.js', + 'package.json', + 'bower.json', + 'karma.conf.js', + 'mocha.conf.js', + 'protractor.conf.js' + ]); + + if (ops.uibootstrap) { + files = files.concat([ + 'client/components/modal/modal.' + markup, + 'client/components/modal/modal.' + stylesheet, + 'client/components/modal/modal.service.' + script, + ]); + } + + if (ops.mongoose) { + files = files.concat([ + 'server/api/thing/thing.model.js', + 'server/config/seed.js' + ]); + } + + if (ops.auth) { + files = files.concat([ + 'client/app/account/account.' + script, + 'client/app/account/login/login.' + markup, + 'client/app/account/login/login.' + stylesheet, + 'client/app/account/login/login.controller.' + script, + 'client/app/account/settings/settings.' + markup, + 'client/app/account/settings/settings.controller.' + script, + 'client/app/account/signup/signup.' + markup, + 'client/app/account/signup/signup.controller.' + script, + 'client/app/admin/admin.' + markup, + 'client/app/admin/admin.' + stylesheet, + 'client/app/admin/admin.' + script, + 'client/app/admin/admin.controller.' + script, + 'client/components/auth/auth.service.' + script, + 'client/components/auth/user.service.' + script, + 'client/components/mongoose-error/mongoose-error.directive.' + script, + 'server/api/user/index.js', + 'server/api/user/index.spec.js', + 'server/api/user/user.controller.js', + 'server/api/user/user.e2e.js', + 'server/api/user/user.model.js', + 'server/api/user/user.model.spec.js', + 'server/auth/index.js', + 'server/auth/auth.service.js', + 'server/auth/local/index.js', + 'server/auth/local/passport.js' + ]); + } + + if (ops.oauth) { + var oauth = ops.oauth; + for (var i = 0, oauthLength = oauth.length; i < oauthLength; i++) { + files = files.concat(oauthFiles(oauth[i].replace('Auth', ''))); + } + } + + if (ops.socketio) { + files = files.concat([ + 'client/components/socket/socket.service.' + script, + 'client/components/socket/socket.mock.' + script, + 'server/api/thing/thing.socket.js', + 'server/config/socketio.js' + ]); + } + + return files; + } + + function everyFile(files, ops) { + ops = ops || { + skip: ['node_modules', 'client/bower_components', 'e2e'] + } + } + beforeEach(function (done) { this.timeout(10000); var deps = [ @@ -68,33 +264,15 @@ describe('angular-fullstack generator', function () { }); it('should run client tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:client', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); - done(); - }); - }); + runTest('grunt test:client', this, done); }); it('should pass jshint', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt jshint', function (error, stdout, stderr) { - expect(stdout).to.contain('Done, without errors.'); - done(); - }); - }); + runTest('grunt jshint', this, done); }); it('should run server tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); - }); + runTest('grunt test:server', this, done); }); it('should run server tests successfully with generated endpoint', function(done) { @@ -130,6 +308,19 @@ describe('angular-fullstack generator', function () { }); }); + it('should generate expected files', function (done) { + gen.run({}, function () { + helpers.assertFile(genFiles(defaultOptions)); + done(); + }); + }); + + it('should not generate unexpected files', function (done) { + gen.run({}, function () { + assertOnlyFiles(genFiles(defaultOptions), done); + }); + }); + // it('should run e2e tests successfully', function(done) { // this.timeout(80000); // gen.run({}, function () { @@ -144,166 +335,131 @@ describe('angular-fullstack generator', function () { }); describe('with other preprocessors and oauth', function() { + var testOptions = { + script: 'coffee', + markup: 'jade', + stylesheet: 'less', + router: 'uirouter', + mongoose: true, + auth: true, + oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], + socketio: true + }; + beforeEach(function() { - helpers.mockPrompt(gen, { - script: 'coffee', - markup: 'jade', - stylesheet: 'less', - router: 'uirouter', - mongoose: true, - auth: true, - oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], - socketio: true - }); + helpers.mockPrompt(gen, testOptions); }); it('should run client tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:client', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); - done(); - }); - }); + runTest('grunt test:client', this, done); }); it('should pass jshint', function(done) { - this.timeout(60000); + runTest('grunt jshint', this, done); + }); + + it('should run server tests successfully', function(done) { + runTest('grunt test:server', this, done); + }); + + it('should generate expected files', function (done) { gen.run({}, function () { - exec('grunt jshint', function (error, stdout, stderr) { - expect(stdout).to.contain('Done, without errors.'); - done(); - }); + helpers.assertFile(genFiles(testOptions)); + done(); }); }); - it('should run server tests successfully', function(done) { - this.timeout(60000); + it('should not generate unexpected files', function (done) { gen.run({}, function () { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); + assertOnlyFiles(genFiles(testOptions), done); }); }); }); describe('with other preprocessors and no server options', function() { + var testOptions = { + script: 'coffee', + markup: 'jade', + stylesheet: 'stylus', + router: 'ngroute', + mongoose: false, + auth: false, + oauth: [], + socketio: false + }; + beforeEach(function(done) { - helpers.mockPrompt(gen, { - script: 'coffee', - markup: 'jade', - stylesheet: 'stylus', - router: 'ngroute', - mongoose: false, - auth: false, - oauth: [], - socketio: false - }); + helpers.mockPrompt(gen, testOptions); done(); }); it('should run client tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:client', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); - done(); - }); - }); + runTest('grunt test:client', this, done); }); it('should pass jshint', function(done) { - this.timeout(60000); + runTest('grunt jshint', this, done); + }); + + it('should run server tests successfully', function(done) { + runTest('grunt test:server', this, done); + }); + + it('should generate expected files', function (done) { gen.run({}, function () { - exec('grunt jshint', function (error, stdout, stderr) { - expect(stdout).to.contain('Done, without errors.'); - done(); - }); + helpers.assertFile(genFiles(testOptions)); + done(); }); }); - it('should run server tests successfully', function(done) { - this.timeout(60000); + it('should not generate unexpected files', function (done) { gen.run({}, function () { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); + assertOnlyFiles(genFiles(testOptions), done); }); }); }); describe('with no preprocessors and no server options', function() { + var testOptions = { + script: 'js', + markup: 'html', + stylesheet: 'css', + router: 'ngroute', + mongoose: false, + auth: false, + oauth: [], + socketio: false + }; + beforeEach(function(done) { - helpers.mockPrompt(gen, { - script: 'js', - markup: 'html', - stylesheet: 'css', - router: 'ngroute', - mongoose: false, - auth: false, - oauth: [], - socketio: false - }); + helpers.mockPrompt(gen, testOptions); done(); }); it('should run client tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:client', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); - done(); - }); - }); + runTest('grunt test:client', this, done); }); it('should pass jshint', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt jshint', function (error, stdout, stderr) { - expect(stdout).to.contain('Done, without errors.'); - done(); - }); - }); + runTest('grunt jshint', this, done); }); it('should run server tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); - }); + runTest('grunt test:server', this, done); }); it('should generate expected files', function (done) { - helpers.mockPrompt(gen, defaultOptions); - gen.run({}, function () { - helpers.assertFile([ - 'client/.htaccess', - 'client/favicon.ico', - 'client/robots.txt', - 'client/app/main/main.scss', - 'client/app/main/main.html', - 'client/index.html', - 'client/.jshintrc', - 'client/assets/images/yeoman.png', - '.bowerrc', - '.editorconfig', - '.gitignore', - 'Gruntfile.js', - 'package.json', - 'bower.json', - 'server/app.js', - 'server/config/express.js', - 'server/api/thing/index.js']); + helpers.assertFile(genFiles(testOptions)); done(); }); }); + + it('should not generate unexpected files', function (done) { + gen.run({}, function () { + assertOnlyFiles(genFiles(testOptions), done); + }); + }); }); }); }); From 3536b4577821734dff86cf6d8c47e501abb28da4 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Tue, 9 Sep 2014 22:33:21 -0600 Subject: [PATCH 011/201] fix unexpected files created in tests --- test/test-file-creation.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index c8d26917b..f5a753375 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -345,7 +345,9 @@ describe('angular-fullstack generator', function () { mongoose: true, auth: true, oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], - socketio: true + socketio: true, + bootstrap: true, + uibootstrap: true }; beforeEach(function() { @@ -387,7 +389,9 @@ describe('angular-fullstack generator', function () { mongoose: false, auth: false, oauth: [], - socketio: false + socketio: false, + bootstrap: false, + uibootstrap: false }; beforeEach(function(done) { @@ -430,7 +434,9 @@ describe('angular-fullstack generator', function () { mongoose: false, auth: false, oauth: [], - socketio: false + socketio: false, + bootstrap: true, + uibootstrap: true }; beforeEach(function(done) { From cf6ae006f5dfd318f8234910365fa13c69336509 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 10 Sep 2014 08:52:09 -0400 Subject: [PATCH 012/201] test(gen): clean up code and test more endpoint combinations Changes: - remove unneeded code - use runTest for endpoints as well - test endpoints with different options - test endpoints with various cased named Exposes Bug: See #540 --- test/test-file-creation.js | 94 ++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 30 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index f5a753375..b6171fabd 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -39,13 +39,16 @@ describe('angular-fullstack generator', function () { path = path || './'; skip = skip || ['e2e', 'node_modules', 'client/bower_components']; - recursiveReadDir(path, skip, function(err, files) { + recursiveReadDir(path, skip, function(err, actualFiles) { if (err) { return done(err); } + var files = actualFiles.concat(); - for (var i = 0, expectedFilesLength = expectedFiles.length; i < expectedFilesLength; i++) { - var index = files.indexOf(expectedFiles[i]); - files.splice(index, 1); - } + expectedFiles.forEach(function(file, i) { + var index = files.indexOf(file); + if (index >= 0) { + files.splice(index, 1); + } + }); if (files.length !== 0) { err = new Error('unexpected files found'); @@ -58,11 +61,16 @@ describe('angular-fullstack generator', function () { }); } - function runTest(type, self, cb, timeout) { + function runTest(cmd, self, cb) { + var args = Array.prototype.slice.call(arguments), + endpoint = (args[3] && typeof args[3] === 'string') ? args.splice(3, 1)[0] : null, + timeout = (args[3] && typeof args[3] === 'number') ? args.splice(3, 1)[0] : null; + self.timeout(timeout || 60000); - gen.run({}, function() { - exec(type, function(error, stdout, stderr) { - switch(type) { + + var execFn = function() { + exec(cmd, function(error, stdout, stderr) { + switch(cmd) { case 'grunt test:client': expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); break; @@ -78,7 +86,13 @@ describe('angular-fullstack generator', function () { cb(); }); - }); + }; + + if (endpoint) { + generatorTest('endpoint', endpoint, {}, execFn); + } else { + gen.run({}, execFn); + } } function genFiles(ops) { @@ -206,10 +220,9 @@ describe('angular-fullstack generator', function () { } if (ops.oauth) { - var oauth = ops.oauth; - for (var i = 0, oauthLength = oauth.length; i < oauthLength; i++) { - files = files.concat(oauthFiles(oauth[i].replace('Auth', ''))); - } + ops.oauth.forEach(function(type, i) { + files = files.concat(oauthFiles(type.replace('Auth', ''))); + }); } if (ops.socketio) { @@ -224,11 +237,10 @@ describe('angular-fullstack generator', function () { return files; } - function everyFile(files, ops) { - ops = ops || { - skip: ['node_modules', 'client/bower_components', 'e2e'] - } - } + + /** + * Generator tests + */ beforeEach(function (done) { this.timeout(10000); @@ -269,7 +281,7 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); - it('should pass jshint', function(done) { + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -277,14 +289,20 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass lint with generated endpoint', function(done) { + runTest('grunt jshint', this, done, 'foo'); + }); + it('should run server tests successfully with generated endpoint', function(done) { - this.timeout(60000); - generatorTest('endpoint', 'foo', {}, function() { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); - }); + runTest('grunt test:server', this, done, 'foo'); + }); + + it('should pass lint with generated capitalized endpoint', function(done) { + runTest('grunt jshint', this, done, 'Foo'); + }); + + it('should run server tests successfully with generated capitalized endpoint', function(done) { + runTest('grunt test:server', this, done, 'Foo'); }); it('should use existing config if available', function(done) { @@ -358,7 +376,7 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); - it('should pass jshint', function(done) { + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -366,6 +384,14 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass lint with generated snake-case endpoint', function(done) { + runTest('grunt jshint', this, done, 'foo-bar'); + }); + + it('should run server tests successfully with generated snake-case endpoint', function(done) { + runTest('grunt test:server', this, done, 'foo-bar'); + }); + it('should generate expected files', function (done) { gen.run({}, function () { helpers.assertFile(genFiles(testOptions)); @@ -403,7 +429,7 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); - it('should pass jshint', function(done) { + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -411,6 +437,14 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass lint with generated endpoint', function(done) { + runTest('grunt jshint', this, done, 'foo'); + }); + + it('should run server tests successfully with generated endpoint', function(done) { + runTest('grunt test:server', this, done, 'foo'); + }); + it('should generate expected files', function (done) { gen.run({}, function () { helpers.assertFile(genFiles(testOptions)); @@ -448,7 +482,7 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); - it('should pass jshint', function(done) { + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); From 73620809a83c2a7ab5c3d6a81f67f8bb56f8fdb7 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 10 Sep 2014 09:32:07 -0400 Subject: [PATCH 013/201] fix(gen): camelCase endpoint name when used in variable name Closes #540 --- endpoint/templates/index.spec.js | 4 ++-- endpoint/templates/name.controller.js | 30 +++++++++++++-------------- endpoint/templates/name.e2e.js | 16 +++++++------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 62caed5dc..74c17d539 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -3,7 +3,7 @@ var proxyquire = require('proxyquire').noPreserveCache(); /* <%= name %>.controller stub */ -var <%= name %>Ctrl = { +var <%= cameledName %>Ctrl = { index: '<%= name %>Ctrl.index'<% if(filters.mongoose) { %>, show: '<%= name %>Ctrl.show', create: '<%= name %>Ctrl.create', @@ -25,7 +25,7 @@ var <%= name %>Ctrl = { return router; } }, - './<%= name %>.controller': <%= name %>Ctrl + './<%= name %>.controller': <%= cameledName %>Ctrl }); describe('<%= classedName %> API Router:', function() { diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 1d9da544e..3b2bbc918 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -6,49 +6,49 @@ var <%= classedName %> = require('./<%= name %>.model');<% } %> // Get list of <%= name %>s exports.index = function(req, res) {<% if (!filters.mongoose) { %> res.json([]);<% } %><% if (filters.mongoose) { %> - <%= classedName %>.find(function (err, <%= name %>s) { + <%= classedName %>.find(function (err, <%= cameledName %>s) { if(err) { return handleError(res, err); } - return res.json(200, <%= name %>s); + return res.json(200, <%= cameledName %>s); });<% } %> };<% if (filters.mongoose) { %> // Get a single <%= name %> exports.show = function(req, res) { - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { + <%= classedName %>.findById(req.params.id, function (err, <%= cameledName %>) { if(err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - return res.json(<%= name %>); + if(!<%= cameledName %>) { return res.send(404); } + return res.json(<%= cameledName %>); }); }; // Creates a new <%= name %> in the DB. exports.create = function(req, res) { - <%= classedName %>.create(req.body, function(err, <%= name %>) { + <%= classedName %>.create(req.body, function(err, <%= cameledName %>) { if(err) { return handleError(res, err); } - return res.json(201, <%= name %>); + return res.json(201, <%= cameledName %>); }); }; // Updates an existing <%= name %> in the DB. exports.update = function(req, res) { if(req.body._id) { delete req.body._id; } - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { + <%= classedName %>.findById(req.params.id, function (err, <%= cameledName %>) { if (err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - var updated = _.merge(<%= name %>, req.body); + if(!<%= cameledName %>) { return res.send(404); } + var updated = _.merge(<%= cameledName %>, req.body); updated.save(function (err) { if (err) { return handleError(res, err); } - return res.json(200, <%= name %>); + return res.json(200, <%= cameledName %>); }); }); }; // Deletes a <%= name %> from the DB. exports.destroy = function(req, res) { - <%= classedName %>.findById(req.params.id, function (err, <%= name %>) { + <%= classedName %>.findById(req.params.id, function (err, <%= cameledName %>) { if(err) { return handleError(res, err); } - if(!<%= name %>) { return res.send(404); } - <%= name %>.remove(function(err) { + if(!<%= cameledName %>) { return res.send(404); } + <%= cameledName %>.remove(function(err) { if(err) { return handleError(res, err); } return res.send(204); }); @@ -57,4 +57,4 @@ exports.destroy = function(req, res) { function handleError(res, err) { return res.send(500, err); -}<% } %> \ No newline at end of file +}<% } %> diff --git a/endpoint/templates/name.e2e.js b/endpoint/templates/name.e2e.js index 5960b40a2..f168f1ca9 100644 --- a/endpoint/templates/name.e2e.js +++ b/endpoint/templates/name.e2e.js @@ -8,7 +8,7 @@ var new<%= classedName %>;<% } %> describe('<%= classedName %> API:', function() { describe('GET <%= route %>', function() { - var <%= name %>s; + var <%= cameledName %>s; beforeEach(function(done) { request(app) @@ -17,13 +17,13 @@ describe('<%= classedName %> API:', function() { .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); - <%= name %>s = res.body; + <%= cameledName %>s = res.body; done(); }); }); it('should respond with JSON array', function() { - <%= name %>s.should.be.instanceOf(Array); + <%= cameledName %>s.should.be.instanceOf(Array); }); });<% if(filters.mongoose) { %> @@ -53,7 +53,7 @@ describe('<%= classedName %> API:', function() { }); describe('GET <%= route %>/:id', function() { - var <%= name %>; + var <%= cameledName %>; beforeEach(function(done) { request(app) @@ -62,18 +62,18 @@ describe('<%= classedName %> API:', function() { .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); - <%= name %> = res.body; + <%= cameledName %> = res.body; done(); }); }); afterEach(function() { - <%= name %> = {}; + <%= cameledName %> = {}; }); it('should respond with the requested <%= name %>', function() { - <%= name %>.name.should.equal('New <%= classedName %>'); - <%= name %>.info.should.equal('This is the brand new <%= name %>!!!'); + <%= cameledName %>.name.should.equal('New <%= classedName %>'); + <%= cameledName %>.info.should.equal('This is the brand new <%= name %>!!!'); }); }); From ac8f335922bd77aa0781ebd4281b8b1b9186f18d Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 14 Sep 2014 18:23:01 -0600 Subject: [PATCH 014/201] style(package): remove unneeded line break --- app/templates/_package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 2d8337b71..1912903fa 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -16,8 +16,7 @@ "jade": "~1.2.0",<% } %><% if(filters.html) { %> "ejs": "~0.8.4",<% } %><% if(filters.mongoose) { %> "mongoose": "~3.8.8", - "mongoose-bird": "~0.0.1", - <% } %><% if(filters.auth) { %> + "mongoose-bird": "~0.0.1",<% } %><% if(filters.auth) { %> "jsonwebtoken": "^0.3.0", "express-jwt": "^0.1.3", "passport": "~0.2.0", From 502be54d092ff1312a7d065da47dbe3d5ec3490e Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 14 Sep 2014 18:25:38 -0600 Subject: [PATCH 015/201] remove fixtures that should not be git ignored --- .gitignore | 4 ++-- test/fixtures/package.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9e436b36f..78a6835b7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ demo .idea .DS_Store release.txt -fixtures/bower.json -fixtures/package.json \ No newline at end of file +test/fixtures/bower.json +test/fixtures/package.json \ No newline at end of file diff --git a/test/fixtures/package.json b/test/fixtures/package.json index 2304c008e..48d48607e 100644 --- a/test/fixtures/package.json +++ b/test/fixtures/package.json @@ -16,6 +16,7 @@ "jade": "~1.2.0", "ejs": "~0.8.4", "mongoose": "~3.8.8", + "mongoose-bird": "~0.0.1", "jsonwebtoken": "^0.3.0", "express-jwt": "^0.1.3", "passport": "~0.2.0", @@ -46,7 +47,7 @@ "grunt-contrib-watch": "~0.6.1", "grunt-contrib-coffee": "^0.10.1", "grunt-contrib-jade": "^0.11.0", - "grunt-contrib-less": "^0.11.0", + "grunt-contrib-less": "^0.11.4", "grunt-google-cdn": "~0.4.0", "grunt-newer": "~0.7.0", "grunt-ng-annotate": "^0.2.3", From 65d03fc8a39590e09ef36740707fdc883739e135 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 17 Aug 2014 03:48:29 -0400 Subject: [PATCH 016/201] feat(app-auth): Improve client-side Auth service Changes: - getCurrentUser, isLoggedIn, and isAdmin are now sync if no arg and async with an arg - Use Error first callback signature where applicable - Remove unused arguments from Auth service - Remove isLoggedInAsync - Switch use of isLoggedInAsync to isLoggedIn - Add/Improve comments - Fix client/app/account(auth)/settings/settings.controller(js).js Breaking Changes: - Callbacks that return Errors, use 'Error first' signature Closes #456 --- app/templates/client/app/app(coffee).coffee | 4 +- app/templates/client/app/app(js).js | 4 +- .../auth(auth)/auth.service(coffee).coffee | 93 +++++++----- .../components/auth(auth)/auth.service(js).js | 140 ++++++++++-------- 4 files changed, 136 insertions(+), 105 deletions(-) diff --git a/app/templates/client/app/app(coffee).coffee b/app/templates/client/app/app(coffee).coffee index ea9ae3c95..9c0a87a0e 100644 --- a/app/templates/client/app/app(coffee).coffee +++ b/app/templates/client/app/app(coffee).coffee @@ -34,6 +34,6 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] .run ($rootScope, $location, Auth) -> # Redirect to login if route requires auth and you're not logged in $rootScope.$on <% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> - Auth.isLoggedInAsync (loggedIn) -> + Auth.isLoggedIn (loggedIn) -> $location.path "/login" if next.authenticate and not loggedIn -<% } %> \ No newline at end of file +<% } %> diff --git a/app/templates/client/app/app(js).js b/app/templates/client/app/app(js).js index eef485d7c..4e6adea0c 100644 --- a/app/templates/client/app/app(js).js +++ b/app/templates/client/app/app(js).js @@ -46,10 +46,10 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) .run(function ($rootScope, $location, Auth) { // Redirect to login if route requires auth and you're not logged in $rootScope.$on(<% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, function (event, next) { - Auth.isLoggedInAsync(function(loggedIn) { + Auth.isLoggedIn(function(loggedIn) { if (next.authenticate && !loggedIn) { $location.path('/login'); } }); }); - })<% } %>; \ No newline at end of file + })<% } %>; diff --git a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee index ac503ed0b..4131efe53 100644 --- a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee +++ b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee @@ -1,40 +1,35 @@ 'use strict' angular.module '<%= scriptAppName %>' -.factory 'Auth', ($location, $rootScope, $http, User, $cookieStore, $q) -> +.factory 'Auth', ($http, User, $cookieStore, $q) -> currentUser = if $cookieStore.get 'token' then User.get() else {} ### Authenticate user and save token @param {Object} user - login info - @param {Function} callback - optional + @param {Function} callback - optional, function(error) @return {Promise} ### login: (user, callback) -> - deferred = $q.defer() $http.post '/auth/local', email: user.email password: user.password - .success (data) -> - $cookieStore.put 'token', data.token + .then (res) -> + $cookieStore.put 'token', res.data.token currentUser = User.get() - deferred.resolve data callback?() + res.data - .error (err) => + , (err) => @logout() - deferred.reject err - callback? err - - deferred.promise + callback? err.data + $q.reject err.data ### Delete access token and user info - - @param {Function} ### logout: -> $cookieStore.remove 'token' @@ -46,7 +41,7 @@ angular.module '<%= scriptAppName %>' Create a new user @param {Object} user - user info - @param {Function} callback - optional + @param {Function} callback - optional, function(error, user) @return {Promise} ### createUser: (user, callback) -> @@ -54,7 +49,7 @@ angular.module '<%= scriptAppName %>' (data) -> $cookieStore.put 'token', data.token currentUser = User.get() - callback? user + callback? null, user , (err) => @logout() @@ -68,7 +63,7 @@ angular.module '<%= scriptAppName %>' @param {String} oldPassword @param {String} newPassword - @param {Function} callback - optional + @param {Function} callback - optional, function(error, user) @return {Promise} ### changePassword: (oldPassword, newPassword, callback) -> @@ -79,7 +74,7 @@ angular.module '<%= scriptAppName %>' newPassword: newPassword , (user) -> - callback? user + callback? null, user , (err) -> callback? err @@ -88,45 +83,61 @@ angular.module '<%= scriptAppName %>' ### - Gets all available info on authenticated user + Gets all available info on a user + (synchronous|asynchronous) - @return {Object} user + @param {Function|*} callback - optional, funciton(user) + @return {Object|Promise} ### - getCurrentUser: -> - currentUser + getCurrentUser: (callback) -> + return currentUser if arguments.length is 0 + value = if (currentUser.hasOwnProperty("$promise")) then currentUser.$promise else currentUser + $q.when value - ### - Check if a user is logged in synchronously + .then (user) -> + callback? user + user - @return {Boolean} - ### - isLoggedIn: -> - currentUser.hasOwnProperty 'role' + , -> + callback? {} + {} ### - Waits for currentUser to resolve before checking if user is logged in + Check if a user is logged in + (synchronous|asynchronous) + + @param {Function|*} callback - optional, function(is) + @return {Bool|Promise} ### - isLoggedInAsync: (callback) -> - if currentUser.hasOwnProperty '$promise' - currentUser.$promise.then -> - callback? true - return - .catch -> - callback? false - return + isLoggedIn: (callback) -> + return currentUser.hasOwnProperty("role") if arguments.length is 0 + + @getCurrentUser null + + .then (user) -> + is_ = user.hasOwnProperty("role") + callback? is_ + is_ - else - callback? currentUser.hasOwnProperty 'role' ### Check if a user is an admin + (synchronous|asynchronous) - @return {Boolean} + @param {Function|*} callback - optional, function(is) + @return {Bool|Promise} ### - isAdmin: -> - currentUser.role is 'admin' + isAdmin: (callback) -> + return currentUser.role is "admin" if arguments_.length is 0 + + @getCurrentUser null + + .then (user) -> + is_ = user.role is "admin" + callback? is_ + is_ ### diff --git a/app/templates/client/components/auth(auth)/auth.service(js).js b/app/templates/client/components/auth(auth)/auth.service(js).js index 9afb12da9..5baf0e0b4 100644 --- a/app/templates/client/components/auth(auth)/auth.service(js).js +++ b/app/templates/client/components/auth(auth)/auth.service(js).js @@ -1,9 +1,20 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .factory('Auth', function Auth($location, $rootScope, $http, User, $cookieStore, $q) { - var currentUser = {}; - if($cookieStore.get('token')) { + .factory('Auth', function Auth($http, User, $cookieStore, $q) { + /** + * Return a callback or noop function + * + * @param {Function|*} cb - a 'potential' function + * @return {Function} + */ + var safeCb = function(cb) { + return (angular.isFunction(cb)) ? cb : angular.noop; + }, + + currentUser = {}; + + if ($cookieStore.get('token')) { currentUser = User.get(); } @@ -13,36 +24,28 @@ angular.module('<%= scriptAppName %>') * Authenticate user and save token * * @param {Object} user - login info - * @param {Function} callback - optional + * @param {Function} callback - optional, function(error) * @return {Promise} */ login: function(user, callback) { - var cb = callback || angular.noop; - var deferred = $q.defer(); - - $http.post('/auth/local', { + return $http.post('/auth/local', { email: user.email, password: user.password - }). - success(function(data) { - $cookieStore.put('token', data.token); + }) + .then(function(res) { + $cookieStore.put('token', res.data.token); currentUser = User.get(); - deferred.resolve(data); - return cb(); - }). - error(function(err) { + safeCb(callback)(); + return res.data; + }, function(err) { this.logout(); - deferred.reject(err); - return cb(err); + safeCb(callback)(err.data); + return $q.reject(err.data); }.bind(this)); - - return deferred.promise; }, /** * Delete access token and user info - * - * @param {Function} */ logout: function() { $cookieStore.remove('token'); @@ -53,21 +56,19 @@ angular.module('<%= scriptAppName %>') * Create a new user * * @param {Object} user - user info - * @param {Function} callback - optional + * @param {Function} callback - optional, function(error, user) * @return {Promise} */ createUser: function(user, callback) { - var cb = callback || angular.noop; - return User.save(user, function(data) { $cookieStore.put('token', data.token); currentUser = User.get(); - return cb(user); + return safeCb(callback)(null, user); }, function(err) { this.logout(); - return cb(err); + return safeCb(callback)(err); }.bind(this)).$promise; }, @@ -76,68 +77,87 @@ angular.module('<%= scriptAppName %>') * * @param {String} oldPassword * @param {String} newPassword - * @param {Function} callback - optional + * @param {Function} callback - optional, function(error, user) * @return {Promise} */ changePassword: function(oldPassword, newPassword, callback) { - var cb = callback || angular.noop; - return User.changePassword({ id: currentUser._id }, { oldPassword: oldPassword, newPassword: newPassword }, function(user) { - return cb(user); + return safeCb(callback)(null, user); }, function(err) { - return cb(err); + return safeCb(callback)(err); }).$promise; }, /** - * Gets all available info on authenticated user + * Gets all available info on a user + * (synchronous|asynchronous) * - * @return {Object} user + * @param {Function|*} callback - optional, funciton(user) + * @return {Object|Promise} */ - getCurrentUser: function() { - return currentUser; + getCurrentUser: function(callback) { + if (arguments.length === 0) { + return currentUser; + } + + var value = (currentUser.hasOwnProperty('$promise')) ? currentUser.$promise : currentUser; + return $q.when(value) + .then(function(user) { + safeCb(callback)(user); + return user; + }, function() { + safeCb(callback)({}); + return {}; + }); }, /** * Check if a user is logged in + * (synchronous|asynchronous) * - * @return {Boolean} + * @param {Function|*} callback - optional, function(is) + * @return {Bool|Promise} */ - isLoggedIn: function() { - return currentUser.hasOwnProperty('role'); - }, + isLoggedIn: function(callback) { + if (arguments.length === 0) { + return currentUser.hasOwnProperty('role'); + } - /** - * Waits for currentUser to resolve before checking if user is logged in - */ - isLoggedInAsync: function(cb) { - if(currentUser.hasOwnProperty('$promise')) { - currentUser.$promise.then(function() { - cb(true); - }).catch(function() { - cb(false); + return this.getCurrentUser(null) + .then(function(user) { + var is = user.hasOwnProperty('role'); + safeCb(callback)(is); + return is; }); - } else if(currentUser.hasOwnProperty('role')) { - cb(true); - } else { - cb(false); - } }, - /** - * Check if a user is an admin - * - * @return {Boolean} - */ - isAdmin: function() { - return currentUser.role === 'admin'; + /** + * Check if a user is an admin + * (synchronous|asynchronous) + * + * @param {Function|*} callback - optional, function(is) + * @return {Bool|Promise} + */ + isAdmin: function(callback) { + if (arguments.length === 0) { + return currentUser.role === 'admin'; + } + + return this.getCurrentUser(null) + .then(function(user) { + var is = user.role === 'admin'; + safeCb(callback)(is); + return is; + }); }, /** * Get auth token + * + * @return {String} - a token string used for authenticating */ getToken: function() { return $cookieStore.get('token'); From 2aaff12d3559770ee2e9bdd8a856ef808e713010 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Tue, 16 Sep 2014 23:41:46 -0600 Subject: [PATCH 017/201] fix typo --- .../client/components/auth(auth)/auth.service(coffee).coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee index 4131efe53..1d4b29544 100644 --- a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee +++ b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee @@ -130,7 +130,7 @@ angular.module '<%= scriptAppName %>' @return {Bool|Promise} ### isAdmin: (callback) -> - return currentUser.role is "admin" if arguments_.length is 0 + return currentUser.role is "admin" if arguments.length is 0 @getCurrentUser null From 6aadee6d956cefb9a787eb0851d287654dfca111 Mon Sep 17 00:00:00 2001 From: kingcody Date: Fri, 15 Aug 2014 02:50:09 -0400 Subject: [PATCH 018/201] feat(app-routing): improve app routing Changes: - Use `ui-sref` instead of `href` or `ng-href` when ui-router is chosen - Use `ui-sref-active` instead of `ng-class='{active: isActive()}'` when ui-router is chosen - Use `$state.go()` where applicable, when ui-router is chosen - Use `$scope.menu[n].state` instead of `$scope.menu[n].link` when ui-router is chosen (attempt to remove possible confusion) - Omit `$scope.isActive` when ui-router is chosen - Simplify `navbar(jade).jade` templating (remove extra `<% if (filters.auth) %>` tag) - Add `/logout` route for both ng-route and ui-router - Use `$routeChangeStart` or `$stateChangeStart` to pass refering route or state to `/logout` - Add `stateMock` for testing `$state` transitions - Use `stateMock` in main.controller for expecting template requests from state transistions Closes #331 --- .../app/account(auth)/account(coffee).coffee | 26 ++++++++++++- .../client/app/account(auth)/account(js).js | 38 ++++++++++++++++++- .../app/account(auth)/login/login(html).html | 2 +- .../app/account(auth)/login/login(jade).jade | 2 +- .../login/login.controller(coffee).coffee | 4 +- .../login/login.controller(js).js | 4 +- .../account(auth)/signup/signup(html).html | 2 +- .../account(auth)/signup/signup(jade).jade | 2 +- .../signup/signup.controller(coffee).coffee | 4 +- .../signup/signup.controller(js).js | 4 +- app/templates/client/app/app(coffee).coffee | 11 +++--- app/templates/client/app/app(js).js | 15 ++++---- .../main/main.controller.spec(coffee).coffee | 13 ++++--- .../app/main/main.controller.spec(js).js | 11 ++++-- .../components/navbar/navbar(html).html | 14 +++---- .../components/navbar/navbar(jade).jade | 24 ++++++------ .../navbar/navbar.controller(coffee).coffee | 12 ++---- .../navbar/navbar.controller(js).js | 15 +++----- .../ui-router.mock(coffee).coffee | 26 +++++++++++++ .../ui-router(uirouter)/ui-router.mock(js).js | 34 +++++++++++++++++ 20 files changed, 191 insertions(+), 72 deletions(-) create mode 100644 app/templates/client/components/ui-router(uirouter)/ui-router.mock(coffee).coffee create mode 100644 app/templates/client/components/ui-router(uirouter)/ui-router.mock(js).js diff --git a/app/templates/client/app/account(auth)/account(coffee).coffee b/app/templates/client/app/account(auth)/account(coffee).coffee index 2b7b8b23b..088fb6840 100644 --- a/app/templates/client/app/account(auth)/account(coffee).coffee +++ b/app/templates/client/app/account(auth)/account(coffee).coffee @@ -7,6 +7,14 @@ angular.module '<%= scriptAppName %>' templateUrl: 'app/account/login/login.html' controller: 'LoginCtrl' + .when '/logout', + name: 'logout' + referrer: '/' + controller: ($location, $route, Auth) -> + referrer = $route.current.params.referrer or $route.current.referrer or "/" + Auth.logout() + $location.path referrer + .when '/signup', templateUrl: 'app/account/signup/signup.html' controller: 'SignupCtrl' @@ -15,6 +23,10 @@ angular.module '<%= scriptAppName %>' templateUrl: 'app/account/settings/settings.html' controller: 'SettingsCtrl' authenticate: true + +.run ($rootScope) -> + $rootScope.$on '$routeChangeStart', (event, next, current) -> + next.referrer = current.originalPath if next.name is "logout" and current and current.originalPath and not current.authenticate <% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> $stateProvider .state 'login', @@ -22,6 +34,14 @@ angular.module '<%= scriptAppName %>' templateUrl: 'app/account/login/login.html' controller: 'LoginCtrl' + .state 'logout', + url: '/logout?referrer' + referrer: 'main' + controller: ($state, Auth) -> + referrer = $state.params.referrer or $state.current.referrer or "main" + Auth.logout() + $state.go referrer + .state 'signup', url: '/signup' templateUrl: 'app/account/signup/signup.html' @@ -32,4 +52,8 @@ angular.module '<%= scriptAppName %>' templateUrl: 'app/account/settings/settings.html' controller: 'SettingsCtrl' authenticate: true -<% } %> \ No newline at end of file + +.run ($rootScope) -> + $rootScope.$on '$stateChangeStart', (event, next, nextParams, current) -> + next.referrer = current.name if next.name is "logout" and current and current.name and not current.authenticate +<% } %> diff --git a/app/templates/client/app/account(auth)/account(js).js b/app/templates/client/app/account(auth)/account(js).js index 0e30543a5..d31ff19d2 100644 --- a/app/templates/client/app/account(auth)/account(js).js +++ b/app/templates/client/app/account(auth)/account(js).js @@ -7,6 +7,17 @@ angular.module('<%= scriptAppName %>') templateUrl: 'app/account/login/login.html', controller: 'LoginCtrl' }) + .when('/logout', { + name: 'logout', + referrer: '/', + controller: function($location, $route, Auth) { + var referrer = $route.current.params.referrer || + $route.current.referrer || + '/'; + Auth.logout(); + $location.path(referrer); + } + }) .when('/signup', { templateUrl: 'app/account/signup/signup.html', controller: 'SignupCtrl' @@ -16,6 +27,13 @@ angular.module('<%= scriptAppName %>') controller: 'SettingsCtrl', authenticate: true }); + }) + .run(function($rootScope) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + if (next.name === 'logout' && current && current.originalPath && !current.authenticate) { + next.referrer = current.originalPath; + } + }); });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { $stateProvider .state('login', { @@ -23,6 +41,17 @@ angular.module('<%= scriptAppName %>') templateUrl: 'app/account/login/login.html', controller: 'LoginCtrl' }) + .state('logout', { + url: '/logout?referrer', + referrer: 'main', + controller: function($state, Auth) { + var referrer = $state.params.referrer || + $state.current.referrer || + 'main'; + Auth.logout(); + $state.go(referrer); + } + }) .state('signup', { url: '/signup', templateUrl: 'app/account/signup/signup.html', @@ -34,4 +63,11 @@ angular.module('<%= scriptAppName %>') controller: 'SettingsCtrl', authenticate: true }); - });<% } %> \ No newline at end of file + }) + .run(function($rootScope) { + $rootScope.$on('$stateChangeStart', function(event, next, nextParams, current) { + if (next.name === 'logout' && current && current.name && !current.authenticate) { + next.referrer = current.name; + } + }); + });<% } %> diff --git a/app/templates/client/app/account(auth)/login/login(html).html b/app/templates/client/app/account(auth)/login/login(html).html index 572f2e144..49a81b55d 100644 --- a/app/templates/client/app/account(auth)/login/login(html).html +++ b/app/templates/client/app/account(auth)/login/login(html).html @@ -37,7 +37,7 @@

Login

- + ui-sref="signup"<% } else { %>href="/signup"<% } %>> Register diff --git a/app/templates/client/app/account(auth)/login/login(jade).jade b/app/templates/client/app/account(auth)/login/login(jade).jade index 4b13c0b13..686b1769e 100644 --- a/app/templates/client/app/account(auth)/login/login(jade).jade +++ b/app/templates/client/app/account(auth)/login/login(jade).jade @@ -34,7 +34,7 @@ div(ng-include='"components/navbar/navbar.html"') button.btn.btn-inverse.btn-lg.btn-login(type='submit') | Login = ' ' - a.btn.btn-default.btn-lg.btn-register(href='/signup') + a.btn.btn-default.btn-lg.btn-register(<% if(filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) | Register <% if(filters.oauth) {%> hr diff --git a/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee b/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee index 3f90c25d7..036191f93 100644 --- a/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee +++ b/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee @@ -1,7 +1,7 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'LoginCtrl', ($scope, Auth, $location<% if(filters.oauth) {%>, $window<% } %>) -> +.controller 'LoginCtrl', ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if(filters.oauth) {%>, $window<% } %>) -> $scope.user = {} $scope.errors = {} $scope.login = (form) -> @@ -14,7 +14,7 @@ angular.module '<%= scriptAppName %>' password: $scope.user.password .then -> - $location.path '/' + <% if(filters.ngroute) { %>$location.path '/'<% } %><% if(filters.uirouter) { %>$state.go 'main'<% } %> .catch (err) -> $scope.errors.other = err.message diff --git a/app/templates/client/app/account(auth)/login/login.controller(js).js b/app/templates/client/app/account(auth)/login/login.controller(js).js index 7b13da384..e2c5dcaa4 100644 --- a/app/templates/client/app/account(auth)/login/login.controller(js).js +++ b/app/templates/client/app/account(auth)/login/login.controller(js).js @@ -1,7 +1,7 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('LoginCtrl', function ($scope, Auth, $location<% if (filters.oauth) { %>, $window<% } %>) { + .controller('LoginCtrl', function ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { $scope.user = {}; $scope.errors = {}; @@ -15,7 +15,7 @@ angular.module('<%= scriptAppName %>') }) .then( function() { // Logged in, redirect to home - $location.path('/'); + <% if(filters.ngroute) { %>$location.path('/');<% } %><% if(filters.uirouter) { %>$state.go('main');<% } %> }) .catch( function(err) { $scope.errors.other = err.message; diff --git a/app/templates/client/app/account(auth)/signup/signup(html).html b/app/templates/client/app/account(auth)/signup/signup(html).html index 59faed568..28d6c39ab 100644 --- a/app/templates/client/app/account(auth)/signup/signup(html).html +++ b/app/templates/client/app/account(auth)/signup/signup(html).html @@ -58,7 +58,7 @@

Sign up

- + ui-sref="login"<% } else { %>href="/login"<% } %>> Login diff --git a/app/templates/client/app/account(auth)/signup/signup(jade).jade b/app/templates/client/app/account(auth)/signup/signup(jade).jade index 43815a21c..7e21b101c 100644 --- a/app/templates/client/app/account(auth)/signup/signup(jade).jade +++ b/app/templates/client/app/account(auth)/signup/signup(jade).jade @@ -36,7 +36,7 @@ div(ng-include='"components/navbar/navbar.html"') button.btn.btn-inverse.btn-lg.btn-login(type='submit') | Sign up = ' ' - a.btn.btn-default.btn-lg.btn-register(href='/login') + a.btn.btn-default.btn-lg.btn-register(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) | Login <% if(filters.oauth) {%> diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee index 1b9c9696f..ac240faa8 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee +++ b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee @@ -1,7 +1,7 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'SignupCtrl', ($scope, Auth, $location<% if(filters.oauth) {%>, $window<% } %>) -> +.controller 'SignupCtrl', ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if(filters.oauth) {%>, $window<% } %>) -> $scope.user = {} $scope.errors = {} $scope.register = (form) -> @@ -15,7 +15,7 @@ angular.module '<%= scriptAppName %>' password: $scope.user.password .then -> - $location.path '/' + <% if(filters.ngroute) { %>$location.path '/'<% } %><% if(filters.uirouter) { %>$state.go 'main'<% } %> .catch (err) -> err = err.data diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(js).js b/app/templates/client/app/account(auth)/signup/signup.controller(js).js index 7d6ba3d38..10685079d 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(js).js +++ b/app/templates/client/app/account(auth)/signup/signup.controller(js).js @@ -1,7 +1,7 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('SignupCtrl', function ($scope, Auth, $location<% if (filters.oauth) { %>, $window<% } %>) { + .controller('SignupCtrl', function ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { $scope.user = {}; $scope.errors = {}; @@ -16,7 +16,7 @@ angular.module('<%= scriptAppName %>') }) .then( function() { // Account created, redirect to home - $location.path('/'); + <% if(filters.ngroute) { %>$location.path('/');<% } %><% if(filters.uirouter) { %>$state.go('main');<% } %> }) .catch( function(err) { err = err.data; diff --git a/app/templates/client/app/app(coffee).coffee b/app/templates/client/app/app(coffee).coffee index 9c0a87a0e..cb6d0c5b1 100644 --- a/app/templates/client/app/app(coffee).coffee +++ b/app/templates/client/app/app(coffee).coffee @@ -15,8 +15,9 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] $locationProvider.html5Mode true<% if(filters.auth) { %> $httpProvider.interceptors.push 'authInterceptor'<% } %> <% } %><% if(filters.auth) { %> -.factory 'authInterceptor', ($rootScope, $q, $cookieStore, $location) -> - # Add authorization token to headers +.factory 'authInterceptor', ($rootScope, $q, $cookieStore<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $injector<% } %>) -> + <% if(filters.uirouter) { %>state = null + <% } %># Add authorization token to headers request: (config) -> config.headers = config.headers or {} config.headers.Authorization = 'Bearer ' + $cookieStore.get 'token' if $cookieStore.get 'token' @@ -25,15 +26,15 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] # Intercept 401s and redirect you to login responseError: (response) -> if response.status is 401 - $location.path '/login' + <% if(filters.ngroute) { %>$location.path '/login'<% } if(filters.uirouter) { %>(state || state = $injector.get '$state').go 'login'<% } %> # remove any stale tokens $cookieStore.remove 'token' $q.reject response -.run ($rootScope, $location, Auth) -> +.run ($rootScope<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %>, Auth) -> # Redirect to login if route requires auth and you're not logged in $rootScope.$on <% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> Auth.isLoggedIn (loggedIn) -> - $location.path "/login" if next.authenticate and not loggedIn + <% if(filters.ngroute) { %>$location.path '/login'<% } %><% if(filters.uirouter) { %>$state.go 'login'<% } %> if next.authenticate and not loggedIn <% } %> diff --git a/app/templates/client/app/app(js).js b/app/templates/client/app/app(js).js index 4e6adea0c..35b8ad327 100644 --- a/app/templates/client/app/app(js).js +++ b/app/templates/client/app/app(js).js @@ -9,16 +9,17 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) $locationProvider.html5Mode(true);<% if(filters.auth) { %> $httpProvider.interceptors.push('authInterceptor');<% } %> - })<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { + })<% } if(filters.uirouter) { %>.config(function ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { $urlRouterProvider .otherwise('/'); $locationProvider.html5Mode(true);<% if(filters.auth) { %> $httpProvider.interceptors.push('authInterceptor');<% } %> - })<% } %><% if(filters.auth) { %> + })<% } if(filters.auth) { %> - .factory('authInterceptor', function ($rootScope, $q, $cookieStore, $location) { - return { + .factory('authInterceptor', function ($rootScope, $q, $cookieStore<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $injector<% } %>) { + <% if(filters.uirouter) { %>var state; + <% } %>return { // Add authorization token to headers request: function (config) { config.headers = config.headers || {}; @@ -31,7 +32,7 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) // Intercept 401s and redirect you to login responseError: function(response) { if(response.status === 401) { - $location.path('/login'); + <% if(filters.ngroute) { %>$location.path('/login');<% } if(filters.uirouter) { %>(state || (state = $injector.get('$state'))).go('login');<% } %> // remove any stale tokens $cookieStore.remove('token'); return $q.reject(response); @@ -43,12 +44,12 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) }; }) - .run(function ($rootScope, $location, Auth) { + .run(function ($rootScope<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $state<% } %>, Auth) { // Redirect to login if route requires auth and you're not logged in $rootScope.$on(<% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, function (event, next) { Auth.isLoggedIn(function(loggedIn) { if (next.authenticate && !loggedIn) { - $location.path('/login'); + <% if(filters.ngroute) { %>$location.path('/login');<% } if(filters.uirouter) { %>$state.go('login');<% } %> } }); }); diff --git a/app/templates/client/app/main/main.controller.spec(coffee).coffee b/app/templates/client/app/main/main.controller.spec(coffee).coffee index efe9b39a6..f974a081d 100644 --- a/app/templates/client/app/main/main.controller.spec(coffee).coffee +++ b/app/templates/client/app/main/main.controller.spec(coffee).coffee @@ -3,15 +3,17 @@ describe 'Controller: MainCtrl', -> # load the controller's module - beforeEach module '<%= scriptAppName %>' <% if(filters.socketio) {%> + beforeEach module '<%= scriptAppName %>' <% if(filters.uirouter) {%> + beforeEach module 'stateMock' <% } %><% if(filters.socketio) {%> beforeEach module 'socketMock' <% } %> MainCtrl = undefined - scope = undefined + scope = undefined<% if(filters.uirouter) {%> + state = undefined<% } %> $httpBackend = undefined # Initialize the controller and a mock scope - beforeEach inject (_$httpBackend_, $controller, $rootScope) -> + beforeEach inject (_$httpBackend_, $controller, $rootScope<% if(filters.uirouter) {%>, $state<% } %>) -> $httpBackend = _$httpBackend_ $httpBackend.expectGET('/api/things').respond [ 'HTML5 Boilerplate' @@ -19,10 +21,11 @@ describe 'Controller: MainCtrl', -> 'Karma' 'Express' ] - scope = $rootScope.$new() + scope = $rootScope.$new()<% if(filters.uirouter) {%> + state = $state<% } %> MainCtrl = $controller 'MainCtrl', $scope: scope it 'should attach a list of things to the scope', -> $httpBackend.flush() - expect(scope.awesomeThings.length).toBe 4 \ No newline at end of file + expect(scope.awesomeThings.length).toBe 4 diff --git a/app/templates/client/app/main/main.controller.spec(js).js b/app/templates/client/app/main/main.controller.spec(js).js index 373e9db08..21b8aba70 100644 --- a/app/templates/client/app/main/main.controller.spec(js).js +++ b/app/templates/client/app/main/main.controller.spec(js).js @@ -3,20 +3,23 @@ describe('Controller: MainCtrl', function () { // load the controller's module - beforeEach(module('<%= scriptAppName %>'));<% if(filters.socketio) {%> + beforeEach(module('<%= scriptAppName %>'));<% if(filters.uirouter) {%> + beforeEach(module('stateMock'));<% } %><% if(filters.socketio) {%> beforeEach(module('socketMock'));<% } %> var MainCtrl, - scope, + scope,<% if(filters.uirouter) {%> + state,<% } %> $httpBackend; // Initialize the controller and a mock scope - beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { + beforeEach(inject(function (_$httpBackend_, $controller, $rootScope<% if(filters.uirouter) {%>, $state<% } %>) { $httpBackend = _$httpBackend_; $httpBackend.expectGET('/api/things') .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']); - scope = $rootScope.$new(); + scope = $rootScope.$new();<% if(filters.uirouter) {%> + state = $state;<% } %> MainCtrl = $controller('MainCtrl', { $scope: scope }); diff --git a/app/templates/client/components/navbar/navbar(html).html b/app/templates/client/components/navbar/navbar(html).html index 71f8606dd..a93839562 100644 --- a/app/templates/client/components/navbar/navbar(html).html +++ b/app/templates/client/components/navbar/navbar(html).html @@ -11,18 +11,18 @@ diff --git a/app/templates/client/components/navbar/navbar(jade).jade b/app/templates/client/components/navbar/navbar(jade).jade index 2b17f29c3..7863f4e0a 100644 --- a/app/templates/client/components/navbar/navbar(jade).jade +++ b/app/templates/client/components/navbar/navbar(jade).jade @@ -10,25 +10,25 @@ div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarCtrl') div#navbar-main.navbar-collapse.collapse(collapse='isCollapsed') ul.nav.navbar-nav - li(ng-repeat='item in menu', ng-class='{active: isActive(item.link)}') - a(ng-href='{{item.link}}') {{item.title}}<% if(filters.auth) { %> + li(ng-repeat='item in menu', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive(item.link)}'<% } %>) + a(<% if(filters.uirouter) { %>ui-sref='{{item.state}}'<% } else { %>ng-href='{{item.link}}'<% } %>) {{item.title}}<% if(filters.auth) { %> - li(ng-show='isAdmin()', ng-class='{active: isActive("/admin")}') - a(href='/admin') Admin<% } %><% if(filters.auth) { %> + li(ng-show='isAdmin()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/admin")}'<% } %>) + a(<% if(filters.uirouter) { %>ui-sref='admin'<% } else { %>href='/admin'<% } %>) Admin ul.nav.navbar-nav.navbar-right - li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/signup")}') - a(href='/signup') Sign up + li(ng-hide='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/signup")}'<% } %>) + a(<% if(filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) Sign up - li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/login")}') - a(href='/login') Login + li(ng-hide='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/login")}'<% } %>) + a(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) Login li(ng-show='isLoggedIn()') p.navbar-text Hello {{ getCurrentUser().name }} - li(ng-show='isLoggedIn()', ng-class='{active: isActive("/settings")}') - a(href='/settings') + li(ng-show='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/settings")}'<% } %>) + a(<% if(filters.uirouter) { %>ui-sref='settings'<% } else { %>href='/settings'<% } %>) span.glyphicon.glyphicon-cog - li(ng-show='isLoggedIn()', ng-class='{active: isActive("/logout")}') - a(href='', ng-click='logout()') Logout<% } %> \ No newline at end of file + li(ng-show='isLoggedIn()') + a(<% if(filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %> \ No newline at end of file diff --git a/app/templates/client/components/navbar/navbar.controller(coffee).coffee b/app/templates/client/components/navbar/navbar.controller(coffee).coffee index d3804c5eb..121437cf1 100644 --- a/app/templates/client/components/navbar/navbar.controller(coffee).coffee +++ b/app/templates/client/components/navbar/navbar.controller(coffee).coffee @@ -1,19 +1,15 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'NavbarCtrl', ($scope, $location<% if(filters.auth) {%>, Auth<% } %>) -> +.controller 'NavbarCtrl', ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if(filters.auth) {%>, Auth<% } %>) -> $scope.menu = [ title: 'Home' - link: '/' + <% if(filters.uirouter) { %>state: 'main'<% } else { %>link: '/'<% } %> ] $scope.isCollapsed = true<% if(filters.auth) {%> $scope.isLoggedIn = Auth.isLoggedIn $scope.isAdmin = Auth.isAdmin - $scope.getCurrentUser = Auth.getCurrentUser - - $scope.logout = -> - Auth.logout() - $location.path '/login'<% } %> + $scope.getCurrentUser = Auth.getCurrentUser<% } %><% if(!filters.uirouter) { %> $scope.isActive = (route) -> - route is $location.path() \ No newline at end of file + route is $location.path()<% } %> \ No newline at end of file diff --git a/app/templates/client/components/navbar/navbar.controller(js).js b/app/templates/client/components/navbar/navbar.controller(js).js index 4ce9dbcb5..2428ac15b 100644 --- a/app/templates/client/components/navbar/navbar.controller(js).js +++ b/app/templates/client/components/navbar/navbar.controller(js).js @@ -1,23 +1,18 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('NavbarCtrl', function ($scope, $location<% if(filters.auth) {%>, Auth<% } %>) { + .controller('NavbarCtrl', function ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if(filters.auth) {%>, Auth<% } %>) { $scope.menu = [{ 'title': 'Home', - 'link': '/' + <% if(filters.uirouter) { %>'state': 'main'<% } else { %>'link': '/'<% } %> }]; $scope.isCollapsed = true;<% if(filters.auth) {%> $scope.isLoggedIn = Auth.isLoggedIn; $scope.isAdmin = Auth.isAdmin; - $scope.getCurrentUser = Auth.getCurrentUser; - - $scope.logout = function() { - Auth.logout(); - $location.path('/login'); - };<% } %> + $scope.getCurrentUser = Auth.getCurrentUser;<% } %><% if(!filters.uirouter) { %> $scope.isActive = function(route) { return route === $location.path(); - }; - }); \ No newline at end of file + };<% } %> + }); diff --git a/app/templates/client/components/ui-router(uirouter)/ui-router.mock(coffee).coffee b/app/templates/client/components/ui-router(uirouter)/ui-router.mock(coffee).coffee new file mode 100644 index 000000000..ff3937c35 --- /dev/null +++ b/app/templates/client/components/ui-router(uirouter)/ui-router.mock(coffee).coffee @@ -0,0 +1,26 @@ +'use strict' + +angular.module 'stateMock', [] +angular.module('stateMock').service '$state', ($q) -> + @expectedTransitions = [] + + @transitionTo = (stateName) -> + if @expectedTransitions.length > 0 + expectedState = @expectedTransitions.shift() + throw Error('Expected transition to state: ' + expectedState + ' but transitioned to ' + stateName) if expectedState isnt stateName + else + throw Error('No more transitions were expected! Tried to transition to ' + stateName) + console.log 'Mock transition to: ' + stateName + deferred = $q.defer() + promise = deferred.promise + deferred.resolve() + promise + + @go = @transitionTo + + @expectTransitionTo = (stateName) -> + @expectedTransitions.push stateName + + @ensureAllTransitionsHappened = -> + throw Error('Not all transitions happened!') if @expectedTransitions.length > 0 + @ diff --git a/app/templates/client/components/ui-router(uirouter)/ui-router.mock(js).js b/app/templates/client/components/ui-router(uirouter)/ui-router.mock(js).js new file mode 100644 index 000000000..a5a1bf413 --- /dev/null +++ b/app/templates/client/components/ui-router(uirouter)/ui-router.mock(js).js @@ -0,0 +1,34 @@ +'use strict'; + +angular.module('stateMock', []); +angular.module('stateMock').service('$state', function($q) { + this.expectedTransitions = []; + + this.transitionTo = function(stateName) { + if (this.expectedTransitions.length > 0) { + var expectedState = this.expectedTransitions.shift(); + if (expectedState !== stateName) { + throw Error('Expected transition to state: ' + expectedState + ' but transitioned to ' + stateName); + } + } else { + throw Error('No more transitions were expected! Tried to transition to ' + stateName); + } + console.log('Mock transition to: ' + stateName); + var deferred = $q.defer(); + var promise = deferred.promise; + deferred.resolve(); + return promise; + }; + + this.go = this.transitionTo; + + this.expectTransitionTo = function(stateName) { + this.expectedTransitions.push(stateName); + }; + + this.ensureAllTransitionsHappened = function() { + if (this.expectedTransitions.length > 0) { + throw Error('Not all transitions happened!'); + } + }; +}); From fb28c28daf8ac777f15644bc2cde2fd149f90788 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Tue, 16 Sep 2014 23:22:45 -0600 Subject: [PATCH 019/201] expect uirouter mocks in tests --- test/test-file-creation.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index b6171fabd..05e83c77f 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -174,11 +174,17 @@ describe('angular-fullstack generator', function () { 'protractor.conf.js' ]); + if (ops.router === 'uirouter') { + files = files.concat([ + 'client/components/ui-router/ui-router.mock.' + script + ]); + } + if (ops.uibootstrap) { files = files.concat([ 'client/components/modal/modal.' + markup, 'client/components/modal/modal.' + stylesheet, - 'client/components/modal/modal.service.' + script, + 'client/components/modal/modal.service.' + script ]); } From f0e568a9b427b9fc67eef4f8a2ec752a10bdead3 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 19:31:16 -0600 Subject: [PATCH 020/201] rename server side e2e tests to integration tests --- app/templates/Gruntfile.js | 24 +++++++++---------- .../{thing.e2e.js => thing.integration.js} | 0 .../{user.e2e.js => user.integration.js} | 0 .../{name.e2e.js => name.integration.js} | 0 4 files changed, 12 insertions(+), 12 deletions(-) rename app/templates/server/api/thing/{thing.e2e.js => thing.integration.js} (100%) rename app/templates/server/api/user(auth)/{user.e2e.js => user.integration.js} (100%) rename endpoint/templates/{name.e2e.js => name.integration.js} (100%) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index a72f42dae..6cd422daa 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -170,14 +170,14 @@ module.exports = function (grunt) { }, src: [ 'server/**/*.js', - '!server/**/*.{spec,e2e}.js' + '!server/**/*.{spec,integration}.js' ] }, serverTest: { options: { jshintrc: 'server/.jshintrc-spec' }, - src: ['server/**/*.{spec,e2e}.js'] + src: ['server/**/*.{spec,integration}.js'] }, all: [ '<%%= yeoman.client %>/{app,components}/**/*.js', @@ -493,8 +493,8 @@ module.exports = function (grunt) { unit: { src: ['server/**/*.spec.js'] }, - e2e: { - src: ['server/**/*.e2e.js'] + integration: { + src: ['server/**/*.integration.js'] } }, @@ -504,7 +504,7 @@ module.exports = function (grunt) { excludes: [ '**/*.spec.js', '**/*.mock.js', - '**/*.e2e.js' + '**/*.integration.js' ], reporter: 'spec', require: ['mocha.conf.js'], @@ -513,17 +513,17 @@ module.exports = function (grunt) { }, src: 'server' }, - e2e: { + integration: { options: { excludes: [ '**/*.spec.js', '**/*.mock.js', - '**/*.e2e.js' + '**/*.integration.js' ], reporter: 'spec', require: ['mocha.conf.js'], - mask: '**/*.e2e.js', - coverageFolder: 'coverage/server/e2e' + mask: '**/*.integration.js', + coverageFolder: 'coverage/server/integration' }, src: 'server' } @@ -822,7 +822,7 @@ module.exports = function (grunt) { 'env:all', 'env:test', 'mochaTest:unit', - 'mochaTest:e2e' + 'mochaTest:integration' ]); } @@ -867,11 +867,11 @@ module.exports = function (grunt) { ]); } - else if (option === 'e2e') { + else if (option === 'integration') { return grunt.task.run([ 'env:all', 'env:test', - 'mocha_istanbul:e2e' + 'mocha_istanbul:integration' ]); } diff --git a/app/templates/server/api/thing/thing.e2e.js b/app/templates/server/api/thing/thing.integration.js similarity index 100% rename from app/templates/server/api/thing/thing.e2e.js rename to app/templates/server/api/thing/thing.integration.js diff --git a/app/templates/server/api/user(auth)/user.e2e.js b/app/templates/server/api/user(auth)/user.integration.js similarity index 100% rename from app/templates/server/api/user(auth)/user.e2e.js rename to app/templates/server/api/user(auth)/user.integration.js diff --git a/endpoint/templates/name.e2e.js b/endpoint/templates/name.integration.js similarity index 100% rename from endpoint/templates/name.e2e.js rename to endpoint/templates/name.integration.js From f1b5b9a101f600dae3289960942c290169e280e4 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 20:53:10 -0600 Subject: [PATCH 021/201] style(tests): use consistent code style for route tests, clarify names --- app/templates/server/api/thing/index.spec.js | 64 +++++++------- .../server/api/user(auth)/index.spec.js | 84 +++++++++---------- endpoint/templates/index.spec.js | 64 +++++++------- 3 files changed, 106 insertions(+), 106 deletions(-) diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js index e62feff60..3c6c71fc2 100644 --- a/app/templates/server/api/thing/index.spec.js +++ b/app/templates/server/api/thing/index.spec.js @@ -2,42 +2,42 @@ var proxyquire = require('proxyquire').noPreserveCache(); - /* thing.controller stub */ -var thingCtrl = { - index: 'thingCtrl.index'<% if(filters.mongoose) { %>, - show: 'thingCtrl.show', - create: 'thingCtrl.create', - update: 'thingCtrl.update', - destroy: 'thingCtrl.destroy'<% } %> - }, - /* express.Router().router stub */ - router = { - get: sinon.spy()<% if(filters.mongoose) { %>, - put: sinon.spy(), - patch: sinon.spy(), - post: sinon.spy(), - delete: sinon.spy()<% } %> - }, - /* stubbed thing router */ - index = proxyquire('./index.js', { - 'express': { - Router: function() { - return router; - } - }, - './thing.controller': thingCtrl - }); +var thingCtrlStub = { + index: 'thingCtrl.index'<% if(filters.mongoose) { %>, + show: 'thingCtrl.show', + create: 'thingCtrl.create', + update: 'thingCtrl.update', + destroy: 'thingCtrl.destroy'<% } %> +}; + +var routerStub = { + get: sinon.spy()<% if(filters.mongoose) { %>, + put: sinon.spy(), + patch: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy()<% } %> +}; + +// require the index with our stubbed out modules +var thingIndex = proxyquire('./index.js', { + 'express': { + Router: function() { + return routerStub; + } + }, + './thing.controller': thingCtrlStub +}); describe('Thing API Router:', function() { it('should return an express router instance', function() { - index.should.equal(router); + thingIndex.should.equal(routerStub); }); describe('GET /api/things', function() { it('should route to thing.controller.index', function() { - router.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; + routerStub.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; }); });<% if(filters.mongoose) { %> @@ -45,7 +45,7 @@ describe('Thing API Router:', function() { describe('GET /api/things/:id', function() { it('should route to thing.controller.show', function() { - router.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; + routerStub.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; }); }); @@ -53,7 +53,7 @@ describe('Thing API Router:', function() { describe('POST /api/things', function() { it('should route to thing.controller.create', function() { - router.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; + routerStub.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; }); }); @@ -61,7 +61,7 @@ describe('Thing API Router:', function() { describe('PUT /api/things/:id', function() { it('should route to thing.controller.update', function() { - router.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + routerStub.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; }); }); @@ -69,7 +69,7 @@ describe('Thing API Router:', function() { describe('PATCH /api/things/:id', function() { it('should route to thing.controller.update', function() { - router.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + routerStub.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; }); }); @@ -77,7 +77,7 @@ describe('Thing API Router:', function() { describe('DELETE /api/things/:id', function() { it('should route to thing.controller.destroy', function() { - router.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; + routerStub.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; }); });<% } %> diff --git a/app/templates/server/api/user(auth)/index.spec.js b/app/templates/server/api/user(auth)/index.spec.js index 30b786fb3..b2510aa00 100644 --- a/app/templates/server/api/user(auth)/index.spec.js +++ b/app/templates/server/api/user(auth)/index.spec.js @@ -2,52 +2,52 @@ var proxyquire = require('proxyquire').noPreserveCache(); - /* user.controller stub */ -var userCtrl = { - index: 'userCtrl.index', - destroy: 'userCtrl.destroy', - me: 'userCtrl.me', - changePassword: 'userCtrl.changePassword', - show: 'userCtrl.show', - create: 'userCtrl.create' - }, - /* auth.service stub */ - authService = { - isAuthenticated: function() { - return 'authService.isAuthenticated'; - }, - hasRole: function(role) { - return 'authService.hasRole.' + role; - } - }, - /* express.Router().router stub */ - router = { - get: sinon.spy(), - put: sinon.spy(), - post: sinon.spy(), - delete: sinon.spy() - }, - /* stubbed user router */ - index = proxyquire('./index', { - 'express': { - Router: function() { - return router; - } - }, - './user.controller': userCtrl, - '../../auth/auth.service': authService - }); +var userCtrlStub = { + index: 'userCtrl.index', + destroy: 'userCtrl.destroy', + me: 'userCtrl.me', + changePassword: 'userCtrl.changePassword', + show: 'userCtrl.show', + create: 'userCtrl.create' +}; + +var authServiceStub = { + isAuthenticated: function() { + return 'authService.isAuthenticated'; + }, + hasRole: function(role) { + return 'authService.hasRole.' + role; + } +}; + +var routerStub = { + get: sinon.spy(), + put: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy() +}; + +// require the index with our stubbed out modules +var userIndex = proxyquire('./index', { + 'express': { + Router: function() { + return routerStub; + } + }, + './user.controller': userCtrlStub, + '../../auth/auth.service': authServiceStub +}); describe('User API Router:', function() { it('should return an express router instance', function() { - index.should.equal(router); + userIndex.should.equal(routerStub); }); describe('GET /api/users', function() { it('should verify admin role and route to user.controller.index', function() { - router.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; + routerStub.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; }); }); @@ -55,7 +55,7 @@ describe('User API Router:', function() { describe('DELETE /api/users/:id', function() { it('should verify admin role and route to user.controller.destroy', function() { - router.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; + routerStub.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; }); }); @@ -63,7 +63,7 @@ describe('User API Router:', function() { describe('GET /api/users/me', function() { it('should be authenticated and route to user.controller.me', function() { - router.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; + routerStub.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; }); }); @@ -71,7 +71,7 @@ describe('User API Router:', function() { describe('PUT /api/users/:id/password', function() { it('should be authenticated and route to user.controller.changePassword', function() { - router.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; + routerStub.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; }); }); @@ -79,7 +79,7 @@ describe('User API Router:', function() { describe('GET /api/users/:id', function() { it('should be authenticated and route to user.controller.show', function() { - router.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; + routerStub.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; }); }); @@ -87,7 +87,7 @@ describe('User API Router:', function() { describe('POST /api/users', function() { it('should route to user.controller.create', function() { - router.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; + routerStub.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; }); }); diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 648a841a0..031e379a4 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -2,42 +2,42 @@ var proxyquire = require('proxyquire').noPreserveCache(); - /* <%= name %>.controller stub */ -var <%= cameledName %>Ctrl = { - index: '<%= name %>Ctrl.index'<% if(filters.mongoose) { %>, - show: '<%= name %>Ctrl.show', - create: '<%= name %>Ctrl.create', - update: '<%= name %>Ctrl.update', - destroy: '<%= name %>Ctrl.destroy'<% } %> - }, - /* express.Router().router stub */ - router = { - get: sinon.spy()<% if(filters.mongoose) { %>, - put: sinon.spy(), - patch: sinon.spy(), - post: sinon.spy(), - delete: sinon.spy()<% } %> - }, - /* stubbed <%= name %> router */ - index = proxyquire('./index.js', { - 'express': { - Router: function() { - return router; - } - }, - './<%= name %>.controller': <%= cameledName %>Ctrl - }); +var <%= cameledName %>CtrlStub = { + index: '<%= name %>Ctrl.index'<% if(filters.mongoose) { %>, + show: '<%= name %>Ctrl.show', + create: '<%= name %>Ctrl.create', + update: '<%= name %>Ctrl.update', + destroy: '<%= name %>Ctrl.destroy'<% } %> +}; + +var routerStub = { + get: sinon.spy()<% if(filters.mongoose) { %>, + put: sinon.spy(), + patch: sinon.spy(), + post: sinon.spy(), + delete: sinon.spy()<% } %> +}; + +// require the index with our stubbed out modules +var <%= name %>Index = proxyquire('./index.js', { + 'express': { + Router: function() { + return routerStub; + } + }, + './<%= name %>.controller': <%= cameledName %>CtrlStub +}); describe('<%= classedName %> API Router:', function() { it('should return an express router instance', function() { - index.should.equal(router); + <%= name %>Index.should.equal(router); }); describe('GET <%= route %>', function() { it('should route to <%= name %>.controller.index', function() { - router.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; + routerStub.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; }); });<% if(filters.mongoose) { %> @@ -45,7 +45,7 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>/:id', function() { it('should route to <%= name %>.controller.show', function() { - router.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; + routerStub.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; }); }); @@ -53,7 +53,7 @@ describe('<%= classedName %> API Router:', function() { describe('POST <%= route %>', function() { it('should route to <%= name %>.controller.create', function() { - router.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; + routerStub.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; }); }); @@ -61,7 +61,7 @@ describe('<%= classedName %> API Router:', function() { describe('PUT <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - router.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + routerStub.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; }); }); @@ -69,7 +69,7 @@ describe('<%= classedName %> API Router:', function() { describe('PATCH <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - router.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + routerStub.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; }); }); @@ -77,7 +77,7 @@ describe('<%= classedName %> API Router:', function() { describe('DELETE <%= route %>/:id', function() { it('should route to <%= name %>.controller.destroy', function() { - router.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; + routerStub.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; }); });<% } %> From 56134c0c20a131e5fd14bb3f6cf00cd67d7fc0c3 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 20:59:01 -0600 Subject: [PATCH 022/201] style(server): missing semicolon --- app/templates/server/api/thing/thing.socket(socketio).js | 2 +- endpoint/templates/name.socket(socketio).js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/server/api/thing/thing.socket(socketio).js b/app/templates/server/api/thing/thing.socket(socketio).js index dbf3e2fe7..d38e73e0d 100644 --- a/app/templates/server/api/thing/thing.socket(socketio).js +++ b/app/templates/server/api/thing/thing.socket(socketio).js @@ -13,7 +13,7 @@ exports.register = function(socket) { thing.schema.post('remove', function (doc) { onRemove(socket, doc); }); -} +}; function onSave(socket, doc, cb) { socket.emit('thing:save', doc); diff --git a/endpoint/templates/name.socket(socketio).js b/endpoint/templates/name.socket(socketio).js index 886f585ee..aabdadeb8 100644 --- a/endpoint/templates/name.socket(socketio).js +++ b/endpoint/templates/name.socket(socketio).js @@ -13,7 +13,7 @@ exports.register = function(socket) { <%= classedName %>.schema.post('remove', function (doc) { onRemove(socket, doc); }); -} +}; function onSave(socket, doc, cb) { socket.emit('<%= name %>:save', doc); From cda5261d75679b08400370230ff55662e846f7e5 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 21:33:40 -0600 Subject: [PATCH 023/201] use spread for saveAsync methods fixes #567, closes #568 --- app/templates/server/api/thing/thing.controller.js | 2 +- app/templates/server/api/user(auth)/user.controller.js | 4 ++-- endpoint/templates/name.controller.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/templates/server/api/thing/thing.controller.js b/app/templates/server/api/thing/thing.controller.js index 4d5abca05..23bfd6937 100644 --- a/app/templates/server/api/thing/thing.controller.js +++ b/app/templates/server/api/thing/thing.controller.js @@ -42,7 +42,7 @@ function saveUpdates(updates){ return function(entity){ var updated = _.merge(entity, updates); return updated.saveAsync() - .then(function () { + .spread(function (updated) { return updated; }); }; diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index 28e30199a..ed0b1749c 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -46,7 +46,7 @@ exports.create = function (req, res, next) { newUser.provider = 'local'; newUser.role = 'user'; newUser.saveAsync() - .then(function(user) { + .spread(function(user) { var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresInMinutes: 60*5 }); res.json({ token: token }); }) @@ -94,7 +94,7 @@ exports.changePassword = function(req, res, next) { if(user.authenticate(oldPass)) { user.password = newPass; return user.saveAsync() - .then(respondWith(res, 200)) + .spread(respondWith(res, 200)) .catch(validationError(res)); } else { return res.send(403); diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 5851a1338..2afb2be8c 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -33,7 +33,7 @@ function saveUpdates(updates){ return function(entity){ var updated = _.merge(entity, updates); return updated.saveAsync() - .then(function () { + .spread(function (updated) { return updated; }); }; From a817ec9ad3ecdbc93ffd21c617eecf4606f87775 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 23:19:41 -0600 Subject: [PATCH 024/201] fix test failures --- endpoint/templates/index.spec.js | 4 ++-- test/test-file-creation.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 031e379a4..fd1086b15 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -19,7 +19,7 @@ var routerStub = { }; // require the index with our stubbed out modules -var <%= name %>Index = proxyquire('./index.js', { +var <%= cameledName %>Index = proxyquire('./index.js', { 'express': { Router: function() { return routerStub; @@ -31,7 +31,7 @@ var <%= name %>Index = proxyquire('./index.js', { describe('<%= classedName %> API Router:', function() { it('should return an express router instance', function() { - <%= name %>Index.should.equal(router); + <%= cameledName %>Index.should.equal(routerStub); }); describe('GET <%= route %>', function() { diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 05e83c77f..ced7ce4ee 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -149,7 +149,7 @@ describe('angular-fullstack generator', function () { 'server/api/thing/index.js', 'server/api/thing/index.spec.js', 'server/api/thing/thing.controller.js', - 'server/api/thing/thing.e2e.js', + 'server/api/thing/thing.integration.js', 'server/components/errors/index.js', 'server/config/local.env.js', 'server/config/local.env.sample.js', @@ -215,7 +215,7 @@ describe('angular-fullstack generator', function () { 'server/api/user/index.js', 'server/api/user/index.spec.js', 'server/api/user/user.controller.js', - 'server/api/user/user.e2e.js', + 'server/api/user/user.integration.js', 'server/api/user/user.model.js', 'server/api/user/user.model.spec.js', 'server/auth/index.js', From 0fbea07d92e3e157ea013e5a77a2b4c51b636089 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 21 Sep 2014 05:09:45 -0400 Subject: [PATCH 025/201] test(app): add protractor tests for account pages Changes: - add protractor tests for auth related pages - add `onPrepare` and `params` to `protractor.conf.js` --- .../e2e/account(auth)/login/login.po.js | 27 ++++++++ .../e2e/account(auth)/login/login.spec.js | 62 +++++++++++++++++++ .../e2e/account(auth)/logout/logout.spec.js | 46 ++++++++++++++ .../e2e/account(auth)/signup/signup.po.js | 28 +++++++++ .../e2e/account(auth)/signup/signup.spec.js | 61 ++++++++++++++++++ .../e2e/components/navbar/navbar.po.js | 16 +++++ app/templates/protractor.conf.js | 18 +++++- 7 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 app/templates/e2e/account(auth)/login/login.po.js create mode 100644 app/templates/e2e/account(auth)/login/login.spec.js create mode 100644 app/templates/e2e/account(auth)/logout/logout.spec.js create mode 100644 app/templates/e2e/account(auth)/signup/signup.po.js create mode 100644 app/templates/e2e/account(auth)/signup/signup.spec.js create mode 100644 app/templates/e2e/components/navbar/navbar.po.js diff --git a/app/templates/e2e/account(auth)/login/login.po.js b/app/templates/e2e/account(auth)/login/login.po.js new file mode 100644 index 000000000..1186cdb6b --- /dev/null +++ b/app/templates/e2e/account(auth)/login/login.po.js @@ -0,0 +1,27 @@ +/** + * This file uses the Page Object pattern to define the main page for tests + * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ + */ + +'use strict'; + +var LoginPage = function() { + this.form = element(by.css('.form')); + this.form.email = this.form.element(by.model('user.email')); + this.form.password = this.form.element(by.model('user.password')); + this.form.submit = this.form.element(by.css('.btn-login')); + + this.login = function(data) { + for (var prop in data) { + var formElem = this.form[prop]; + if (data.hasOwnProperty(prop) && formElem && typeof formElem.sendKeys === 'function') { + formElem.sendKeys(data[prop]); + } + } + + this.form.submit.click(); + }; +}; + +module.exports = new LoginPage(); + diff --git a/app/templates/e2e/account(auth)/login/login.spec.js b/app/templates/e2e/account(auth)/login/login.spec.js new file mode 100644 index 000000000..d3f0d48ed --- /dev/null +++ b/app/templates/e2e/account(auth)/login/login.spec.js @@ -0,0 +1,62 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Login View', function() { + var page; + + var loadPage = function() { + browser.get('/login'); + page = require('./login.po'); + }; + + var testUser = { + name: 'Test User', + email: 'test@test.com', + password: 'test' + }; + + beforeEach(function(done) { + UserModel.removeAsync() + .then(function() { + return UserModel.createAsync(testUser); + }) + .then(loadPage) + .finally(done); + }); + + it('should include login form with correct inputs and submit button', function() { + expect(page.form.email.getAttribute('type')).toBe('email'); + expect(page.form.email.getAttribute('name')).toBe('email'); + expect(page.form.password.getAttribute('type')).toBe('password'); + expect(page.form.password.getAttribute('name')).toBe('password'); + expect(page.form.submit.getAttribute('type')).toBe('submit'); + expect(page.form.submit.getText()).toBe('Login'); + }); + + describe('with local auth', function() { + + it('should login a user and redirecting to "/"', function() { + page.login(testUser); + + var navbar = require('../../components/navbar/navbar.po'); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/'); + expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name); + }); + + it('should indicate login failures', function() { + page.login({ + email: testUser.email, + password: 'badPassword' + }); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/login'); + + var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding')); + expect(helpBlock.getText()).toBe('This password is not correct.'); + }); + + }); +}); diff --git a/app/templates/e2e/account(auth)/logout/logout.spec.js b/app/templates/e2e/account(auth)/logout/logout.spec.js new file mode 100644 index 000000000..f496459d8 --- /dev/null +++ b/app/templates/e2e/account(auth)/logout/logout.spec.js @@ -0,0 +1,46 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Logout View', function() { + var login = function(user) { + browser.get('/login'); + require('../login/login.po').login(user); + }; + + var testUser = { + name: 'Test User', + email: 'test@test.com', + password: 'test' + }; + + beforeEach(function(done) { + UserModel.removeAsync() + .then(function() { + return UserModel.createAsync(testUser); + }) + .then(function() { + return login(testUser); + }) + .finally(done); + }); + + describe('with local auth', function() { + + it('should logout a user and redirecting to "/"', function() { + var navbar = require('../../components/navbar/navbar.po'); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/'); + expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name); + + browser.get('/logout'); + + navbar = require('../../components/navbar/navbar.po'); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/'); + expect(navbar.navbarAccountGreeting.isDisplayed()).toBe(false); + }); + + }); +}); diff --git a/app/templates/e2e/account(auth)/signup/signup.po.js b/app/templates/e2e/account(auth)/signup/signup.po.js new file mode 100644 index 000000000..3a496c6e3 --- /dev/null +++ b/app/templates/e2e/account(auth)/signup/signup.po.js @@ -0,0 +1,28 @@ +/** + * This file uses the Page Object pattern to define the main page for tests + * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ + */ + +'use strict'; + +var SignupPage = function() { + this.form = element(by.css('.form')); + this.form.name = this.form.element(by.model('user.name')); + this.form.email = this.form.element(by.model('user.email')); + this.form.password = this.form.element(by.model('user.password')); + this.form.submit = this.form.element(by.css('.btn-register')); + + this.signup = function(data) { + for (var prop in data) { + var formElem = this.form[prop]; + if (data.hasOwnProperty(prop) && formElem && typeof formElem.sendKeys === 'function') { + formElem.sendKeys(data[prop]); + } + } + + this.form.submit.click(); + }; +}; + +module.exports = new SignupPage(); + diff --git a/app/templates/e2e/account(auth)/signup/signup.spec.js b/app/templates/e2e/account(auth)/signup/signup.spec.js new file mode 100644 index 000000000..cc63a5b7b --- /dev/null +++ b/app/templates/e2e/account(auth)/signup/signup.spec.js @@ -0,0 +1,61 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Signup View', function() { + var page; + + var loadPage = function() { + browser.get('/signup'); + page = require('./signup.po'); + }; + + var testUser = { + name: 'Test User', + email: 'test@test.com', + password: 'test' + }; + + beforeEach(function() { + loadPage(); + }); + + it('should include signup form with correct inputs and submit button', function() { + expect(page.form.name.getAttribute('type')).toBe('text'); + expect(page.form.name.getAttribute('name')).toBe('name'); + expect(page.form.email.getAttribute('type')).toBe('email'); + expect(page.form.email.getAttribute('name')).toBe('email'); + expect(page.form.password.getAttribute('type')).toBe('password'); + expect(page.form.password.getAttribute('name')).toBe('password'); + expect(page.form.submit.getAttribute('type')).toBe('submit'); + expect(page.form.submit.getText()).toBe('Sign up'); + }); + + describe('with local auth', function() { + + it('should signup a new user, log them in, and redirecting to "/"', function(done) { + UserModel.remove(function() { + page.signup(testUser); + + var navbar = require('../../components/navbar/navbar.po'); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/'); + expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name); + + done(); + }); + }); + + it('should indicate signup failures', function() { + page.signup(testUser); + + expect(browser.getLocationAbsUrl()).toBe(config.baseUrl + '/signup'); + expect(page.form.email.getAttribute('class')).toContain('ng-invalid-mongoose'); + + var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding')); + expect(helpBlock.getText()).toBe('The specified email address is already in use.'); + }); + + }); +}); diff --git a/app/templates/e2e/components/navbar/navbar.po.js b/app/templates/e2e/components/navbar/navbar.po.js new file mode 100644 index 000000000..ee2ec1ada --- /dev/null +++ b/app/templates/e2e/components/navbar/navbar.po.js @@ -0,0 +1,16 @@ +/** + * This file uses the Page Object pattern to define the main page for tests + * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ + */ + +'use strict'; + +var NavbarComponent = function() { + this.navbar = element(by.css('.navbar')); + this.navbarHeader = this.navbar.element(by.css('.navbar-header')); + this.navbarNav = this.navbar.element(by.css('#navbar-main .nav.navbar-nav:not(.navbar-right)'));<% if(filters.auth) { %> + this.navbarAccount = this.navbar.element(by.css('#navbar-main .nav.navbar-nav.navbar-right')); + this.navbarAccountGreeting = this.navbarAccount.element(by.binding('Hello {{ getCurrentUser().name }}'));<% } %> +}; + +module.exports = new NavbarComponent(); diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index cb66c67c1..195733525 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -3,7 +3,7 @@ 'use strict'; -exports.config = { +var config = { // The timeout for each script run on the browser. This should be longer // than the maximum time your application needs to stabilize between tasks. allScriptsTimeout: 110000, @@ -46,5 +46,21 @@ exports.config = { // See the full list at https://github.com/juliemr/minijasminenode jasmineNodeOpts: { defaultTimeoutInterval: 30000 + }, + + // Prepare environment for tests + params: { + serverConfig: require('./server/config/environment') + }, + + onPrepare: function() { + var serverConfig = config.params.serverConfig; + + // Setup mongo tests + var mongoose = require('mongoose-bird')(); + mongoose.connect(serverConfig.mongo.uri, serverConfig.mongo.options); // Connect to database } }; + +config.params.baseUrl = config.baseUrl; +exports.config = config; From 5898e0c98f552bc5a3609a7329f4f200de0cc262 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 21 Sep 2014 05:52:31 -0400 Subject: [PATCH 026/201] fix(app-signup): switch button classes --- .../client/app/account(auth)/signup/signup(html).html | 4 ++-- .../client/app/account(auth)/signup/signup(jade).jade | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/templates/client/app/account(auth)/signup/signup(html).html b/app/templates/client/app/account(auth)/signup/signup(html).html index 28d6c39ab..ee4f17fa4 100644 --- a/app/templates/client/app/account(auth)/signup/signup(html).html +++ b/app/templates/client/app/account(auth)/signup/signup(html).html @@ -55,10 +55,10 @@

Sign up

diff --git a/app/templates/client/app/account(auth)/signup/signup(jade).jade b/app/templates/client/app/account(auth)/signup/signup(jade).jade index 7e21b101c..8c5710686 100644 --- a/app/templates/client/app/account(auth)/signup/signup(jade).jade +++ b/app/templates/client/app/account(auth)/signup/signup(jade).jade @@ -33,10 +33,10 @@ div(ng-include='"components/navbar/navbar.html"') | {{ errors.password }} div - button.btn.btn-inverse.btn-lg.btn-login(type='submit') + button.btn.btn-inverse.btn-lg.btn-register(type='submit') | Sign up = ' ' - a.btn.btn-default.btn-lg.btn-register(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) + a.btn.btn-default.btn-lg.btn-login(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) | Login <% if(filters.oauth) {%> From 650d244b8b36c254848743929fb9ee2498343265 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 21 Sep 2014 05:56:17 -0400 Subject: [PATCH 027/201] fix(app-logout): add blank templates to logout route/state Closes #570 --- app/templates/client/app/account(auth)/account(js).js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/templates/client/app/account(auth)/account(js).js b/app/templates/client/app/account(auth)/account(js).js index d31ff19d2..8c005c952 100644 --- a/app/templates/client/app/account(auth)/account(js).js +++ b/app/templates/client/app/account(auth)/account(js).js @@ -10,6 +10,7 @@ angular.module('<%= scriptAppName %>') .when('/logout', { name: 'logout', referrer: '/', + template: '', controller: function($location, $route, Auth) { var referrer = $route.current.params.referrer || $route.current.referrer || @@ -44,6 +45,7 @@ angular.module('<%= scriptAppName %>') .state('logout', { url: '/logout?referrer', referrer: 'main', + template: '', controller: function($state, Auth) { var referrer = $state.params.referrer || $state.current.referrer || From 50ca41d21b71962e829bc2743cc37819c650dc41 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 20 Sep 2014 23:19:41 -0600 Subject: [PATCH 028/201] feat(generator): use sauce labs for running e2e tests with travis CI closes #572 --- .travis.yml | 6 ++++++ Gruntfile.js | 18 +++++++++++++----- app/templates/protractor.conf.js | 7 ++++--- endpoint/templates/index.spec.js | 4 ++-- test/test-file-creation.js | 24 +++++++++++------------- 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85fbe4a6b..ae5a22e65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,12 @@ language: node_js node_js: - '0.10' - '0.11' +env: + global: + - secure: fBqMlUrbIwaRJeKe39zxVsRcvtPIP/R98JNzrD0ycHzdfbhsWge0J7FCpdKjgRCf99ggqMhyevJafSJv7cfiVgJhB6kYudhG0G60V+vBjj4NIZnOelpVeQHXyLlekRpu+Qa/DaL43jovRAI0I11cwVfIRWtXZwiQOjCd/Elsdl8= + - secure: GZ95FcH0K88RG7P0SJjoIcHLfUalFRHeu5Vd7Kh0wXTh3O6Zku7iauk6Cd+aYGuFedL5wSzht5qnVBRm10VxhhJMxHiZ+I+VBxt4bysKM0axMZ+SMTfPK3zajVVXKfzIsIYO0m0qwYtHCgSXUrMnwAczESxczxq48VxA/rCXbYc= +addons: + sauce_connect: true before_install: - gem update --system - gem install sass --version "=3.3.7" diff --git a/Gruntfile.js b/Gruntfile.js index 9819a4041..3a510072a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -3,7 +3,7 @@ var markdown = require('marked'); var semver = require('semver'); var _s = require('underscore.string'); var shell = require('shelljs'); -var process = require('child_process'); +var child_process = require('child_process'); var Q = require('q'); var helpers = require('yeoman-generator').test; var fs = require('fs-extra'); @@ -227,12 +227,20 @@ module.exports = function (grunt) { shell.cd('test/fixtures'); grunt.log.ok('installing npm dependencies for generated app'); - process.exec('npm install --quiet', {cwd: '../fixtures'}, function (error, stdout, stderr) { + child_process.exec('npm install --quiet', {cwd: '../fixtures'}, function (error, stdout, stderr) { grunt.log.ok('installing bower dependencies for generated app'); - process.exec('bower install', {cwd: '../fixtures'}, function (error, stdout, stderr) { - shell.cd('../../'); - done(); + child_process.exec('bower install', {cwd: '../fixtures'}, function (error, stdout, stderr) { + + if(!process.env.SAUCE_USERNAME) { + child_process.exec('npm run update-webdriver', function() { + shell.cd('../../'); + done(); + }); + } else { + shell.cd('../../'); + done(); + } }) }); }); diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index cb66c67c1..d05f9e4d1 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -12,9 +12,10 @@ exports.config = { // with relative paths will be prepended with this. baseUrl: 'http://localhost:' + (process.env.PORT || '9000'), - // If true, only chromedriver will be started, not a standalone selenium. - // Tests for browsers other than chrome will not run. - chromeOnly: true, + // Credientials for Saucelabs + sauceUser: process.env.SAUCE_USERNAME, + + sauceKey: process.env.SAUCE_ACCESS_KEY, // list of files / patterns to load in the browser specs: [ diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 031e379a4..fd1086b15 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -19,7 +19,7 @@ var routerStub = { }; // require the index with our stubbed out modules -var <%= name %>Index = proxyquire('./index.js', { +var <%= cameledName %>Index = proxyquire('./index.js', { 'express': { Router: function() { return routerStub; @@ -31,7 +31,7 @@ var <%= name %>Index = proxyquire('./index.js', { describe('<%= classedName %> API Router:', function() { it('should return an express router instance', function() { - <%= name %>Index.should.equal(router); + <%= cameledName %>Index.should.equal(routerStub); }); describe('GET <%= route %>', function() { diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 05e83c77f..568315d92 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -149,7 +149,7 @@ describe('angular-fullstack generator', function () { 'server/api/thing/index.js', 'server/api/thing/index.spec.js', 'server/api/thing/thing.controller.js', - 'server/api/thing/thing.e2e.js', + 'server/api/thing/thing.integration.js', 'server/components/errors/index.js', 'server/config/local.env.js', 'server/config/local.env.sample.js', @@ -215,7 +215,7 @@ describe('angular-fullstack generator', function () { 'server/api/user/index.js', 'server/api/user/index.spec.js', 'server/api/user/user.controller.js', - 'server/api/user/user.e2e.js', + 'server/api/user/user.integration.js', 'server/api/user/user.model.js', 'server/api/user/user.model.spec.js', 'server/auth/index.js', @@ -347,17 +347,15 @@ describe('angular-fullstack generator', function () { }); }); -// it('should run e2e tests successfully', function(done) { -// this.timeout(80000); -// gen.run({}, function () { -// exec('npm run update-webdriver', function (error, stdout, stderr) { -// exec('grunt test:e2e', function (error, stdout, stderr) { -// expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Done, without errors.'); -// done(); -// }); -// }); -// }) -// }); + it('should run e2e tests successfully', function(done) { + this.timeout(80000); + gen.run({}, function () { + exec('grunt test:e2e', function (error, stdout, stderr) { + expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); + done(); + }); + }); + }); }); describe('with other preprocessors and oauth', function() { From 7bd31938ca5116e62fafb30812e80d78b5d4c2ca Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 05:20:24 -0600 Subject: [PATCH 029/201] add log info for running npm run update-webdriver --- Gruntfile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Gruntfile.js b/Gruntfile.js index 3a510072a..8edbe3ccd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -233,6 +233,7 @@ module.exports = function (grunt) { child_process.exec('bower install', {cwd: '../fixtures'}, function (error, stdout, stderr) { if(!process.env.SAUCE_USERNAME) { + grunt.log.ok('running npm run update-webdriver'); child_process.exec('npm run update-webdriver', function() { shell.cd('../../'); done(); From 24bfde4de8e747ecfcd8b8b7737044fefffb7623 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 13:41:26 -0600 Subject: [PATCH 030/201] add capabilities to protractor config --- app/templates/protractor.conf.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index 2bdcde7fe..18b9ba6af 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -32,7 +32,10 @@ var config = { // and // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js capabilities: { - 'browserName': 'chrome' + 'browserName': 'chrome', + 'name': 'Fullstack E2E', + 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER, + 'build': process.env.TRAVIS_BUILD_NUMBER }, // ----- The test framework ----- From 456631e056fede3d2e0afad6d88b793cdffc45ca Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 14:06:21 -0600 Subject: [PATCH 031/201] use opensauce saucelabs account --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae5a22e65..d408bd4db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ node_js: - '0.11' env: global: - - secure: fBqMlUrbIwaRJeKe39zxVsRcvtPIP/R98JNzrD0ycHzdfbhsWge0J7FCpdKjgRCf99ggqMhyevJafSJv7cfiVgJhB6kYudhG0G60V+vBjj4NIZnOelpVeQHXyLlekRpu+Qa/DaL43jovRAI0I11cwVfIRWtXZwiQOjCd/Elsdl8= - - secure: GZ95FcH0K88RG7P0SJjoIcHLfUalFRHeu5Vd7Kh0wXTh3O6Zku7iauk6Cd+aYGuFedL5wSzht5qnVBRm10VxhhJMxHiZ+I+VBxt4bysKM0axMZ+SMTfPK3zajVVXKfzIsIYO0m0qwYtHCgSXUrMnwAczESxczxq48VxA/rCXbYc= + - secure: hwJX8w4D15UPdU4UIS+iB4XC/lxmh/y6m3IN5Ia5ha++rHs2JZ3FVOPdosb03fMoXYpR2682pzvTEHrZw6Ks0dpmJs3KJWB4kgsK7slfKyKA38j8rDvSU+iBfiB2lo8lTmj9g5Ua8c2hiJcw6EMt8VlLlhgoJLy3heycPTsW04A= + - secure: gl/h7p5S+hfR7Cv2tl53c+biW3Mfhh6P4VI4VxrPFj5Mm1ha89dbMYjPn0PuLkmjaZ2+n9siU7j6lwlOdyWGAo0tkPtK/EC62L2Q938O204jD8VXnvjQ8kbP9zcjHogicD+elF0X5hvnXApW9I7nOZIs59V5Pp8DXkuHEWMIo8U= addons: sauce_connect: true before_install: From fca79d9a93c736328d19686dd1d77c2ed423d778 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 18:30:14 -0600 Subject: [PATCH 032/201] caching folders to reduce build time --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index d408bd4db..63d45919a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,11 @@ env: - secure: gl/h7p5S+hfR7Cv2tl53c+biW3Mfhh6P4VI4VxrPFj5Mm1ha89dbMYjPn0PuLkmjaZ2+n9siU7j6lwlOdyWGAo0tkPtK/EC62L2Q938O204jD8VXnvjQ8kbP9zcjHogicD+elF0X5hvnXApW9I7nOZIs59V5Pp8DXkuHEWMIo8U= addons: sauce_connect: true +cache: + directories: + - node_modules + - test/fixtures/node_modules + - test/fixtures/bower_components before_install: - gem update --system - gem install sass --version "=3.3.7" From f9e7f6d7af72201675a1f528062313df95b098d4 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 18:38:38 -0600 Subject: [PATCH 033/201] revert caching --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63d45919a..d408bd4db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,11 +8,6 @@ env: - secure: gl/h7p5S+hfR7Cv2tl53c+biW3Mfhh6P4VI4VxrPFj5Mm1ha89dbMYjPn0PuLkmjaZ2+n9siU7j6lwlOdyWGAo0tkPtK/EC62L2Q938O204jD8VXnvjQ8kbP9zcjHogicD+elF0X5hvnXApW9I7nOZIs59V5Pp8DXkuHEWMIo8U= addons: sauce_connect: true -cache: - directories: - - node_modules - - test/fixtures/node_modules - - test/fixtures/bower_components before_install: - gem update --system - gem install sass --version "=3.3.7" From 25d91873d1e9adedd39a2d165ca807bfbbf15d5e Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 19:32:57 -0600 Subject: [PATCH 034/201] fix test timeouts and sign up test failure --- app/templates/e2e/account(auth)/signup/signup.spec.js | 2 +- test/test-file-creation.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/e2e/account(auth)/signup/signup.spec.js b/app/templates/e2e/account(auth)/signup/signup.spec.js index cc63a5b7b..856786e4a 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec.js +++ b/app/templates/e2e/account(auth)/signup/signup.spec.js @@ -12,7 +12,7 @@ describe('Signup View', function() { }; var testUser = { - name: 'Test User', + name: 'Test', email: 'test@test.com', password: 'test' }; diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 568315d92..35ca54538 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -348,7 +348,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - this.timeout(80000); + this.timeout(240000); // 4 minutes gen.run({}, function () { exec('grunt test:e2e', function (error, stdout, stderr) { expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); From 2f3ee4f5cb790144d8b2d24c6e4f56d814fa1375 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 19:50:56 -0600 Subject: [PATCH 035/201] run e2e tests for other builds --- .../app/account(auth)/login/login(jade).jade | 2 +- test/test-file-creation.js | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/templates/client/app/account(auth)/login/login(jade).jade b/app/templates/client/app/account(auth)/login/login(jade).jade index 686b1769e..5f608a67b 100644 --- a/app/templates/client/app/account(auth)/login/login(jade).jade +++ b/app/templates/client/app/account(auth)/login/login(jade).jade @@ -20,7 +20,7 @@ div(ng-include='"components/navbar/navbar.html"') form.form(name='form', ng-submit='login(form)', novalidate='') .form-group label Email - input.form-control(type='text', name='email', ng-model='user.email') + input.form-control(type='email', name='email', ng-model='user.email') .form-group label Password input.form-control(type='password', name='password', ng-model='user.password') diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 35ca54538..5eab66047 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -408,6 +408,16 @@ describe('angular-fullstack generator', function () { assertOnlyFiles(genFiles(testOptions), done); }); }); + + it('should run e2e tests successfully', function(done) { + this.timeout(240000); // 4 minutes + gen.run({}, function () { + exec('grunt test:e2e', function (error, stdout, stderr) { + expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); + done(); + }); + }); + }); }); describe('with other preprocessors and no server options', function() { @@ -461,6 +471,16 @@ describe('angular-fullstack generator', function () { assertOnlyFiles(genFiles(testOptions), done); }); }); + + it('should run e2e tests successfully', function(done) { + this.timeout(240000); // 4 minutes + gen.run({}, function () { + exec('grunt test:e2e', function (error, stdout, stderr) { + expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); + done(); + }); + }); + }); }); describe('with no preprocessors and no server options', function() { @@ -506,6 +526,16 @@ describe('angular-fullstack generator', function () { assertOnlyFiles(genFiles(testOptions), done); }); }); + + it('should run e2e tests successfully', function(done) { + this.timeout(240000); // 4 minutes + gen.run({}, function () { + exec('grunt test:e2e', function (error, stdout, stderr) { + expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); + done(); + }); + }); + }); }); }); }); From 4bf07505509b64c65906220ec12da3288402790f Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 20:14:23 -0600 Subject: [PATCH 036/201] chore(docs): remove outdated readme from test folder --- test/readme.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test/readme.md diff --git a/test/readme.md b/test/readme.md deleted file mode 100644 index 6c709f50b..000000000 --- a/test/readme.md +++ /dev/null @@ -1 +0,0 @@ -Run bower install and npm install in the fixtures folder before running tests \ No newline at end of file From c131bc4d451e02404785130df0f5b36ad8802da8 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 22:15:24 -0600 Subject: [PATCH 037/201] make tests more dry --- test/test-file-creation.js | 42 +++++++++++++------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 5eab66047..aecb08dcb 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -61,6 +61,16 @@ describe('angular-fullstack generator', function () { }); } + function runE2E() { + this.timeout(240000); // 4 minutes + gen.run({}, function () { + exec('grunt test:e2e', function (error, stdout, stderr) { + expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); + done(); + }); + }); + }; + function runTest(cmd, self, cb) { var args = Array.prototype.slice.call(arguments), endpoint = (args[3] && typeof args[3] === 'string') ? args.splice(3, 1)[0] : null, @@ -348,13 +358,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - this.timeout(240000); // 4 minutes - gen.run({}, function () { - exec('grunt test:e2e', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); - done(); - }); - }); + runE2E(); }); }); @@ -410,13 +414,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - this.timeout(240000); // 4 minutes - gen.run({}, function () { - exec('grunt test:e2e', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); - done(); - }); - }); + runE2E(); }); }); @@ -473,13 +471,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - this.timeout(240000); // 4 minutes - gen.run({}, function () { - exec('grunt test:e2e', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); - done(); - }); - }); + runE2E(); }); }); @@ -528,13 +520,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - this.timeout(240000); // 4 minutes - gen.run({}, function () { - exec('grunt test:e2e', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); - done(); - }); - }); + runE2E(); }); }); }); From 828857bbd1a2c4147ecd943fdc9a6625888e89ec Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Mon, 22 Sep 2014 01:51:23 -0600 Subject: [PATCH 038/201] fix test failure --- test/test-file-creation.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index aecb08dcb..31ed71ab2 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -61,8 +61,8 @@ describe('angular-fullstack generator', function () { }); } - function runE2E() { - this.timeout(240000); // 4 minutes + function runE2E(self, done) { + self.timeout(240000); // 4 minutes gen.run({}, function () { exec('grunt test:e2e', function (error, stdout, stderr) { expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); @@ -87,6 +87,9 @@ describe('angular-fullstack generator', function () { case 'grunt jshint': expect(stdout).to.contain('Done, without errors.'); break; + case 'grunt jscs': + expect(stdout).to.contain('Done, without errors.'); + break; case 'grunt test:server': expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); break; @@ -358,7 +361,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(); + runE2E(this, done); }); }); @@ -414,7 +417,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(); + runE2E(this, done); }); }); @@ -471,7 +474,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(); + runE2E(this, done); }); }); @@ -520,7 +523,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(); + runE2E(this, done); }); }); }); From 4667013bb9f621e514a3f178985389ddc1d8af10 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Thu, 25 Sep 2014 19:40:11 -0600 Subject: [PATCH 039/201] update sauce labs config so e2e tests can run against pull requests --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d408bd4db..6b84b4557 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ node_js: - '0.11' env: global: - - secure: hwJX8w4D15UPdU4UIS+iB4XC/lxmh/y6m3IN5Ia5ha++rHs2JZ3FVOPdosb03fMoXYpR2682pzvTEHrZw6Ks0dpmJs3KJWB4kgsK7slfKyKA38j8rDvSU+iBfiB2lo8lTmj9g5Ua8c2hiJcw6EMt8VlLlhgoJLy3heycPTsW04A= - - secure: gl/h7p5S+hfR7Cv2tl53c+biW3Mfhh6P4VI4VxrPFj5Mm1ha89dbMYjPn0PuLkmjaZ2+n9siU7j6lwlOdyWGAo0tkPtK/EC62L2Q938O204jD8VXnvjQ8kbP9zcjHogicD+elF0X5hvnXApW9I7nOZIs59V5Pp8DXkuHEWMIo8U= + - SAUCE_USERNAME=fullstack-ci + - SAUCE_ACCESS_KEY=1a527ca6-4aa5-4618-86ce-0278bf158cbf addons: sauce_connect: true before_install: From d2bd1f5d820e0fd03f81ab7aa8d3880530721195 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Thu, 25 Sep 2014 23:12:25 -0600 Subject: [PATCH 040/201] fix sauce username --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6b84b4557..676afbb43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ node_js: - '0.11' env: global: - - SAUCE_USERNAME=fullstack-ci + - SAUCE_USERNAME=fullstack_ci - SAUCE_ACCESS_KEY=1a527ca6-4aa5-4618-86ce-0278bf158cbf addons: sauce_connect: true From 654de87ff7d695b9ff8d2b91b43f0b860d6c7e56 Mon Sep 17 00:00:00 2001 From: kingcody Date: Mon, 22 Sep 2014 06:37:09 -0400 Subject: [PATCH 041/201] feat(gen): unify testing framework Changes: - add prompt for Jasmine or Mocha - if Mocha choosen, prompt for Expect or Should - use `<%= does() %>` to dynamically insert assertions (expect|should) - add mocha variants for protractor tests - add mocha options to protractor.conf - remove `test/fixtures/(bower|package).json` from repo - move runE2E functionality to runTest and simplify switch - comment generator test functions - use node `0.11.13` in travis due to issues with `0.11.14`+ Note: Server-side jasmine test are needed to fully unify testing frameworks. Once Jasmine tests are included for server, mocha dep can be removed fully when selecting Jasmine. --- .travis.yml | 2 +- app/index.js | 133 +++++++++++++----- app/templates/_package.json | 18 ++- .../main/main.controller.spec(coffee).coffee | 5 +- .../app/main/main.controller.spec(js).js | 5 +- .../{login.spec.js => login.spec(jasmine).js} | 0 .../account(auth)/login/login.spec(mocha).js | 73 ++++++++++ ...logout.spec.js => logout.spec(jasmine).js} | 0 .../logout/logout.spec(mocha).js | 50 +++++++ ...signup.spec.js => signup.spec(jasmine).js} | 0 .../signup/signup.spec(mocha).js | 72 ++++++++++ .../{main.spec.js => main.spec(jasmine).js} | 0 app/templates/e2e/main/main.spec(mocha).js | 16 +++ app/templates/karma.conf.js | 13 +- app/templates/mocha.conf.js | 16 ++- app/templates/protractor.conf.js | 26 +++- script-base.js | 11 +- test/fixtures/bower.json | 25 ---- test/fixtures/package.json | 104 -------------- test/test-file-creation.js | 85 ++++++++--- 20 files changed, 438 insertions(+), 216 deletions(-) rename app/templates/e2e/account(auth)/login/{login.spec.js => login.spec(jasmine).js} (100%) create mode 100644 app/templates/e2e/account(auth)/login/login.spec(mocha).js rename app/templates/e2e/account(auth)/logout/{logout.spec.js => logout.spec(jasmine).js} (100%) create mode 100644 app/templates/e2e/account(auth)/logout/logout.spec(mocha).js rename app/templates/e2e/account(auth)/signup/{signup.spec.js => signup.spec(jasmine).js} (100%) create mode 100644 app/templates/e2e/account(auth)/signup/signup.spec(mocha).js rename app/templates/e2e/main/{main.spec.js => main.spec(jasmine).js} (100%) create mode 100644 app/templates/e2e/main/main.spec(mocha).js delete mode 100644 test/fixtures/bower.json delete mode 100644 test/fixtures/package.json diff --git a/.travis.yml b/.travis.yml index 676afbb43..e1abfbd26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js node_js: - '0.10' - - '0.11' + - '0.11.13' env: global: - SAUCE_USERNAME=fullstack_ci diff --git a/app/index.js b/app/index.js index 6e4724801..7dcee4d55 100644 --- a/app/index.js +++ b/app/index.js @@ -24,6 +24,15 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.pkg = require('../package.json'); this.filters = {}; + + // dynamic assertion statement + this.does = this.is = function(foo) { + if (this.filters.should) { + return foo + '.should'; + } else { + return 'expect(' + foo + ').to'; + } + }.bind(this); }, info: function () { @@ -36,9 +45,9 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ if(this.config.get('filters')) { this.prompt([{ - type: "confirm", - name: "skipConfig", - message: "Existing .yo-rc configuration found, would you like to use it?", + type: 'confirm', + name: 'skipConfig', + message: 'Existing .yo-rc configuration found, would you like to use it?', default: true, }], function (answers) { this.skipConfig = answers.skipConfig; @@ -66,10 +75,10 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.log('# Client\n'); this.prompt([{ - type: "list", - name: "script", - message: "What would you like to write scripts with?", - choices: [ "JavaScript", "CoffeeScript"], + type: 'list', + name: 'script', + message: 'What would you like to write scripts with?', + choices: [ 'JavaScript', 'CoffeeScript'], filter: function( val ) { var filterMap = { 'JavaScript': 'js', @@ -79,33 +88,33 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ return filterMap[val]; } }, { - type: "list", - name: "markup", - message: "What would you like to write markup with?", - choices: [ "HTML", "Jade"], + type: 'list', + name: 'markup', + message: 'What would you like to write markup with?', + choices: [ 'HTML', 'Jade'], filter: function( val ) { return val.toLowerCase(); } }, { - type: "list", - name: "stylesheet", + type: 'list', + name: 'stylesheet', default: 1, - message: "What would you like to write stylesheets with?", - choices: [ "CSS", "Sass", "Stylus", "Less"], + message: 'What would you like to write stylesheets with?', + choices: [ 'CSS', 'Sass', 'Stylus', 'Less'], filter: function( val ) { return val.toLowerCase(); } }, { - type: "list", - name: "router", + type: 'list', + name: 'router', default: 1, - message: "What Angular router would you like to use?", - choices: [ "ngRoute", "uiRouter"], + message: 'What Angular router would you like to use?', + choices: [ 'ngRoute', 'uiRouter'], filter: function( val ) { return val.toLowerCase(); } }, { - type: "confirm", - name: "bootstrap", - message: "Would you like to include Bootstrap?" + type: 'confirm', + name: 'bootstrap', + message: 'Would you like to include Bootstrap?' }, { - type: "confirm", - name: "uibootstrap", - message: "Would you like to include UI Bootstrap?", + type: 'confirm', + name: 'uibootstrap', + message: 'Would you like to include UI Bootstrap?', when: function (answers) { return answers.bootstrap; } @@ -116,7 +125,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.filters[answers.router] = true; this.filters.bootstrap = !!answers.bootstrap; this.filters.uibootstrap = !!answers.uibootstrap; - cb(); + cb(); }.bind(this)); }, @@ -128,13 +137,13 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.log('\n# Server\n'); this.prompt([{ - type: "confirm", - name: "mongoose", - message: "Would you like to use mongoDB with Mongoose for data modeling?" + type: 'confirm', + name: 'mongoose', + message: 'Would you like to use mongoDB with Mongoose for data modeling?' }, { - type: "confirm", - name: "auth", - message: "Would you scaffold out an authentication boilerplate?", + type: 'confirm', + name: 'auth', + message: 'Would you scaffold out an authentication boilerplate?', when: function (answers) { return answers.mongoose; } @@ -163,9 +172,9 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ } ] }, { - type: "confirm", - name: "socketio", - message: "Would you like to use socket.io?", + type: 'confirm', + name: 'socketio', + message: 'Would you like to use socket.io?', // to-do: should not be dependent on mongoose when: function (answers) { return answers.mongoose; @@ -186,6 +195,47 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }.bind(this)); }, + projectPrompts: function() { + if(this.skipConfig) return; + var cb = this.async(); + var self = this; + + this.log('\n# Project\n'); + + this.prompt([{ + type: 'list', + name: 'testing', + message: 'What would you like to write tests with?', + choices: [ 'Jasmine', 'Mocha + Chai + Sinon'], + filter: function( val ) { + var filterMap = { + 'Jasmine': 'jasmine', + 'Mocha + Chai + Sinon': 'mocha' + }; + + return filterMap[val]; + } + }, { + type: 'list', + name: 'chai', + message: 'What would you like to write Chai assertions with?', + choices: ['Expect', 'Should'], + filter: function( val ) { + return val.toLowerCase(); + }, + when: function( answers ) { + return answers.testing === 'mocha'; + } + }], function (answers) { + this.filters[answers.testing] = true; + if (this.filters.mocha) { + this.filters[answers.chai] = true; + } + + cb(); + }.bind(this)); + }, + saveSettings: function() { if(this.skipConfig) return; this.config.set('insertRoutes', true); @@ -207,10 +257,15 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ if(this.skipConfig) return; var appPath = 'client/app/'; var extensions = []; - var filters = []; + var filters = [ + 'ngroute', + 'uirouter', + 'jasmine', + 'mocha', + 'expect', + 'should' + ].filter(function(v) {return this.filters[v];}, this); - if(this.filters.ngroute) filters.push('ngroute'); - if(this.filters.uirouter) filters.push('uirouter'); if(this.filters.coffee) extensions.push('coffee'); if(this.filters.js) extensions.push('js'); if(this.filters.html) extensions.push('html'); @@ -249,7 +304,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ if(this.filters.uirouter) angModules.push("'ui.router'"); if(this.filters.uibootstrap) angModules.push("'ui.bootstrap'"); - this.angularModules = "\n " + angModules.join(",\n ") +"\n"; + this.angularModules = '\n ' + angModules.join(',\n ') +'\n'; }, generate: function() { diff --git a/app/templates/_package.json b/app/templates/_package.json index 1912903fa..08784aa6c 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -31,7 +31,6 @@ "socketio-jwt": "^2.0.2"<% } %> }, "devDependencies": { - "chai-as-promised": "^4.1.1", "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-wiredep": "~1.8.0", @@ -62,9 +61,7 @@ "grunt-protractor-runner": "^1.1.0", "grunt-asset-injector": "^0.1.0", "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control", - "grunt-mocha-test": "~0.10.2", - "grunt-mocha-istanbul": "^2.0.0",<% if(filters.sass) { %> + "grunt-build-control": "DaftMonk/grunt-build-control",<% if(filters.sass) { %> "grunt-contrib-sass": "^0.7.3",<% } %><% if(filters.stylus) { %> "grunt-contrib-stylus": "latest",<% } %> "jit-grunt": "^0.5.0", @@ -74,12 +71,19 @@ "open": "~0.0.4", "jshint-stylish": "~0.1.5", "connect-livereload": "~0.4.0", + "grunt-mocha-test": "~0.10.2", + "grunt-mocha-istanbul": "^2.0.0", + "chai-as-promised": "^4.1.1", + "chai-things": "^0.2.0", + "sinon-chai": "^2.5.0",<% if(filters.mocha) { %> + "karma-mocha": "^0.1.9", + "karma-chai-plugins": "^0.2.3",<% } if(filters.jasmine) { %> + "karma-jasmine": "~0.1.5",<% } %> "karma-ng-scenario": "~0.1.0", "karma-firefox-launcher": "~0.1.3", "karma-script-launcher": "~0.1.0", "karma-html2js-preprocessor": "~0.1.0", "karma-ng-jade2js-preprocessor": "^0.1.2", - "karma-jasmine": "~0.1.5", "karma-chrome-launcher": "~0.1.3", "requirejs": "~2.1.11", "karma-requirejs": "~0.2.1", @@ -88,9 +92,9 @@ "karma-phantomjs-launcher": "~0.1.4", "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", + "karma-spec-reporter": "0.0.13", "proxyquire": "^1.0.1", - "supertest": "~0.11.0", - "sinon-chai": "^2.5.0" + "supertest": "~0.11.0" }, "engines": { "node": ">=0.10.0" diff --git a/app/templates/client/app/main/main.controller.spec(coffee).coffee b/app/templates/client/app/main/main.controller.spec(coffee).coffee index f974a081d..5bdf4f840 100644 --- a/app/templates/client/app/main/main.controller.spec(coffee).coffee +++ b/app/templates/client/app/main/main.controller.spec(coffee).coffee @@ -27,5 +27,6 @@ describe 'Controller: MainCtrl', -> $scope: scope it 'should attach a list of things to the scope', -> - $httpBackend.flush() - expect(scope.awesomeThings.length).toBe 4 + $httpBackend.flush()<% if (filters.jasmine) { %> + expect(scope.awesomeThings.length).toBe 4 <% } if (filters.mocha) { %> + <%= does("scope.awesomeThings.length") %>.equal 4<% } %> diff --git a/app/templates/client/app/main/main.controller.spec(js).js b/app/templates/client/app/main/main.controller.spec(js).js index 21b8aba70..dc048b4af 100644 --- a/app/templates/client/app/main/main.controller.spec(js).js +++ b/app/templates/client/app/main/main.controller.spec(js).js @@ -26,7 +26,8 @@ describe('Controller: MainCtrl', function () { })); it('should attach a list of things to the scope', function () { - $httpBackend.flush(); - expect(scope.awesomeThings.length).toBe(4); + $httpBackend.flush();<% if (filters.jasmine) { %> + expect(scope.awesomeThings.length).toBe(4);<% } if (filters.mocha) { %> + <%= does("scope.awesomeThings.length") %>.equal(4);<% } %> }); }); diff --git a/app/templates/e2e/account(auth)/login/login.spec.js b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js similarity index 100% rename from app/templates/e2e/account(auth)/login/login.spec.js rename to app/templates/e2e/account(auth)/login/login.spec(jasmine).js diff --git a/app/templates/e2e/account(auth)/login/login.spec(mocha).js b/app/templates/e2e/account(auth)/login/login.spec(mocha).js new file mode 100644 index 000000000..a2c986f32 --- /dev/null +++ b/app/templates/e2e/account(auth)/login/login.spec(mocha).js @@ -0,0 +1,73 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Login View', function() { + var page; + + var loadPage = function() { + browser.get('/login'); + page = require('./login.po'); + }; + + var testUser = { + name: 'Test User', + email: 'test@test.com', + password: 'test' + }; + + before(function() { + return UserModel + .removeAsync() + .then(function() { + return UserModel.createAsync(testUser); + }) + .then(loadPage); + }); + + after(function() { + return UserModel.removeAsync(); + }); + + it('should include login form with correct inputs and submit button', function() { + <%= does("page.form.email.getAttribute('type')") %>.eventually.equal('email'); + <%= does("page.form.email.getAttribute('name')") %>.eventually.equal('email'); + <%= does("page.form.password.getAttribute('type')") %>.eventually.equal('password'); + <%= does("page.form.password.getAttribute('name')") %>.eventually.equal('password'); + <%= does("page.form.submit.getAttribute('type')") %>.eventually.equal('submit'); + <%= does("page.form.submit.getText()") %>.eventually.equal('Login'); + }); + + describe('with local auth', function() { + + it('should login a user and redirecting to "/"', function() { + page.login(testUser); + + var navbar = require('../../components/navbar/navbar.po'); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/'); + <%= does("navbar.navbarAccountGreeting.getText()") %>.eventually.equal('Hello ' + testUser.name); + }); + + describe('and invalid credentials', function() { + before(function() { + return loadPage(); + }) + + it('should indicate login failures', function() { + page.login({ + email: testUser.email, + password: 'badPassword' + }); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/login'); + + var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding')); + <%= does("helpBlock.getText()") %>.eventually.equal('This password is not correct.'); + }); + + }); + + }); +}); diff --git a/app/templates/e2e/account(auth)/logout/logout.spec.js b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js similarity index 100% rename from app/templates/e2e/account(auth)/logout/logout.spec.js rename to app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js new file mode 100644 index 000000000..3adba51f8 --- /dev/null +++ b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js @@ -0,0 +1,50 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Logout View', function() { + var login = function(user) { + browser.get('/login'); + require('../login/login.po').login(user); + }; + + var testUser = { + name: 'Test User', + email: 'test@test.com', + password: 'test' + }; + + beforeEach(function() { + return UserModel + .removeAsync() + .then(function() { + return UserModel.createAsync(testUser); + }) + .then(function() { + return login(testUser); + }); + }); + + after(function() { + return UserModel.removeAsync(); + }) + + describe('with local auth', function() { + + it('should logout a user and redirecting to "/"', function() { + var navbar = require('../../components/navbar/navbar.po'); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/'); + <%= does("navbar.navbarAccountGreeting.getText()") %>.eventually.equal('Hello ' + testUser.name); + + browser.get('/logout'); + + navbar = require('../../components/navbar/navbar.po'); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/'); + <%= does("navbar.navbarAccountGreeting.isDisplayed()") %>.eventually.equal(false); + }); + + }); +}); diff --git a/app/templates/e2e/account(auth)/signup/signup.spec.js b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js similarity index 100% rename from app/templates/e2e/account(auth)/signup/signup.spec.js rename to app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js new file mode 100644 index 000000000..6a6b0a775 --- /dev/null +++ b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js @@ -0,0 +1,72 @@ +'use strict'; + +var config = protractor.getInstance().params; +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); + +describe('Signup View', function() { + var page; + + var loadPage = function() { + browser.get('/signup'); + page = require('./signup.po'); + }; + + var testUser = { + name: 'Test', + email: 'test@test.com', + password: 'test' + }; + + before(function() { + return loadPage(); + }); + + after(function() { + return UserModel.removeAsync(); + }); + + it('should include signup form with correct inputs and submit button', function() { + <%= does("page.form.name.getAttribute('type')") %>.eventually.equal('text'); + <%= does("page.form.name.getAttribute('name')") %>.eventually.equal('name'); + <%= does("page.form.email.getAttribute('type')") %>.eventually.equal('email'); + <%= does("page.form.email.getAttribute('name')") %>.eventually.equal('email'); + <%= does("page.form.password.getAttribute('type')") %>.eventually.equal('password'); + <%= does("page.form.password.getAttribute('name')") %>.eventually.equal('password'); + <%= does("page.form.submit.getAttribute('type')") %>.eventually.equal('submit'); + <%= does("page.form.submit.getText()") %>.eventually.equal('Sign up'); + }); + + describe('with local auth', function() { + + it('should signup a new user, log them in, and redirecting to "/"', function(done) { + UserModel.remove(function() { + page.signup(testUser); + + var navbar = require('../../components/navbar/navbar.po'); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/'); + <%= does("navbar.navbarAccountGreeting.getText()") %>.eventually.equal('Hello ' + testUser.name); + + done(); + }); + }); + + describe('and invalid credentials', function() { + before(function() { + return loadPage(); + }); + + it('should indicate signup failures', function() { + page.signup(testUser); + + <%= does("browser.getLocationAbsUrl()") %>.eventually.equal(config.baseUrl + '/signup'); + <%= does("page.form.email.getAttribute('class')") %>.eventually.contain('ng-invalid-mongoose'); + + var helpBlock = page.form.element(by.css('.form-group.has-error .help-block.ng-binding')); + <%= does("helpBlock.getText()") %>.eventually.equal('The specified email address is already in use.'); + }); + + }); + + }); +}); diff --git a/app/templates/e2e/main/main.spec.js b/app/templates/e2e/main/main.spec(jasmine).js similarity index 100% rename from app/templates/e2e/main/main.spec.js rename to app/templates/e2e/main/main.spec(jasmine).js diff --git a/app/templates/e2e/main/main.spec(mocha).js b/app/templates/e2e/main/main.spec(mocha).js new file mode 100644 index 000000000..1962ba765 --- /dev/null +++ b/app/templates/e2e/main/main.spec(mocha).js @@ -0,0 +1,16 @@ +'use strict'; + +describe('Main View', function() { + var page; + + beforeEach(function() { + browser.get('/'); + page = require('./main.po'); + }); + + it('should include jumbotron with correct data', function() { + <%= does("page.h1El.getText()") %>.eventually.equal('\'Allo, \'Allo!'); + <%= does("page.imgEl.getAttribute('src')") %>.eventually.match(/assets\/images\/yeoman.png$/); + <%= does("page.imgEl.getAttribute('alt')") %>.eventually.equal('I\'m Yeoman'); + }); +}); diff --git a/app/templates/karma.conf.js b/app/templates/karma.conf.js index 57b3fa6f2..6b6c6c477 100644 --- a/app/templates/karma.conf.js +++ b/app/templates/karma.conf.js @@ -6,8 +6,9 @@ module.exports = function(config) { // base path, that will be used to resolve files and exclude basePath: '', - // testing framework to use (jasmine/mocha/qunit/...) - frameworks: ['jasmine'], + // testing framework to use (jasmine/mocha/qunit/...)<% if(filters.jasmine) { %> + frameworks: ['jasmine'],<% } if(filters.mocha) { %> + frameworks: ['mocha', 'chai', 'sinon-chai', 'chai-as-promised', 'chai-things'],<% } %> // list of files / patterns to load in the browser files: [ @@ -58,6 +59,14 @@ module.exports = function(config) { // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG logLevel: config.LOG_INFO, + // reporter types: + // - dots + // - progress (default) + // - spec (karma-spec-reporter) + // - junit + // - growl + // - coverage + reporters: ['spec'], // enable / disable watching file and executing tests whenever any file changes autoWatch: false, diff --git a/app/templates/mocha.conf.js b/app/templates/mocha.conf.js index 497d43b2c..54e33bb6f 100644 --- a/app/templates/mocha.conf.js +++ b/app/templates/mocha.conf.js @@ -1,14 +1,16 @@ 'use strict'; var chai = require('chai'); -var sinon = require('sinon'); -var sinonChai = require('sinon-chai'); -var chaiAsPromised = require('chai-as-promised'); +// Load Chai assertions global.expect = chai.expect; global.assert = chai.assert; -global.sinon = sinon; - chai.should(); -chai.use(sinonChai); -chai.use(chaiAsPromised); + +// Load Sinon +global.sinon = require('sinon'); + +// Initialize Chai plugins +chai.use(require('sinon-chai')); +chai.use(require('chai-as-promised')); +chai.use(require('chai-things')) diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index 18b9ba6af..14f704b3d 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -43,24 +43,40 @@ var config = { // Jasmine and Cucumber are fully supported as a test and assertion framework. // Mocha has limited beta support. You will need to include your own // assertion framework if working with mocha. - framework: 'jasmine', - + framework: '<% if(filters.jasmine) { %>jasmine<% } if(filters.mocha) { %>mocha<% } %>', +<% if(filters.jasmine) { %> // ----- Options to be passed to minijasminenode ----- // // See the full list at https://github.com/juliemr/minijasminenode jasmineNodeOpts: { defaultTimeoutInterval: 30000 - }, + },<% } if(filters.mocha) { %> + // ----- Options to be passed to mocha ----- + mochaOpts: { + reporter: 'spec', + timeout: 30000, + defaultTimeoutInterval: 30000 + },<% } %> // Prepare environment for tests params: { serverConfig: require('./server/config/environment') }, - onPrepare: function() { + onPrepare: function() {<% if(filters.mocha) { %> + // Load Mocha and Chai + plugins + require('./mocha.conf'); + + // Expose should assertions (see https://github.com/angular/protractor/issues/633) + Object.defineProperty( + protractor.promise.Promise.prototype, + 'should', + Object.getOwnPropertyDescriptor(Object.prototype, 'should') + ); +<% } %> var serverConfig = config.params.serverConfig; - // Setup mongo tests + // Setup mongo for tests var mongoose = require('mongoose-bird')(); mongoose.connect(serverConfig.mongo.uri, serverConfig.mongo.options); // Connect to database } diff --git a/script-base.js b/script-base.js index 2f44ce09f..5d6c7dd2e 100644 --- a/script-base.js +++ b/script-base.js @@ -18,8 +18,17 @@ var Generator = module.exports = function Generator() { this.cameledName = this._.camelize(this.name); this.classedName = this._.classify(this.name); + // dynamic assertion statement + this.does = this.is = function(foo) { + if (this.filters.should) { + return foo + '.should'; + } else { + return 'expect(' + foo + ').to'; + } + }.bind(this); + this.filters = this.config.get('filters'); this.sourceRoot(path.join(__dirname, '/templates')); }; -util.inherits(Generator, yeoman.generators.NamedBase); \ No newline at end of file +util.inherits(Generator, yeoman.generators.NamedBase); diff --git a/test/fixtures/bower.json b/test/fixtures/bower.json deleted file mode 100644 index 7d9aae354..000000000 --- a/test/fixtures/bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "tempApp", - "version": "0.0.0", - "dependencies": { - "angular": ">=1.2.*", - "json3": "~3.3.1", - "es5-shim": "~3.0.1", - "jquery": "~1.11.0", - "bootstrap-sass-official": "~3.1.1", - "bootstrap": "~3.1.1", - "angular-resource": ">=1.2.*", - "angular-cookies": ">=1.2.*", - "angular-sanitize": ">=1.2.*", - "angular-route": ">=1.2.*", - "angular-bootstrap": "~0.11.0", - "font-awesome": ">=4.1.0", - "lodash": "~2.4.1", - "angular-socket-io": "~0.6.0", - "angular-ui-router": "~0.2.10" - }, - "devDependencies": { - "angular-mocks": ">=1.2.*", - "angular-scenario": ">=1.2.*" - } -} diff --git a/test/fixtures/package.json b/test/fixtures/package.json deleted file mode 100644 index 48d48607e..000000000 --- a/test/fixtures/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "tempApp", - "version": "0.0.0", - "main": "server/app.js", - "dependencies": { - "express": "~4.0.0", - "morgan": "~1.0.0", - "body-parser": "~1.5.0", - "method-override": "~1.0.0", - "serve-favicon": "~2.0.1", - "cookie-parser": "~1.0.1", - "express-session": "~1.0.2", - "errorhandler": "~1.0.0", - "compression": "~1.0.1", - "lodash": "~2.4.1", - "jade": "~1.2.0", - "ejs": "~0.8.4", - "mongoose": "~3.8.8", - "mongoose-bird": "~0.0.1", - "jsonwebtoken": "^0.3.0", - "express-jwt": "^0.1.3", - "passport": "~0.2.0", - "passport-local": "~0.1.6", - "passport-facebook": "latest", - "passport-twitter": "latest", - "passport-google-oauth": "latest", - "composable-middleware": "^0.3.0", - "connect-mongo": "^0.4.1", - "socket.io": "^1.0.6", - "socket.io-client": "^1.0.6", - "socketio-jwt": "^2.0.2" - }, - "devDependencies": { - "chai-as-promised": "^4.1.1", - "grunt": "~0.4.4", - "grunt-autoprefixer": "~0.7.2", - "grunt-wiredep": "~1.8.0", - "grunt-concurrent": "~0.5.0", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-concat": "~0.4.0", - "grunt-contrib-copy": "~0.5.0", - "grunt-contrib-cssmin": "~0.9.0", - "grunt-contrib-htmlmin": "~0.2.0", - "grunt-contrib-imagemin": "~0.7.1", - "grunt-contrib-jshint": "~0.10.0", - "grunt-contrib-uglify": "~0.4.0", - "grunt-contrib-watch": "~0.6.1", - "grunt-contrib-coffee": "^0.10.1", - "grunt-contrib-jade": "^0.11.0", - "grunt-contrib-less": "^0.11.4", - "grunt-google-cdn": "~0.4.0", - "grunt-newer": "~0.7.0", - "grunt-ng-annotate": "^0.2.3", - "grunt-rev": "~0.1.0", - "grunt-svgmin": "~0.4.0", - "grunt-usemin": "~2.1.1", - "grunt-env": "~0.4.1", - "grunt-node-inspector": "~0.1.5", - "grunt-nodemon": "~0.2.0", - "grunt-angular-templates": "^0.5.4", - "grunt-dom-munger": "^3.4.0", - "grunt-protractor-runner": "^1.1.0", - "grunt-asset-injector": "^0.1.0", - "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control", - "grunt-mocha-test": "~0.10.2", - "grunt-mocha-istanbul": "^2.0.0", - "grunt-contrib-sass": "^0.7.3", - "grunt-contrib-stylus": "latest", - "jit-grunt": "^0.5.0", - "time-grunt": "~0.3.1", - "grunt-express-server": "~0.4.17", - "grunt-open": "~0.2.3", - "open": "~0.0.4", - "jshint-stylish": "~0.1.5", - "connect-livereload": "~0.4.0", - "karma-ng-scenario": "~0.1.0", - "karma-firefox-launcher": "~0.1.3", - "karma-script-launcher": "~0.1.0", - "karma-html2js-preprocessor": "~0.1.0", - "karma-ng-jade2js-preprocessor": "^0.1.2", - "karma-jasmine": "~0.1.5", - "karma-chrome-launcher": "~0.1.3", - "requirejs": "~2.1.11", - "karma-requirejs": "~0.2.1", - "karma-coffee-preprocessor": "~0.2.1", - "karma-jade-preprocessor": "0.0.11", - "karma-phantomjs-launcher": "~0.1.4", - "karma": "~0.12.9", - "karma-ng-html2js-preprocessor": "~0.1.0", - "proxyquire": "^1.0.1", - "supertest": "~0.11.0", - "sinon-chai": "^2.5.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "start": "node server/app.js", - "test": "grunt test", - "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update" - }, - "private": true -} diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 31ed71ab2..7db1d4afe 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -14,6 +14,8 @@ describe('angular-fullstack generator', function () { markup: 'html', stylesheet: 'sass', router: 'uirouter', + testing: 'mocha', + chai: 'expect', bootstrap: true, uibootstrap: true, mongoose: true, @@ -35,9 +37,18 @@ describe('angular-fullstack generator', function () { }); } + /** + * Assert that only an array of files exist at a given path + * + * @param {Array} expectedFiles - array of files + * @param {Function} done - callback(error{Error}) + * @param {String} path - top level path to assert files at (optional) + * @param {Array} skip - array of paths to skip/ignore (optional) + * + */ function assertOnlyFiles(expectedFiles, done, path, skip) { path = path || './'; - skip = skip || ['e2e', 'node_modules', 'client/bower_components']; + skip = skip || ['node_modules', 'client/bower_components']; recursiveReadDir(path, skip, function(err, actualFiles) { if (err) { return done(err); } @@ -61,16 +72,16 @@ describe('angular-fullstack generator', function () { }); } - function runE2E(self, done) { - self.timeout(240000); // 4 minutes - gen.run({}, function () { - exec('grunt test:e2e', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout).to.contain('0 failures'); - done(); - }); - }); - }; - + /** + * Exec a command and run test assertion(s) based on command type + * + * @param {String} cmd - the command to exec + * @param {Object} self - context of the test + * @param {Function} cb - callback() + * @param {String} endpoint - endpoint to generate before exec (optional) + * @param {Number} timeout - timeout for the exec and test (optional) + * + */ function runTest(cmd, self, cb) { var args = Array.prototype.slice.call(arguments), endpoint = (args[3] && typeof args[3] === 'string') ? args.splice(3, 1)[0] : null, @@ -81,15 +92,14 @@ describe('angular-fullstack generator', function () { var execFn = function() { exec(cmd, function(error, stdout, stderr) { switch(cmd) { - case 'grunt test:client': - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1\u001b[32m SUCCESS\u001b'); - break; case 'grunt jshint': - expect(stdout).to.contain('Done, without errors.'); - break; case 'grunt jscs': expect(stdout).to.contain('Done, without errors.'); break; + case 'grunt test:client': + case 'grunt test:e2e': + expect(stdout, 'Client tests failed \n' + stdout).to.contain('Done, without errors.'); + break; case 'grunt test:server': expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); break; @@ -108,6 +118,13 @@ describe('angular-fullstack generator', function () { } } + /** + * Generate an array of files to expect from a set of options + * + * @param {Object} ops - generator options + * @return {Array} - array of files + * + */ function genFiles(ops) { var mapping = { stylesheet: { @@ -127,6 +144,13 @@ describe('angular-fullstack generator', function () { }, files = []; + /** + * Generate an array of OAuth files based on type + * + * @param {String} type - type of oauth + * @return {Array} - array of files + * + */ var oauthFiles = function(type) { return [ 'server/auth/' + type + '/index.js', @@ -139,6 +163,7 @@ describe('angular-fullstack generator', function () { markup = mapping.markup[ops.markup], stylesheet = mapping.stylesheet[ops.stylesheet]; + /* Core Files */ files = files.concat([ 'client/.htaccess', 'client/.jshintrc', @@ -172,6 +197,9 @@ describe('angular-fullstack generator', function () { 'server/config/environment/production.js', 'server/config/environment/test.js', 'server/views/404.' + markup, + 'e2e/main/main.po.js', + 'e2e/main/main.spec.js', + 'e2e/components/navbar/navbar.po.js', '.bowerrc', '.buildignore', '.editorconfig', @@ -187,12 +215,14 @@ describe('angular-fullstack generator', function () { 'protractor.conf.js' ]); + /* Ui-Router */ if (ops.router === 'uirouter') { files = files.concat([ 'client/components/ui-router/ui-router.mock.' + script ]); } + /* Ui-Bootstrap */ if (ops.uibootstrap) { files = files.concat([ 'client/components/modal/modal.' + markup, @@ -201,6 +231,7 @@ describe('angular-fullstack generator', function () { ]); } + /* Mongoose */ if (ops.mongoose) { files = files.concat([ 'server/api/thing/thing.model.js', @@ -208,6 +239,7 @@ describe('angular-fullstack generator', function () { ]); } + /* Authentication */ if (ops.auth) { files = files.concat([ 'client/app/account/account.' + script, @@ -234,16 +266,23 @@ describe('angular-fullstack generator', function () { 'server/auth/index.js', 'server/auth/auth.service.js', 'server/auth/local/index.js', - 'server/auth/local/passport.js' + 'server/auth/local/passport.js', + 'e2e/account/login/login.po.js', + 'e2e/account/login/login.spec.js', + 'e2e/account/logout/logout.spec.js', + 'e2e/account/signup/signup.po.js', + 'e2e/account/signup/signup.spec.js' ]); } + /* OAuth (see oauthFiles function above) */ if (ops.oauth) { ops.oauth.forEach(function(type, i) { files = files.concat(oauthFiles(type.replace('Auth', ''))); }); } + /* Socket.IO */ if (ops.socketio) { files = files.concat([ 'client/components/socket/socket.service.' + script, @@ -361,7 +400,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(this, done); + runTest('grunt test:e2e', this, done, 240000); }); }); @@ -371,6 +410,7 @@ describe('angular-fullstack generator', function () { markup: 'jade', stylesheet: 'less', router: 'uirouter', + testing: 'jasmine', mongoose: true, auth: true, oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], @@ -417,7 +457,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(this, done); + runTest('grunt test:e2e', this, done, 240000); }); }); @@ -427,6 +467,8 @@ describe('angular-fullstack generator', function () { markup: 'jade', stylesheet: 'stylus', router: 'ngroute', + testing: 'mocha', + chai: 'should', mongoose: false, auth: false, oauth: [], @@ -474,7 +516,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(this, done); + runTest('grunt test:e2e', this, done, 240000); }); }); @@ -484,6 +526,7 @@ describe('angular-fullstack generator', function () { markup: 'html', stylesheet: 'css', router: 'ngroute', + testing: 'jasmine', mongoose: false, auth: false, oauth: [], @@ -523,7 +566,7 @@ describe('angular-fullstack generator', function () { }); it('should run e2e tests successfully', function(done) { - runE2E(this, done); + runTest('grunt test:e2e', this, done, 240000); }); }); }); From 696c6fb9336e3319083dd7a684da541996b22db7 Mon Sep 17 00:00:00 2001 From: BenFradet Date: Sat, 27 Sep 2014 17:16:18 +0200 Subject: [PATCH 042/201] docs(gen:endpoint): standardized comments --- endpoint/templates/name.controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 2afb2be8c..87dd641de 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -50,7 +50,7 @@ function removeEntity(res){ }; }<% } %> -// Get list of <%= name %>s +// Gets list of <%= name %>s from the DB. exports.index = function(req, res) {<% if (!filters.mongoose) { %> res.json([]);<% } if (filters.mongoose) { %> <%= classedName %>.findAsync() @@ -58,7 +58,7 @@ exports.index = function(req, res) {<% if (!filters.mongoose) { %> .catch(handleError(res));<% } %> };<% if (filters.mongoose) { %> -// Get a single <%= name %> +// Gets a single <%= name %> from the DB. exports.show = function(req, res) { <%= classedName %>.findByIdAsync(req.params.id) .then(handleEntityNotFound(res)) From a29b71310239b2ef6a7e39ea077781abb78e582f Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 27 Sep 2014 23:52:15 -0600 Subject: [PATCH 043/201] remove sauce connect addon from travis and replace with shell script --- .travis.yml | 5 ++- scripts/sauce_connect_setup.sh | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) create mode 100755 scripts/sauce_connect_setup.sh diff --git a/.travis.yml b/.travis.yml index e1abfbd26..598a4b2ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,9 @@ env: global: - SAUCE_USERNAME=fullstack_ci - SAUCE_ACCESS_KEY=1a527ca6-4aa5-4618-86ce-0278bf158cbf -addons: - sauce_connect: true before_install: + - ./scripts/sauce_connect_setup.sh - gem update --system - gem install sass --version "=3.3.7" - npm install -g bower grunt-cli -services: mongodb +services: mongodb \ No newline at end of file diff --git a/scripts/sauce_connect_setup.sh b/scripts/sauce_connect_setup.sh new file mode 100755 index 000000000..06b6e2092 --- /dev/null +++ b/scripts/sauce_connect_setup.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Setup and start Sauce Connect for your TravisCI build +# This script requires your .travis.yml to include the following two private env variables: +# SAUCE_USERNAME +# SAUCE_ACCESS_KEY +# Follow the steps at https://saucelabs.com/opensource/travis to set that up. +# https://gist.githubusercontent.com/santiycr/4683e262467c0a84d857/raw/1254ace59257e341ab200cbc8946e626756f079f/sauce-connect.sh + +if [ -z "${SAUCE_USERNAME}" ] || [ -z "${SAUCE_ACCESS_KEY}" ]; then + echo "This script can't run without your Sauce credentials" + echo "Please set SAUCE_USERNAME and SAUCE_ACCESS_KEY env variables" + echo "export SAUCE_USERNAME=ur-username" + echo "export SAUCE_ACCESS_KEY=ur-access-key" + exit 1 +fi + +SAUCE_TMP_DIR="$(mktemp -d -t sc.XXXX)" +echo "Using temp dir $SAUCE_TMP_DIR" +pushd $SAUCE_TMP_DIR + +SAUCE_CONNECT_PLATFORM=$(uname | sed -e 's/Darwin/osx/' -e 's/Linux/linux/') +case "${SAUCE_CONNECT_PLATFORM}" in + linux) + SC_DISTRIBUTION_FMT=tar.gz;; + *) + SC_DISTRIBUTION_FMT=zip;; +esac +SC_DISTRIBUTION=sc-latest-${SAUCE_CONNECT_PLATFORM}.${SC_DISTRIBUTION_FMT} +SC_READYFILE=sauce-connect-ready-$RANDOM +SC_LOGFILE=$HOME/sauce-connect.log +if [ ! -z "${TRAVIS_JOB_NUMBER}" ]; then + SC_TUNNEL_ID="-i ${TRAVIS_JOB_NUMBER}" +fi +echo "Downloading Sauce Connect" +wget https://saucelabs.com/downloads/${SC_DISTRIBUTION} +SC_DIR=$(tar -ztf ${SC_DISTRIBUTION} | head -n1) + +echo "Extracting Sauce Connect" +case "${SC_DISTRIBUTION_FMT}" in + tar.gz) + tar zxf $SC_DISTRIBUTION;; + zip) + unzip $SC_DISTRIBUTION;; +esac + +echo "Starting Sauce Connect" +${SC_DIR}/bin/sc \ + ${SC_TUNNEL_ID} \ + -f ${SC_READYFILE} \ + -l ${SC_LOGFILE} & + +echo "Waiting for Sauce Connect readyfile" +while [ ! -f ${SC_READYFILE} ]; do + sleep .5 +done + +unset SAUCE_CONNECT_PLATFORM SAUCE_TMP_DIR SC_DIR SC_DISTRIBUTION SC_READYFILE SC_LOGFILE SC_TUNNEL_ID + +popd \ No newline at end of file From 8a1a245f212c24604fc78ba8442a87af31586537 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 21 Sep 2014 22:11:35 -0600 Subject: [PATCH 044/201] feat(app): add grunt jscs task for maintaining consistent code style --- app/templates/.jscs.json | 3 +++ app/templates/Gruntfile.js | 15 +++++++++++++++ app/templates/_package.json | 1 + 3 files changed, 19 insertions(+) create mode 100644 app/templates/.jscs.json diff --git a/app/templates/.jscs.json b/app/templates/.jscs.json new file mode 100644 index 000000000..dc46a2f34 --- /dev/null +++ b/app/templates/.jscs.json @@ -0,0 +1,3 @@ +{ + "preset": "google" +} \ No newline at end of file diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 6cd422daa..3e2da06c8 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -192,6 +192,21 @@ module.exports = function (grunt) { } }, + jscs: { + options: { + config: ".jscs.json" + }, + main: { + files: { + src: [ + '<%%= yeoman.client %>/app/**/*.js', + '<%%= yeoman.client %>/app/**/*.js', + 'server/**/*.js' + ] + } + } + }, + // Empties folders to start fresh clean: { dist: { diff --git a/app/templates/_package.json b/app/templates/_package.json index 08784aa6c..3775d0d90 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -48,6 +48,7 @@ "grunt-contrib-jade": "^0.11.0",<% } %><% if(filters.less) { %> "grunt-contrib-less": "^0.11.4",<% } %> "grunt-google-cdn": "~0.4.0", + "grunt-jscs": "~0.7.1", "grunt-newer": "~0.7.0", "grunt-ng-annotate": "^0.2.3", "grunt-rev": "~0.1.0", From 18c4c31d3c8c35690810966e0e27b22f74c26a13 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sat, 27 Sep 2014 01:41:39 -0600 Subject: [PATCH 045/201] style(app): update style to match jscs style guide --- app/templates/.jscs.json | 11 ++- app/templates/Gruntfile.js | 86 +++++++++---------- app/templates/_.gitignore | 2 +- app/templates/_bower.json | 10 +-- app/templates/_package.json | 30 +++---- .../app/account(auth)/account(coffee).coffee | 4 +- .../client/app/account(auth)/account(js).js | 4 +- .../app/account(auth)/login/login(html).html | 10 +-- .../app/account(auth)/login/login(jade).jade | 10 +-- .../app/account(auth)/login/login(less).less | 2 +- .../app/account(auth)/login/login(sass).scss | 2 +- .../login/login.controller(coffee).coffee | 6 +- .../login/login.controller(js).js | 12 +-- .../settings/settings.controller(js).js | 24 +++--- .../account(auth)/signup/signup(html).html | 10 +-- .../account(auth)/signup/signup(jade).jade | 10 +-- .../signup/signup.controller(coffee).coffee | 6 +- .../signup/signup.controller(js).js | 12 +-- .../app/admin(auth)/admin(coffee).coffee | 4 +- .../client/app/admin(auth)/admin(js).js | 6 +- .../app/admin(auth)/admin.controller(js).js | 2 +- app/templates/client/app/app(coffee).coffee | 22 ++--- app/templates/client/app/app(css).css | 4 +- app/templates/client/app/app(js).js | 26 +++--- app/templates/client/app/app(less).less | 6 +- app/templates/client/app/app(sass).scss | 6 +- app/templates/client/app/app(stylus).styl | 4 +- .../client/app/main/main(coffee).coffee | 4 +- app/templates/client/app/main/main(html).html | 4 +- app/templates/client/app/main/main(jade).jade | 4 +- app/templates/client/app/main/main(js).js | 6 +- .../app/main/main.controller(coffee).coffee | 8 +- .../client/app/main/main.controller(js).js | 12 +-- .../main/main.controller.spec(coffee).coffee | 10 +-- .../app/main/main.controller.spec(js).js | 20 ++--- .../components/navbar/navbar(html).html | 18 ++-- .../components/navbar/navbar(jade).jade | 22 ++--- .../navbar/navbar.controller(coffee).coffee | 6 +- .../navbar/navbar.controller(js).js | 6 +- app/templates/client/index.html | 4 +- .../e2e/components/navbar/navbar.po.js | 2 +- app/templates/karma.conf.js | 10 +-- app/templates/protractor.conf.js | 8 +- app/templates/server/api/thing/index.js | 2 +- app/templates/server/api/thing/index.spec.js | 30 +++++-- .../server/api/thing/thing.controller.js | 73 ++++++++-------- .../server/api/thing/thing.integration.js | 28 ++++-- .../server/api/thing/thing.model(mongoose).js | 4 +- .../api/thing/thing.socket(socketio).js | 4 +- .../server/api/user(auth)/index.spec.js | 24 ++++-- .../server/api/user(auth)/user.controller.js | 32 ++++--- .../server/api/user(auth)/user.integration.js | 4 +- .../server/api/user(auth)/user.model.js | 72 ++++++++++------ .../server/api/user(auth)/user.model.spec.js | 4 +- app/templates/server/app.js | 4 +- .../server/auth(auth)/auth.service.js | 21 +++-- .../facebook(facebookAuth)/index.js | 2 +- .../facebook(facebookAuth)/passport.js | 63 +++++++------- .../auth(auth)/google(googleAuth)/index.js | 2 +- .../auth(auth)/google(googleAuth)/passport.js | 55 ++++++------ app/templates/server/auth(auth)/index.js | 2 +- .../server/auth(auth)/local/index.js | 16 ++-- .../server/auth(auth)/local/passport.js | 48 ++++++----- .../auth(auth)/twitter(twitterAuth)/index.js | 2 +- .../twitter(twitterAuth)/passport.js | 11 +-- .../server/components/errors/index.js | 6 +- app/templates/server/config/_local.env.js | 2 +- .../server/config/environment/index.js | 10 +-- .../server/config/environment/production.js | 5 +- .../server/config/environment/test.js | 2 +- app/templates/server/config/express.js | 6 +- app/templates/server/config/seed(mongoose).js | 40 +++++---- .../server/config/socketio(socketio).js | 17 ++-- app/templates/server/routes.js | 6 +- endpoint/templates/index.js | 2 +- endpoint/templates/index.spec.js | 24 ++++-- endpoint/templates/name.controller.js | 36 ++++---- endpoint/templates/name.integration.js | 24 ++++-- endpoint/templates/name.model(mongoose).js | 4 +- endpoint/templates/name.socket(socketio).js | 6 +- test/test-file-creation.js | 29 +++++++ 81 files changed, 676 insertions(+), 521 deletions(-) diff --git a/app/templates/.jscs.json b/app/templates/.jscs.json index dc46a2f34..1c278d0c4 100644 --- a/app/templates/.jscs.json +++ b/app/templates/.jscs.json @@ -1,3 +1,12 @@ { - "preset": "google" + "preset": "google", + "maximumLineLength": { + "value": 100, + "allowComments": true, + "allowRegex": true + }, + "requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties", + "requireSpacesInsideObjectBrackets": "all", + "disallowSpacesInsideObjectBrackets": "nested", + "requireSpacesInConditionalExpression": true } \ No newline at end of file diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 3e2da06c8..224e84c66 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -80,7 +80,7 @@ module.exports = function (grunt) { '<%%= yeoman.client %>/{app,components}/**/*.mock.js' ], tasks: ['newer:jshint:all', 'karma'] - },<% if(filters.stylus) { %> + },<% if (filters.stylus) { %> injectStylus: { files: [ '<%%= yeoman.client %>/{app,components}/**/*.styl'], @@ -90,7 +90,7 @@ module.exports = function (grunt) { files: [ '<%%= yeoman.client %>/{app,components}/**/*.styl'], tasks: ['stylus', 'autoprefixer'] - },<% } %><% if(filters.sass) { %> + },<% } %><% if (filters.sass) { %> injectSass: { files: [ '<%%= yeoman.client %>/{app,components}/**/*.{scss,sass}'], @@ -100,7 +100,7 @@ module.exports = function (grunt) { files: [ '<%%= yeoman.client %>/{app,components}/**/*.{scss,sass}'], tasks: ['sass', 'autoprefixer'] - },<% } %><% if(filters.less) { %> + },<% } %><% if (filters.less) { %> injectLess: { files: [ '<%%= yeoman.client %>/{app,components}/**/*.less'], @@ -110,13 +110,13 @@ module.exports = function (grunt) { files: [ '<%%= yeoman.client %>/{app,components}/**/*.less'], tasks: ['less', 'autoprefixer'] - },<% } %><% if(filters.jade) { %> + },<% } %><% if (filters.jade) { %> jade: { files: [ '<%%= yeoman.client %>/{app,components}/*', '<%%= yeoman.client %>/{app,components}/**/*.jade'], tasks: ['jade'] - },<% } %><% if(filters.coffee) { %> + },<% } %><% if (filters.coffee) { %> coffee: { files: [ '<%%= yeoman.client %>/{app,components}/**/*.{coffee,litcoffee,coffee.md}', @@ -458,18 +458,18 @@ module.exports = function (grunt) { // Run some tasks in parallel to speed up the build process concurrent: { - server: [<% if(filters.coffee) { %> - 'coffee',<% } %><% if(filters.jade) { %> - 'jade',<% } %><% if(filters.stylus) { %> - 'stylus',<% } %><% if(filters.sass) { %> - 'sass',<% } %><% if(filters.less) { %> + server: [<% if (filters.coffee) { %> + 'coffee',<% } %><% if (filters.jade) { %> + 'jade',<% } %><% if (filters.stylus) { %> + 'stylus',<% } %><% if (filters.sass) { %> + 'sass',<% } %><% if (filters.less) { %> 'less',<% } %> ], - test: [<% if(filters.coffee) { %> - 'coffee',<% } %><% if(filters.jade) { %> - 'jade',<% } %><% if(filters.stylus) { %> - 'stylus',<% } %><% if(filters.sass) { %> - 'sass',<% } %><% if(filters.less) { %> + test: [<% if (filters.coffee) { %> + 'coffee',<% } %><% if (filters.jade) { %> + 'jade',<% } %><% if (filters.stylus) { %> + 'stylus',<% } %><% if (filters.sass) { %> + 'sass',<% } %><% if (filters.less) { %> 'less',<% } %> ], debug: { @@ -481,11 +481,11 @@ module.exports = function (grunt) { logConcurrentOutput: true } }, - dist: [<% if(filters.coffee) { %> - 'coffee',<% } %><% if(filters.jade) { %> - 'jade',<% } %><% if(filters.stylus) { %> - 'stylus',<% } %><% if(filters.sass) { %> - 'sass',<% } %><% if(filters.less) { %> + dist: [<% if (filters.coffee) { %> + 'coffee',<% } %><% if (filters.jade) { %> + 'jade',<% } %><% if (filters.stylus) { %> + 'stylus',<% } %><% if (filters.sass) { %> + 'sass',<% } %><% if (filters.less) { %> 'less',<% } %> 'imagemin', 'svgmin' @@ -579,7 +579,7 @@ module.exports = function (grunt) { NODE_ENV: 'production' }, all: localConfig - },<% if(filters.jade) { %> + },<% if (filters.jade) { %> // Compiles Jade to html jade: { @@ -599,7 +599,7 @@ module.exports = function (grunt) { ext: '.html' }] } - },<% } %><% if(filters.coffee) { %> + },<% } %><% if (filters.coffee) { %> // Compiles CoffeeScript to JavaScript coffee: { @@ -619,7 +619,7 @@ module.exports = function (grunt) { ext: '.js' }] } - },<% } %><% if(filters.stylus) { %> + },<% } %><% if (filters.stylus) { %> // Compiles Stylus to CSS stylus: { @@ -636,7 +636,7 @@ module.exports = function (grunt) { '.tmp/app/app.css' : '<%%= yeoman.client %>/app/app.styl' } } - },<% } %><% if(filters.sass) { %> + },<% } %><% if (filters.sass) { %> // Compiles Sass to CSS sass: { @@ -653,7 +653,7 @@ module.exports = function (grunt) { '.tmp/app/app.css' : '<%%= yeoman.client %>/app/app.scss' } } - },<% } %><% if(filters.less) { %> + },<% } %><% if (filters.less) { %> // Compiles Less to CSS less: { @@ -694,7 +694,7 @@ module.exports = function (grunt) { '!{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.mock.js'] ] } - },<% if(filters.stylus) { %> + },<% if (filters.stylus) { %> // Inject component styl into app.styl stylus: { @@ -713,7 +713,7 @@ module.exports = function (grunt) { '!<%%= yeoman.client %>/app/app.styl' ] } - },<% } %><% if(filters.sass) { %> + },<% } %><% if (filters.sass) { %> // Inject component scss into app.scss sass: { @@ -732,7 +732,7 @@ module.exports = function (grunt) { '!<%%= yeoman.client %>/app/app.{scss,sass}' ] } - },<% } %><% if(filters.less) { %> + },<% } %><% if (filters.less) { %> // Inject component less into app.less less: { @@ -797,9 +797,9 @@ module.exports = function (grunt) { if (target === 'debug') { return grunt.task.run([ 'clean:server', - 'env:all',<% if(filters.stylus) { %> - 'injector:stylus', <% } %><% if(filters.less) { %> - 'injector:less', <% } %><% if(filters.sass) { %> + 'env:all',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> 'injector:sass', <% } %> 'concurrent:server', 'injector', @@ -811,9 +811,9 @@ module.exports = function (grunt) { grunt.task.run([ 'clean:server', - 'env:all',<% if(filters.stylus) { %> - 'injector:stylus', <% } %><% if(filters.less) { %> - 'injector:less', <% } %><% if(filters.sass) { %> + 'env:all',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> 'injector:sass', <% } %> 'concurrent:server', 'injector', @@ -844,9 +844,9 @@ module.exports = function (grunt) { else if (target === 'client') { return grunt.task.run([ 'clean:server', - 'env:all',<% if(filters.stylus) { %> - 'injector:stylus', <% } %><% if(filters.less) { %> - 'injector:less', <% } %><% if(filters.sass) { %> + 'env:all',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> 'injector:sass', <% } %> 'concurrent:test', 'injector', @@ -859,9 +859,9 @@ module.exports = function (grunt) { return grunt.task.run([ 'clean:server', 'env:all', - 'env:test',<% if(filters.stylus) { %> - 'injector:stylus', <% } %><% if(filters.less) { %> - 'injector:less', <% } %><% if(filters.sass) { %> + 'env:test',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> 'injector:sass', <% } %> 'concurrent:test', 'injector', @@ -914,9 +914,9 @@ module.exports = function (grunt) { }); grunt.registerTask('build', [ - 'clean:dist',<% if(filters.stylus) { %> - 'injector:stylus', <% } %><% if(filters.less) { %> - 'injector:less', <% } %><% if(filters.sass) { %> + 'clean:dist',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> 'injector:sass', <% } %> 'concurrent:dist', 'injector', diff --git a/app/templates/_.gitignore b/app/templates/_.gitignore index 6b4afbb0f..6d88c2a0a 100644 --- a/app/templates/_.gitignore +++ b/app/templates/_.gitignore @@ -1,6 +1,6 @@ node_modules public -.tmp<% if(filters.sass) { %> +.tmp<% if (filters.sass) { %> .sass-cache<% } %> .idea client/bower_components diff --git a/app/templates/_bower.json b/app/templates/_bower.json index 1681050a2..aaf0f8b81 100644 --- a/app/templates/_bower.json +++ b/app/templates/_bower.json @@ -5,17 +5,17 @@ "angular": ">=1.2.*", "json3": "~3.3.1", "es5-shim": "~3.0.1", - "jquery": "~1.11.0",<% if(filters.bootstrap) { %><% if (filters.sass) { %> + "jquery": "~1.11.0",<% if (filters.bootstrap) { %><% if (filters.sass) { %> "bootstrap-sass-official": "~3.1.1",<% } %> "bootstrap": "~3.1.1",<% } %> "angular-resource": ">=1.2.*", "angular-cookies": ">=1.2.*", - "angular-sanitize": ">=1.2.*",<% if(filters.ngroute) { %> - "angular-route": ">=1.2.*",<% } %><% if(filters.uibootstrap) { %> + "angular-sanitize": ">=1.2.*",<% if (filters.ngroute) { %> + "angular-route": ">=1.2.*",<% } %><% if (filters.uibootstrap) { %> "angular-bootstrap": "~0.11.0",<% } %> "font-awesome": ">=4.1.0", - "lodash": "~2.4.1"<% if(filters.socketio) { %>, - "angular-socket-io": "~0.6.0"<% } %><% if(filters.uirouter) { %>, + "lodash": "~2.4.1"<% if (filters.socketio) { %>, + "angular-socket-io": "~0.6.0"<% } %><% if (filters.uirouter) { %>, "angular-ui-router": "~0.2.10"<% } %> }, "devDependencies": { diff --git a/app/templates/_package.json b/app/templates/_package.json index 3775d0d90..8963ff15d 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -12,20 +12,20 @@ "express-session": "~1.0.2", "errorhandler": "~1.0.0", "compression": "~1.0.1", - "lodash": "~2.4.1",<% if(filters.jade) { %> - "jade": "~1.2.0",<% } %><% if(filters.html) { %> - "ejs": "~0.8.4",<% } %><% if(filters.mongoose) { %> + "lodash": "~2.4.1",<% if (filters.jade) { %> + "jade": "~1.2.0",<% } %><% if (filters.html) { %> + "ejs": "~0.8.4",<% } %><% if (filters.mongoose) { %> "mongoose": "~3.8.8", - "mongoose-bird": "~0.0.1",<% } %><% if(filters.auth) { %> + "mongoose-bird": "~0.0.1",<% } %><% if (filters.auth) { %> "jsonwebtoken": "^0.3.0", "express-jwt": "^0.1.3", "passport": "~0.2.0", - "passport-local": "~0.1.6",<% } %><% if(filters.facebookAuth) { %> - "passport-facebook": "latest",<% } %><% if(filters.twitterAuth) { %> - "passport-twitter": "latest",<% } %><% if(filters.googleAuth) { %> + "passport-local": "~0.1.6",<% } %><% if (filters.facebookAuth) { %> + "passport-facebook": "latest",<% } %><% if (filters.twitterAuth) { %> + "passport-twitter": "latest",<% } %><% if (filters.googleAuth) { %> "passport-google-oauth": "latest",<% } %> "composable-middleware": "^0.3.0", - "connect-mongo": "^0.4.1"<% if(filters.socketio) { %>, + "connect-mongo": "^0.4.1"<% if (filters.socketio) { %>, "socket.io": "^1.0.6", "socket.io-client": "^1.0.6", "socketio-jwt": "^2.0.2"<% } %> @@ -43,9 +43,9 @@ "grunt-contrib-imagemin": "~0.7.1", "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-uglify": "~0.4.0", - "grunt-contrib-watch": "~0.6.1",<% if(filters.coffee) { %> - "grunt-contrib-coffee": "^0.10.1",<% } %><% if(filters.jade) { %> - "grunt-contrib-jade": "^0.11.0",<% } %><% if(filters.less) { %> + "grunt-contrib-watch": "~0.6.1",<% if (filters.coffee) { %> + "grunt-contrib-coffee": "^0.10.1",<% } %><% if (filters.jade) { %> + "grunt-contrib-jade": "^0.11.0",<% } %><% if (filters.less) { %> "grunt-contrib-less": "^0.11.4",<% } %> "grunt-google-cdn": "~0.4.0", "grunt-jscs": "~0.7.1", @@ -62,8 +62,8 @@ "grunt-protractor-runner": "^1.1.0", "grunt-asset-injector": "^0.1.0", "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control",<% if(filters.sass) { %> - "grunt-contrib-sass": "^0.7.3",<% } %><% if(filters.stylus) { %> + "grunt-build-control": "DaftMonk/grunt-build-control",<% if (filters.sass) { %> + "grunt-contrib-sass": "^0.7.3",<% } %><% if (filters.stylus) { %> "grunt-contrib-stylus": "latest",<% } %> "jit-grunt": "^0.5.0", "time-grunt": "~0.3.1", @@ -76,9 +76,9 @@ "grunt-mocha-istanbul": "^2.0.0", "chai-as-promised": "^4.1.1", "chai-things": "^0.2.0", - "sinon-chai": "^2.5.0",<% if(filters.mocha) { %> + "sinon-chai": "^2.5.0",<% if (filters.mocha) { %> "karma-mocha": "^0.1.9", - "karma-chai-plugins": "^0.2.3",<% } if(filters.jasmine) { %> + "karma-chai-plugins": "^0.2.3",<% } if (filters.jasmine) { %> "karma-jasmine": "~0.1.5",<% } %> "karma-ng-scenario": "~0.1.0", "karma-firefox-launcher": "~0.1.3", diff --git a/app/templates/client/app/account(auth)/account(coffee).coffee b/app/templates/client/app/account(auth)/account(coffee).coffee index 088fb6840..c794d7f04 100644 --- a/app/templates/client/app/account(auth)/account(coffee).coffee +++ b/app/templates/client/app/account(auth)/account(coffee).coffee @@ -1,7 +1,7 @@ 'use strict' angular.module '<%= scriptAppName %>' -<% if(filters.ngroute) { %>.config ($routeProvider) -> +<% if (filters.ngroute) { %>.config ($routeProvider) -> $routeProvider .when '/login', templateUrl: 'app/account/login/login.html' @@ -27,7 +27,7 @@ angular.module '<%= scriptAppName %>' .run ($rootScope) -> $rootScope.$on '$routeChangeStart', (event, next, current) -> next.referrer = current.originalPath if next.name is "logout" and current and current.originalPath and not current.authenticate -<% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> +<% } %><% if (filters.uirouter) { %>.config ($stateProvider) -> $stateProvider .state 'login', url: '/login' diff --git a/app/templates/client/app/account(auth)/account(js).js b/app/templates/client/app/account(auth)/account(js).js index 8c005c952..d60fd72fe 100644 --- a/app/templates/client/app/account(auth)/account(js).js +++ b/app/templates/client/app/account(auth)/account(js).js @@ -1,7 +1,7 @@ 'use strict'; angular.module('<%= scriptAppName %>') - <% if(filters.ngroute) { %>.config(function ($routeProvider) { + <% if (filters.ngroute) { %>.config(function($routeProvider) { $routeProvider .when('/login', { templateUrl: 'app/account/login/login.html', @@ -35,7 +35,7 @@ angular.module('<%= scriptAppName %>') next.referrer = current.originalPath; } }); - });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { + });<% } %><% if (filters.uirouter) { %>.config(function($stateProvider) { $stateProvider .state('login', { url: '/login', diff --git a/app/templates/client/app/account(auth)/login/login(html).html b/app/templates/client/app/account(auth)/login/login(html).html index 49a81b55d..f02de2616 100644 --- a/app/templates/client/app/account(auth)/login/login(html).html +++ b/app/templates/client/app/account(auth)/login/login(html).html @@ -37,19 +37,19 @@

Login

- ui-sref="signup"<% } else { %>href="/signup"<% } %>> + ui-sref="signup"<% } else { %>href="/signup"<% } %>> Register -<% if(filters.oauth) {%> +<% if (filters.oauth) {%>
-
<% if(filters.facebookAuth) {%> +
<% if (filters.facebookAuth) {%> Connect with Facebook - <% } %><% if(filters.googleAuth) {%> + <% } %><% if (filters.googleAuth) {%> Connect with Google+ - <% } %><% if(filters.twitterAuth) {%> + <% } %><% if (filters.twitterAuth) {%> Connect with Twitter <% } %> diff --git a/app/templates/client/app/account(auth)/login/login(jade).jade b/app/templates/client/app/account(auth)/login/login(jade).jade index 5f608a67b..fd95e6ff1 100644 --- a/app/templates/client/app/account(auth)/login/login(jade).jade +++ b/app/templates/client/app/account(auth)/login/login(jade).jade @@ -34,20 +34,20 @@ div(ng-include='"components/navbar/navbar.html"') button.btn.btn-inverse.btn-lg.btn-login(type='submit') | Login = ' ' - a.btn.btn-default.btn-lg.btn-register(<% if(filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) + a.btn.btn-default.btn-lg.btn-register(<% if (filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) | Register -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> hr - div<% if(filters.facebookAuth) {%> + div<% if (filters.facebookAuth) {%> a.btn.btn-facebook(href='', ng-click='loginOauth("facebook")') i.fa.fa-facebook | Connect with Facebook - = ' '<% } %><% if(filters.googleAuth) {%> + = ' '<% } %><% if (filters.googleAuth) {%> a.btn.btn-google-plus(href='', ng-click='loginOauth("google")') i.fa.fa-google-plus | Connect with Google+ - = ' '<% } %><% if(filters.twitterAuth) {%> + = ' '<% } %><% if (filters.twitterAuth) {%> a.btn.btn-twitter(href='', ng-click='loginOauth("twitter")') i.fa.fa-twitter | Connect with Twitter<% } %><% } %> diff --git a/app/templates/client/app/account(auth)/login/login(less).less b/app/templates/client/app/account(auth)/login/login(less).less index bd01a056e..6eaecd90c 100644 --- a/app/templates/client/app/account(auth)/login/login(less).less +++ b/app/templates/client/app/account(auth)/login/login(less).less @@ -1,4 +1,4 @@ -<% if(filters.bootstrap) { %>// Colors +<% if (filters.bootstrap) { %>// Colors // -------------------------------------------------- @btnText: #fff; diff --git a/app/templates/client/app/account(auth)/login/login(sass).scss b/app/templates/client/app/account(auth)/login/login(sass).scss index eb214a8ca..5b6956124 100644 --- a/app/templates/client/app/account(auth)/login/login(sass).scss +++ b/app/templates/client/app/account(auth)/login/login(sass).scss @@ -1,4 +1,4 @@ -<% if(filters.bootstrap) { %>// Colors +<% if (filters.bootstrap) { %>// Colors // -------------------------------------------------- $btnText: #fff; diff --git a/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee b/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee index 036191f93..7bcb69969 100644 --- a/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee +++ b/app/templates/client/app/account(auth)/login/login.controller(coffee).coffee @@ -1,7 +1,7 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'LoginCtrl', ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if(filters.oauth) {%>, $window<% } %>) -> +.controller 'LoginCtrl', ($scope, Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %><% if (filters.oauth) {%>, $window<% } %>) -> $scope.user = {} $scope.errors = {} $scope.login = (form) -> @@ -14,10 +14,10 @@ angular.module '<%= scriptAppName %>' password: $scope.user.password .then -> - <% if(filters.ngroute) { %>$location.path '/'<% } %><% if(filters.uirouter) { %>$state.go 'main'<% } %> + <% if (filters.ngroute) { %>$location.path '/'<% } %><% if (filters.uirouter) { %>$state.go 'main'<% } %> .catch (err) -> $scope.errors.other = err.message -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> $scope.loginOauth = (provider) -> $window.location.href = '/auth/' + provider<% } %> diff --git a/app/templates/client/app/account(auth)/login/login.controller(js).js b/app/templates/client/app/account(auth)/login/login.controller(js).js index e2c5dcaa4..2417e62f4 100644 --- a/app/templates/client/app/account(auth)/login/login.controller(js).js +++ b/app/templates/client/app/account(auth)/login/login.controller(js).js @@ -1,28 +1,28 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('LoginCtrl', function ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { + .controller('LoginCtrl', function($scope, Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { $scope.user = {}; $scope.errors = {}; $scope.login = function(form) { $scope.submitted = true; - if(form.$valid) { + if (form.$valid) { Auth.login({ email: $scope.user.email, password: $scope.user.password }) - .then( function() { + .then(function() { // Logged in, redirect to home - <% if(filters.ngroute) { %>$location.path('/');<% } %><% if(filters.uirouter) { %>$state.go('main');<% } %> + <% if (filters.ngroute) { %>$location.path('/');<% } %><% if (filters.uirouter) { %>$state.go('main');<% } %> }) - .catch( function(err) { + .catch(function(err) { $scope.errors.other = err.message; }); } }; -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> $scope.loginOauth = function(provider) { $window.location.href = '/auth/' + provider; };<% } %> diff --git a/app/templates/client/app/account(auth)/settings/settings.controller(js).js b/app/templates/client/app/account(auth)/settings/settings.controller(js).js index 829bd8248..eeb1219cf 100644 --- a/app/templates/client/app/account(auth)/settings/settings.controller(js).js +++ b/app/templates/client/app/account(auth)/settings/settings.controller(js).js @@ -1,21 +1,21 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('SettingsCtrl', function ($scope, User, Auth) { + .controller('SettingsCtrl', function($scope, User, Auth) { $scope.errors = {}; $scope.changePassword = function(form) { $scope.submitted = true; - if(form.$valid) { - Auth.changePassword( $scope.user.oldPassword, $scope.user.newPassword ) - .then( function() { - $scope.message = 'Password successfully changed.'; - }) - .catch( function() { - form.password.$setValidity('mongoose', false); - $scope.errors.other = 'Incorrect password'; - $scope.message = ''; - }); + if (form.$valid) { + Auth.changePassword($scope.user.oldPassword, $scope.user.newPassword) + .then(function() { + $scope.message = 'Password successfully changed.'; + }) + .catch(function() { + form.password.$setValidity('mongoose', false); + $scope.errors.other = 'Incorrect password'; + $scope.message = ''; + }); } - }; + }; }); diff --git a/app/templates/client/app/account(auth)/signup/signup(html).html b/app/templates/client/app/account(auth)/signup/signup(html).html index ee4f17fa4..fc55d3790 100644 --- a/app/templates/client/app/account(auth)/signup/signup(html).html +++ b/app/templates/client/app/account(auth)/signup/signup(html).html @@ -58,19 +58,19 @@

Sign up

-
-<% if(filters.oauth) {%> +<% if (filters.oauth) {%>
-
<% if(filters.facebookAuth) {%> +
<% if (filters.facebookAuth) {%> Connect with Facebook - <% } %><% if(filters.googleAuth) {%> + <% } %><% if (filters.googleAuth) {%> Connect with Google+ - <% } %><% if(filters.twitterAuth) {%> + <% } %><% if (filters.twitterAuth) {%> Connect with Twitter <% } %> diff --git a/app/templates/client/app/account(auth)/signup/signup(jade).jade b/app/templates/client/app/account(auth)/signup/signup(jade).jade index 8c5710686..081657a6d 100644 --- a/app/templates/client/app/account(auth)/signup/signup(jade).jade +++ b/app/templates/client/app/account(auth)/signup/signup(jade).jade @@ -36,21 +36,21 @@ div(ng-include='"components/navbar/navbar.html"') button.btn.btn-inverse.btn-lg.btn-register(type='submit') | Sign up = ' ' - a.btn.btn-default.btn-lg.btn-login(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) + a.btn.btn-default.btn-lg.btn-login(<% if (filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) | Login -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> hr - div<% if(filters.facebookAuth) {%> + div<% if (filters.facebookAuth) {%> a.btn.btn-facebook(href='', ng-click='loginOauth("facebook")') i.fa.fa-facebook | Connect with Facebook - = ' '<% } %><% if(filters.googleAuth) {%> + = ' '<% } %><% if (filters.googleAuth) {%> a.btn.btn-google-plus(href='', ng-click='loginOauth("google")') i.fa.fa-google-plus | Connect with Google+ - = ' '<% } %><% if(filters.twitterAuth) {%> + = ' '<% } %><% if (filters.twitterAuth) {%> a.btn.btn-twitter(href='', ng-click='loginOauth("twitter")') i.fa.fa-twitter | Connect with Twitter<% } %><% } %> diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee index ac240faa8..3d96f3bf5 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee +++ b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee @@ -1,7 +1,7 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'SignupCtrl', ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if(filters.oauth) {%>, $window<% } %>) -> +.controller 'SignupCtrl', ($scope, Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %><% if (filters.oauth) {%>, $window<% } %>) -> $scope.user = {} $scope.errors = {} $scope.register = (form) -> @@ -15,7 +15,7 @@ angular.module '<%= scriptAppName %>' password: $scope.user.password .then -> - <% if(filters.ngroute) { %>$location.path '/'<% } %><% if(filters.uirouter) { %>$state.go 'main'<% } %> + <% if (filters.ngroute) { %>$location.path '/'<% } %><% if (filters.uirouter) { %>$state.go 'main'<% } %> .catch (err) -> err = err.data @@ -25,6 +25,6 @@ angular.module '<%= scriptAppName %>' angular.forEach err.errors, (error, field) -> form[field].$setValidity 'mongoose', false $scope.errors[field] = error.message -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> $scope.loginOauth = (provider) -> $window.location.href = '/auth/' + provider<% } %> diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(js).js b/app/templates/client/app/account(auth)/signup/signup.controller(js).js index 10685079d..7e93a6949 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(js).js +++ b/app/templates/client/app/account(auth)/signup/signup.controller(js).js @@ -1,24 +1,24 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('SignupCtrl', function ($scope, Auth<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { + .controller('SignupCtrl', function($scope, Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %><% if (filters.oauth) { %>, $window<% } %>) { $scope.user = {}; $scope.errors = {}; $scope.register = function(form) { $scope.submitted = true; - if(form.$valid) { + if (form.$valid) { Auth.createUser({ name: $scope.user.name, email: $scope.user.email, password: $scope.user.password }) - .then( function() { + .then(function() { // Account created, redirect to home - <% if(filters.ngroute) { %>$location.path('/');<% } %><% if(filters.uirouter) { %>$state.go('main');<% } %> + <% if (filters.ngroute) { %>$location.path('/');<% } %><% if (filters.uirouter) { %>$state.go('main');<% } %> }) - .catch( function(err) { + .catch(function(err) { err = err.data; $scope.errors = {}; @@ -30,7 +30,7 @@ angular.module('<%= scriptAppName %>') }); } }; -<% if(filters.oauth) {%> +<% if (filters.oauth) {%> $scope.loginOauth = function(provider) { $window.location.href = '/auth/' + provider; };<% } %> diff --git a/app/templates/client/app/admin(auth)/admin(coffee).coffee b/app/templates/client/app/admin(auth)/admin(coffee).coffee index a0497445e..18bb9d4ad 100644 --- a/app/templates/client/app/admin(auth)/admin(coffee).coffee +++ b/app/templates/client/app/admin(auth)/admin(coffee).coffee @@ -1,12 +1,12 @@ 'use strict' angular.module '<%= scriptAppName %>' -<% if(filters.ngroute) { %>.config ($routeProvider) -> +<% if (filters.ngroute) { %>.config ($routeProvider) -> $routeProvider .when '/admin', templateUrl: 'app/admin/admin.html' controller: 'AdminCtrl' -<% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> +<% } %><% if (filters.uirouter) { %>.config ($stateProvider) -> $stateProvider .state 'admin', url: '/admin' diff --git a/app/templates/client/app/admin(auth)/admin(js).js b/app/templates/client/app/admin(auth)/admin(js).js index 270e8a974..f37ba9fcc 100644 --- a/app/templates/client/app/admin(auth)/admin(js).js +++ b/app/templates/client/app/admin(auth)/admin(js).js @@ -1,17 +1,17 @@ 'use strict'; angular.module('<%= scriptAppName %>') - <% if(filters.ngroute) { %>.config(function ($routeProvider) { + <% if (filters.ngroute) { %>.config(function($routeProvider) { $routeProvider .when('/admin', { templateUrl: 'app/admin/admin.html', controller: 'AdminCtrl' }); - });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { + });<% } %><% if (filters.uirouter) { %>.config(function($stateProvider) { $stateProvider .state('admin', { url: '/admin', templateUrl: 'app/admin/admin.html', controller: 'AdminCtrl' }); - });<% } %> \ No newline at end of file + });<% } %> diff --git a/app/templates/client/app/admin(auth)/admin.controller(js).js b/app/templates/client/app/admin(auth)/admin.controller(js).js index dd6b09405..51a52b759 100644 --- a/app/templates/client/app/admin(auth)/admin.controller(js).js +++ b/app/templates/client/app/admin(auth)/admin.controller(js).js @@ -1,7 +1,7 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('AdminCtrl', function ($scope, $http, Auth, User) { + .controller('AdminCtrl', function($scope, $http, Auth, User) { // Use the User $resource to fetch all users $scope.users = User.query(); diff --git a/app/templates/client/app/app(coffee).coffee b/app/templates/client/app/app(coffee).coffee index cb6d0c5b1..25b572a75 100644 --- a/app/templates/client/app/app(coffee).coffee +++ b/app/templates/client/app/app(coffee).coffee @@ -1,22 +1,22 @@ 'use strict' angular.module '<%= scriptAppName %>', [<%= angularModules %>] -<% if(filters.ngroute) { %>.config ($routeProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) -> +<% if (filters.ngroute) { %>.config ($routeProvider, $locationProvider<% if (filters.auth) { %>, $httpProvider<% } %>) -> $routeProvider .otherwise redirectTo: '/' - $locationProvider.html5Mode true<% if(filters.auth) { %> + $locationProvider.html5Mode true<% if (filters.auth) { %> $httpProvider.interceptors.push 'authInterceptor'<% } %> -<% } %><% if(filters.uirouter) { %>.config ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) -> +<% } %><% if (filters.uirouter) { %>.config ($stateProvider, $urlRouterProvider, $locationProvider<% if (filters.auth) { %>, $httpProvider<% } %>) -> $urlRouterProvider .otherwise '/' - $locationProvider.html5Mode true<% if(filters.auth) { %> + $locationProvider.html5Mode true<% if (filters.auth) { %> $httpProvider.interceptors.push 'authInterceptor'<% } %> -<% } %><% if(filters.auth) { %> -.factory 'authInterceptor', ($rootScope, $q, $cookieStore<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $injector<% } %>) -> - <% if(filters.uirouter) { %>state = null +<% } %><% if (filters.auth) { %> +.factory 'authInterceptor', ($rootScope, $q, $cookieStore<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) -> + <% if (filters.uirouter) { %>state = null <% } %># Add authorization token to headers request: (config) -> config.headers = config.headers or {} @@ -26,15 +26,15 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] # Intercept 401s and redirect you to login responseError: (response) -> if response.status is 401 - <% if(filters.ngroute) { %>$location.path '/login'<% } if(filters.uirouter) { %>(state || state = $injector.get '$state').go 'login'<% } %> + <% if (filters.ngroute) { %>$location.path '/login'<% } if (filters.uirouter) { %>(state || state = $injector.get '$state').go 'login'<% } %> # remove any stale tokens $cookieStore.remove 'token' $q.reject response -.run ($rootScope<% if(filters.ngroute) { %>, $location<% } %><% if(filters.uirouter) { %>, $state<% } %>, Auth) -> +.run ($rootScope<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %>, Auth) -> # Redirect to login if route requires auth and you're not logged in - $rootScope.$on <% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> + $rootScope.$on <% if (filters.ngroute) { %>'$routeChangeStart'<% } %><% if (filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> Auth.isLoggedIn (loggedIn) -> - <% if(filters.ngroute) { %>$location.path '/login'<% } %><% if(filters.uirouter) { %>$state.go 'login'<% } %> if next.authenticate and not loggedIn + <% if (filters.ngroute) { %>$location.path '/login'<% } %><% if (filters.uirouter) { %>$state.go 'login'<% } %> if next.authenticate and not loggedIn <% } %> diff --git a/app/templates/client/app/app(css).css b/app/templates/client/app/app(css).css index f1a61a918..b4e05273d 100644 --- a/app/templates/client/app/app(css).css +++ b/app/templates/client/app/app(css).css @@ -1,4 +1,4 @@ -<% if(filters.bootstrap) { %> +<% if (filters.bootstrap) { %> /** * Bootstrap Fonts */ @@ -37,7 +37,7 @@ color: #000; padding: 0.2em 0; } -<% if (!filters.bootstrap) { %> +<% if(!filters.bootstrap) { %> /* Responsive: Portrait tablets and up */ @media screen and (min-width: 768px) { .container { diff --git a/app/templates/client/app/app(js).js b/app/templates/client/app/app(js).js index 35b8ad327..b45db3c7f 100644 --- a/app/templates/client/app/app(js).js +++ b/app/templates/client/app/app(js).js @@ -1,27 +1,27 @@ 'use strict'; angular.module('<%= scriptAppName %>', [<%= angularModules %>]) - <% if(filters.ngroute) { %>.config(function ($routeProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { + <% if (filters.ngroute) { %>.config(function($routeProvider, $locationProvider<% if (filters.auth) { %>, $httpProvider<% } %>) { $routeProvider .otherwise({ redirectTo: '/' }); - $locationProvider.html5Mode(true);<% if(filters.auth) { %> + $locationProvider.html5Mode(true);<% if (filters.auth) { %> $httpProvider.interceptors.push('authInterceptor');<% } %> - })<% } if(filters.uirouter) { %>.config(function ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { + })<% } if (filters.uirouter) { %>.config(function($stateProvider, $urlRouterProvider, $locationProvider<% if (filters.auth) { %>, $httpProvider<% } %>) { $urlRouterProvider .otherwise('/'); - $locationProvider.html5Mode(true);<% if(filters.auth) { %> + $locationProvider.html5Mode(true);<% if (filters.auth) { %> $httpProvider.interceptors.push('authInterceptor');<% } %> - })<% } if(filters.auth) { %> + })<% } if (filters.auth) { %> - .factory('authInterceptor', function ($rootScope, $q, $cookieStore<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $injector<% } %>) { - <% if(filters.uirouter) { %>var state; + .factory('authInterceptor', function($rootScope, $q, $cookieStore<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) { + <% if (filters.uirouter) { %>var state; <% } %>return { // Add authorization token to headers - request: function (config) { + request: function(config) { config.headers = config.headers || {}; if ($cookieStore.get('token')) { config.headers.Authorization = 'Bearer ' + $cookieStore.get('token'); @@ -31,8 +31,8 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) // Intercept 401s and redirect you to login responseError: function(response) { - if(response.status === 401) { - <% if(filters.ngroute) { %>$location.path('/login');<% } if(filters.uirouter) { %>(state || (state = $injector.get('$state'))).go('login');<% } %> + if (response.status === 401) { + <% if (filters.ngroute) { %>$location.path('/login');<% } if (filters.uirouter) { %>(state || (state = $injector.get('$state'))).go('login');<% } %> // remove any stale tokens $cookieStore.remove('token'); return $q.reject(response); @@ -44,12 +44,12 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) }; }) - .run(function ($rootScope<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $state<% } %>, Auth) { + .run(function($rootScope<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $state<% } %>, Auth) { // Redirect to login if route requires auth and you're not logged in - $rootScope.$on(<% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, function (event, next) { + $rootScope.$on(<% if (filters.ngroute) { %>'$routeChangeStart'<% } %><% if (filters.uirouter) { %>'$stateChangeStart'<% } %>, function(event, next) { Auth.isLoggedIn(function(loggedIn) { if (next.authenticate && !loggedIn) { - <% if(filters.ngroute) { %>$location.path('/login');<% } if(filters.uirouter) { %>$state.go('login');<% } %> + <% if (filters.ngroute) { %>$location.path('/login');<% } if (filters.uirouter) { %>$state.go('login');<% } %> } }); }); diff --git a/app/templates/client/app/app(less).less b/app/templates/client/app/app(less).less index 30639f539..71381ceb1 100644 --- a/app/templates/client/app/app(less).less +++ b/app/templates/client/app/app(less).less @@ -1,7 +1,7 @@ -<% if(filters.bootstrap) { %>@import 'bootstrap/less/bootstrap.less';<% } %> +<% if (filters.bootstrap) { %>@import 'bootstrap/less/bootstrap.less';<% } %> @import 'font-awesome/less/font-awesome.less'; -<% if(filters.bootstrap) { %>@icon-font-path: '/bower_components/bootstrap/fonts/';<% } %> +<% if (filters.bootstrap) { %>@icon-font-path: '/bower_components/bootstrap/fonts/';<% } %> @fa-font-path: '/bower_components/font-awesome/fonts'; /** @@ -14,7 +14,7 @@ color: #000; padding: 0.2em 0; } -<% if (!filters.bootstrap) { %> +<% if(!filters.bootstrap) { %> /* Responsive: Portrait tablets and up */ @media screen and (min-width: 768px) { .container { diff --git a/app/templates/client/app/app(sass).scss b/app/templates/client/app/app(sass).scss index 4b8ae7a04..fe03d7044 100644 --- a/app/templates/client/app/app(sass).scss +++ b/app/templates/client/app/app(sass).scss @@ -1,6 +1,6 @@ -<% if(filters.bootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> +<% if (filters.bootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> $fa-font-path: "/bower_components/font-awesome/fonts"; -<% if(filters.bootstrap) { %> +<% if (filters.bootstrap) { %> @import 'bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> @import 'font-awesome/scss/font-awesome'; @@ -14,7 +14,7 @@ $fa-font-path: "/bower_components/font-awesome/fonts"; color: #000; padding: 0.2em 0; } -<% if (!filters.bootstrap) { %> +<% if(!filters.bootstrap) { %> /* Responsive: Portrait tablets and up */ @media screen and (min-width: 768px) { .container { diff --git a/app/templates/client/app/app(stylus).styl b/app/templates/client/app/app(stylus).styl index b7e4bb9c1..2d8afe893 100644 --- a/app/templates/client/app/app(stylus).styl +++ b/app/templates/client/app/app(stylus).styl @@ -1,5 +1,5 @@ @import "font-awesome/css/font-awesome.css" -<% if(filters.bootstrap) { %>@import "bootstrap/dist/css/bootstrap.css" +<% if (filters.bootstrap) { %>@import "bootstrap/dist/css/bootstrap.css" // // Bootstrap Fonts @@ -36,7 +36,7 @@ color #000 margin 0.2em 0 padding 0.2em 0 -<% if (!filters.bootstrap) { %> +<% if(!filters.bootstrap) { %> // Responsive: Portrait tablets and up @media screen and (min-width: 768px) .container diff --git a/app/templates/client/app/main/main(coffee).coffee b/app/templates/client/app/main/main(coffee).coffee index 6d84bdc1e..5d28335d1 100644 --- a/app/templates/client/app/main/main(coffee).coffee +++ b/app/templates/client/app/main/main(coffee).coffee @@ -1,12 +1,12 @@ 'use strict' angular.module '<%= scriptAppName %>' -<% if(filters.ngroute) { %>.config ($routeProvider) -> +<% if (filters.ngroute) { %>.config ($routeProvider) -> $routeProvider .when '/', templateUrl: 'app/main/main.html' controller: 'MainCtrl' -<% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> +<% } %><% if (filters.uirouter) { %>.config ($stateProvider) -> $stateProvider .state 'main', url: '/' diff --git a/app/templates/client/app/main/main(html).html b/app/templates/client/app/main/main(html).html index cd0f185b2..7d0d5c44b 100644 --- a/app/templates/client/app/main/main(html).html +++ b/app/templates/client/app/main/main(html).html @@ -13,10 +13,10 @@

'Allo, 'Allo!

-
<% if(filters.socketio) { %> +
<% if (filters.socketio) { %>
diff --git a/app/templates/client/app/main/main(jade).jade b/app/templates/client/app/main/main(jade).jade index 76784c855..ee66a5fc6 100644 --- a/app/templates/client/app/main/main(jade).jade +++ b/app/templates/client/app/main/main(jade).jade @@ -13,8 +13,8 @@ header#banner.hero-unit ul.nav.nav-tabs.nav-stacked.col-md-4.col-lg-4.col-sm-6(ng-repeat='thing in awesomeThings') li a(href='#', tooltip='{{thing.info}}') - | {{thing.name}}<% if(filters.socketio) { %> - button.close(type='button', ng-click='deleteThing(thing)') ×<% } %><% if(filters.socketio) { %> + | {{thing.name}}<% if (filters.socketio) { %> + button.close(type='button', ng-click='deleteThing(thing)') ×<% } %><% if (filters.socketio) { %> form.thing-form label Syncs in realtime across clients diff --git a/app/templates/client/app/main/main(js).js b/app/templates/client/app/main/main(js).js index 1d3bc318a..165181ffe 100644 --- a/app/templates/client/app/main/main(js).js +++ b/app/templates/client/app/main/main(js).js @@ -1,17 +1,17 @@ 'use strict'; angular.module('<%= scriptAppName %>') - <% if(filters.ngroute) { %>.config(function ($routeProvider) { + <% if (filters.ngroute) { %>.config(function($routeProvider) { $routeProvider .when('/', { templateUrl: 'app/main/main.html', controller: 'MainCtrl' }); - });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { + });<% } %><% if (filters.uirouter) { %>.config(function($stateProvider) { $stateProvider .state('main', { url: '/', templateUrl: 'app/main/main.html', controller: 'MainCtrl' }); - });<% } %> \ No newline at end of file + });<% } %> diff --git a/app/templates/client/app/main/main.controller(coffee).coffee b/app/templates/client/app/main/main.controller(coffee).coffee index 143e7f387..3dffae2f7 100644 --- a/app/templates/client/app/main/main.controller(coffee).coffee +++ b/app/templates/client/app/main/main.controller(coffee).coffee @@ -1,13 +1,13 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'MainCtrl', ($scope, $http<% if(filters.socketio) { %>, socket<% } %>) -> +.controller 'MainCtrl', ($scope, $http<% if (filters.socketio) { %>, socket<% } %>) -> $scope.awesomeThings = [] $http.get('/api/things').success (awesomeThings) -> $scope.awesomeThings = awesomeThings - <% if(filters.socketio) { %>socket.syncUpdates 'thing', $scope.awesomeThings<% } %> -<% if(filters.mongoose) { %> + <% if (filters.socketio) { %>socket.syncUpdates 'thing', $scope.awesomeThings<% } %> +<% if (filters.mongoose) { %> $scope.addThing = -> return if $scope.newThing is '' $http.post '/api/things', @@ -16,7 +16,7 @@ angular.module '<%= scriptAppName %>' $scope.newThing = '' $scope.deleteThing = (thing) -> - $http.delete '/api/things/' + thing._id<% } %><% if(filters.socketio) { %> + $http.delete '/api/things/' + thing._id<% } %><% if (filters.socketio) { %> $scope.$on '$destroy', -> socket.unsyncUpdates 'thing'<% } %> diff --git a/app/templates/client/app/main/main.controller(js).js b/app/templates/client/app/main/main.controller(js).js index 433a10fe4..8164a90dc 100644 --- a/app/templates/client/app/main/main.controller(js).js +++ b/app/templates/client/app/main/main.controller(js).js @@ -1,16 +1,16 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('MainCtrl', function ($scope, $http<% if(filters.socketio) { %>, socket<% } %>) { + .controller('MainCtrl', function($scope, $http<% if (filters.socketio) { %>, socket<% } %>) { $scope.awesomeThings = []; $http.get('/api/things').success(function(awesomeThings) { - $scope.awesomeThings = awesomeThings;<% if(filters.socketio) { %> + $scope.awesomeThings = awesomeThings;<% if (filters.socketio) { %> socket.syncUpdates('thing', $scope.awesomeThings);<% } %> }); -<% if(filters.mongoose) { %> +<% if (filters.mongoose) { %> $scope.addThing = function() { - if($scope.newThing === '') { + if ($scope.newThing === '') { return; } $http.post('/api/things', { name: $scope.newThing }); @@ -19,9 +19,9 @@ angular.module('<%= scriptAppName %>') $scope.deleteThing = function(thing) { $http.delete('/api/things/' + thing._id); - };<% } %><% if(filters.socketio) { %> + };<% } %><% if (filters.socketio) { %> - $scope.$on('$destroy', function () { + $scope.$on('$destroy', function() { socket.unsyncUpdates('thing'); });<% } %> }); diff --git a/app/templates/client/app/main/main.controller.spec(coffee).coffee b/app/templates/client/app/main/main.controller.spec(coffee).coffee index 5bdf4f840..a72ae8695 100644 --- a/app/templates/client/app/main/main.controller.spec(coffee).coffee +++ b/app/templates/client/app/main/main.controller.spec(coffee).coffee @@ -3,17 +3,17 @@ describe 'Controller: MainCtrl', -> # load the controller's module - beforeEach module '<%= scriptAppName %>' <% if(filters.uirouter) {%> - beforeEach module 'stateMock' <% } %><% if(filters.socketio) {%> + beforeEach module '<%= scriptAppName %>' <% if (filters.uirouter) {%> + beforeEach module 'stateMock' <% } %><% if (filters.socketio) {%> beforeEach module 'socketMock' <% } %> MainCtrl = undefined - scope = undefined<% if(filters.uirouter) {%> + scope = undefined<% if (filters.uirouter) {%> state = undefined<% } %> $httpBackend = undefined # Initialize the controller and a mock scope - beforeEach inject (_$httpBackend_, $controller, $rootScope<% if(filters.uirouter) {%>, $state<% } %>) -> + beforeEach inject (_$httpBackend_, $controller, $rootScope<% if (filters.uirouter) {%>, $state<% } %>) -> $httpBackend = _$httpBackend_ $httpBackend.expectGET('/api/things').respond [ 'HTML5 Boilerplate' @@ -21,7 +21,7 @@ describe 'Controller: MainCtrl', -> 'Karma' 'Express' ] - scope = $rootScope.$new()<% if(filters.uirouter) {%> + scope = $rootScope.$new()<% if (filters.uirouter) {%> state = $state<% } %> MainCtrl = $controller 'MainCtrl', $scope: scope diff --git a/app/templates/client/app/main/main.controller.spec(js).js b/app/templates/client/app/main/main.controller.spec(js).js index dc048b4af..71fd2a783 100644 --- a/app/templates/client/app/main/main.controller.spec(js).js +++ b/app/templates/client/app/main/main.controller.spec(js).js @@ -1,31 +1,31 @@ 'use strict'; -describe('Controller: MainCtrl', function () { +describe('Controller: MainCtrl', function() { // load the controller's module - beforeEach(module('<%= scriptAppName %>'));<% if(filters.uirouter) {%> - beforeEach(module('stateMock'));<% } %><% if(filters.socketio) {%> + beforeEach(module('<%= scriptAppName %>'));<% if (filters.uirouter) {%> + beforeEach(module('stateMock'));<% } %><% if (filters.socketio) {%> beforeEach(module('socketMock'));<% } %> - var MainCtrl, - scope,<% if(filters.uirouter) {%> - state,<% } %> - $httpBackend; + var MainCtrl; + var scope;<% if (filters.uirouter) {%> + var state;<% } %> + var $httpBackend; // Initialize the controller and a mock scope - beforeEach(inject(function (_$httpBackend_, $controller, $rootScope<% if(filters.uirouter) {%>, $state<% } %>) { + beforeEach(inject(function(_$httpBackend_, $controller, $rootScope<% if (filters.uirouter) {%>, $state<% } %>) { $httpBackend = _$httpBackend_; $httpBackend.expectGET('/api/things') .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']); - scope = $rootScope.$new();<% if(filters.uirouter) {%> + scope = $rootScope.$new();<% if (filters.uirouter) {%> state = $state;<% } %> MainCtrl = $controller('MainCtrl', { $scope: scope }); })); - it('should attach a list of things to the scope', function () { + it('should attach a list of things to the scope', function() { $httpBackend.flush();<% if (filters.jasmine) { %> expect(scope.awesomeThings.length).toBe(4);<% } if (filters.mocha) { %> <%= does("scope.awesomeThings.length") %>.equal(4);<% } %> diff --git a/app/templates/client/components/navbar/navbar(html).html b/app/templates/client/components/navbar/navbar(html).html index a93839562..ec9e4682d 100644 --- a/app/templates/client/components/navbar/navbar(html).html +++ b/app/templates/client/components/navbar/navbar(html).html @@ -11,18 +11,18 @@
diff --git a/app/templates/client/components/navbar/navbar(jade).jade b/app/templates/client/components/navbar/navbar(jade).jade index 7863f4e0a..5d7cb2795 100644 --- a/app/templates/client/components/navbar/navbar(jade).jade +++ b/app/templates/client/components/navbar/navbar(jade).jade @@ -10,25 +10,25 @@ div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarCtrl') div#navbar-main.navbar-collapse.collapse(collapse='isCollapsed') ul.nav.navbar-nav - li(ng-repeat='item in menu', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive(item.link)}'<% } %>) - a(<% if(filters.uirouter) { %>ui-sref='{{item.state}}'<% } else { %>ng-href='{{item.link}}'<% } %>) {{item.title}}<% if(filters.auth) { %> + li(ng-repeat='item in menu', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive(item.link)}'<% } %>) + a(<% if (filters.uirouter) { %>ui-sref='{{item.state}}'<% } else { %>ng-href='{{item.link}}'<% } %>) {{item.title}}<% if (filters.auth) { %> - li(ng-show='isAdmin()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/admin")}'<% } %>) - a(<% if(filters.uirouter) { %>ui-sref='admin'<% } else { %>href='/admin'<% } %>) Admin + li(ng-show='isAdmin()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/admin")}'<% } %>) + a(<% if (filters.uirouter) { %>ui-sref='admin'<% } else { %>href='/admin'<% } %>) Admin ul.nav.navbar-nav.navbar-right - li(ng-hide='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/signup")}'<% } %>) - a(<% if(filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) Sign up + li(ng-hide='isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/signup")}'<% } %>) + a(<% if (filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) Sign up - li(ng-hide='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/login")}'<% } %>) - a(<% if(filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) Login + li(ng-hide='isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/login")}'<% } %>) + a(<% if (filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) Login li(ng-show='isLoggedIn()') p.navbar-text Hello {{ getCurrentUser().name }} - li(ng-show='isLoggedIn()', <% if(filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/settings")}'<% } %>) - a(<% if(filters.uirouter) { %>ui-sref='settings'<% } else { %>href='/settings'<% } %>) + li(ng-show='isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: isActive("/settings")}'<% } %>) + a(<% if (filters.uirouter) { %>ui-sref='settings'<% } else { %>href='/settings'<% } %>) span.glyphicon.glyphicon-cog li(ng-show='isLoggedIn()') - a(<% if(filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %> \ No newline at end of file + a(<% if (filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %> \ No newline at end of file diff --git a/app/templates/client/components/navbar/navbar.controller(coffee).coffee b/app/templates/client/components/navbar/navbar.controller(coffee).coffee index 121437cf1..9dda1ae4b 100644 --- a/app/templates/client/components/navbar/navbar.controller(coffee).coffee +++ b/app/templates/client/components/navbar/navbar.controller(coffee).coffee @@ -1,12 +1,12 @@ 'use strict' angular.module '<%= scriptAppName %>' -.controller 'NavbarCtrl', ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if(filters.auth) {%>, Auth<% } %>) -> +.controller 'NavbarCtrl', ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if (filters.auth) {%>, Auth<% } %>) -> $scope.menu = [ title: 'Home' - <% if(filters.uirouter) { %>state: 'main'<% } else { %>link: '/'<% } %> + <% if (filters.uirouter) { %>state: 'main'<% } else { %>link: '/'<% } %> ] - $scope.isCollapsed = true<% if(filters.auth) {%> + $scope.isCollapsed = true<% if (filters.auth) {%> $scope.isLoggedIn = Auth.isLoggedIn $scope.isAdmin = Auth.isAdmin $scope.getCurrentUser = Auth.getCurrentUser<% } %><% if(!filters.uirouter) { %> diff --git a/app/templates/client/components/navbar/navbar.controller(js).js b/app/templates/client/components/navbar/navbar.controller(js).js index 2428ac15b..b3eef7cf6 100644 --- a/app/templates/client/components/navbar/navbar.controller(js).js +++ b/app/templates/client/components/navbar/navbar.controller(js).js @@ -1,13 +1,13 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .controller('NavbarCtrl', function ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if(filters.auth) {%>, Auth<% } %>) { + .controller('NavbarCtrl', function ($scope<% if(!filters.uirouter) { %>, $location<% } %><% if (filters.auth) {%>, Auth<% } %>) { $scope.menu = [{ 'title': 'Home', - <% if(filters.uirouter) { %>'state': 'main'<% } else { %>'link': '/'<% } %> + <% if (filters.uirouter) { %>'state': 'main'<% } else { %>'link': '/'<% } %> }]; - $scope.isCollapsed = true;<% if(filters.auth) {%> + $scope.isCollapsed = true;<% if (filters.auth) {%> $scope.isLoggedIn = Auth.isLoggedIn; $scope.isAdmin = Auth.isAdmin; $scope.getCurrentUser = Auth.getCurrentUser;<% } %><% if(!filters.uirouter) { %> diff --git a/app/templates/client/index.html b/app/templates/client/index.html index e823e372d..479a3f2a3 100644 --- a/app/templates/client/index.html +++ b/app/templates/client/index.html @@ -27,7 +27,7 @@ - <% if(filters.ngroute) { %>
<% } %><% if(filters.uirouter) { %>
<% } %> + <% if (filters.ngroute) { %>
<% } %><% if (filters.uirouter) { %>
<% } %> <% } %> diff --git a/app/templates/e2e/components/navbar/navbar.po.js b/app/templates/e2e/components/navbar/navbar.po.js index ee2ec1ada..62f407210 100644 --- a/app/templates/e2e/components/navbar/navbar.po.js +++ b/app/templates/e2e/components/navbar/navbar.po.js @@ -8,7 +8,7 @@ var NavbarComponent = function() { this.navbar = element(by.css('.navbar')); this.navbarHeader = this.navbar.element(by.css('.navbar-header')); - this.navbarNav = this.navbar.element(by.css('#navbar-main .nav.navbar-nav:not(.navbar-right)'));<% if(filters.auth) { %> + this.navbarNav = this.navbar.element(by.css('#navbar-main .nav.navbar-nav:not(.navbar-right)'));<% if (filters.auth) { %> this.navbarAccount = this.navbar.element(by.css('#navbar-main .nav.navbar-nav.navbar-right')); this.navbarAccountGreeting = this.navbarAccount.element(by.binding('Hello {{ getCurrentUser().name }}'));<% } %> }; diff --git a/app/templates/karma.conf.js b/app/templates/karma.conf.js index 6b6c6c477..ed4cd2955 100644 --- a/app/templates/karma.conf.js +++ b/app/templates/karma.conf.js @@ -6,8 +6,8 @@ module.exports = function(config) { // base path, that will be used to resolve files and exclude basePath: '', - // testing framework to use (jasmine/mocha/qunit/...)<% if(filters.jasmine) { %> - frameworks: ['jasmine'],<% } if(filters.mocha) { %> + // testing framework to use (jasmine/mocha/qunit/...)<% if (filters.jasmine) { %> + frameworks: ['jasmine'],<% } if (filters.mocha) { %> frameworks: ['mocha', 'chai', 'sinon-chai', 'chai-as-promised', 'chai-things'],<% } %> // list of files / patterns to load in the browser @@ -18,10 +18,10 @@ module.exports = function(config) { 'client/bower_components/angular-resource/angular-resource.js', 'client/bower_components/angular-cookies/angular-cookies.js', 'client/bower_components/angular-sanitize/angular-sanitize.js', - 'client/bower_components/angular-route/angular-route.js',<% if(filters.uibootstrap) { %> + 'client/bower_components/angular-route/angular-route.js',<% if (filters.uibootstrap) { %> 'client/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',<% } %> - 'client/bower_components/lodash/dist/lodash.compat.js',<% if(filters.socketio) { %> - 'client/bower_components/angular-socket-io/socket.js',<% } %><% if(filters.uirouter) { %> + 'client/bower_components/lodash/dist/lodash.compat.js',<% if (filters.socketio) { %> + 'client/bower_components/angular-socket-io/socket.js',<% } %><% if (filters.uirouter) { %> 'client/bower_components/angular-ui-router/release/angular-ui-router.js',<% } %> 'client/app/app.js', 'client/app/app.coffee', diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index 14f704b3d..f0061ff86 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -43,14 +43,14 @@ var config = { // Jasmine and Cucumber are fully supported as a test and assertion framework. // Mocha has limited beta support. You will need to include your own // assertion framework if working with mocha. - framework: '<% if(filters.jasmine) { %>jasmine<% } if(filters.mocha) { %>mocha<% } %>', -<% if(filters.jasmine) { %> + framework: '<% if (filters.jasmine) { %>jasmine<% } if (filters.mocha) { %>mocha<% } %>', +<% if (filters.jasmine) { %> // ----- Options to be passed to minijasminenode ----- // // See the full list at https://github.com/juliemr/minijasminenode jasmineNodeOpts: { defaultTimeoutInterval: 30000 - },<% } if(filters.mocha) { %> + },<% } if (filters.mocha) { %> // ----- Options to be passed to mocha ----- mochaOpts: { reporter: 'spec', @@ -63,7 +63,7 @@ var config = { serverConfig: require('./server/config/environment') }, - onPrepare: function() {<% if(filters.mocha) { %> + onPrepare: function() {<% if (filters.mocha) { %> // Load Mocha and Chai + plugins require('./mocha.conf'); diff --git a/app/templates/server/api/thing/index.js b/app/templates/server/api/thing/index.js index e77e80c5b..ea697d38b 100644 --- a/app/templates/server/api/thing/index.js +++ b/app/templates/server/api/thing/index.js @@ -5,7 +5,7 @@ var controller = require('./thing.controller'); var router = express.Router(); -router.get('/', controller.index);<% if(filters.mongoose) { %> +router.get('/', controller.index);<% if (filters.mongoose) { %> router.get('/:id', controller.show); router.post('/', controller.create); router.put('/:id', controller.update); diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js index 3c6c71fc2..899b22d79 100644 --- a/app/templates/server/api/thing/index.spec.js +++ b/app/templates/server/api/thing/index.spec.js @@ -3,7 +3,7 @@ var proxyquire = require('proxyquire').noPreserveCache(); var thingCtrlStub = { - index: 'thingCtrl.index'<% if(filters.mongoose) { %>, + index: 'thingCtrl.index'<% if (filters.mongoose) { %>, show: 'thingCtrl.show', create: 'thingCtrl.create', update: 'thingCtrl.update', @@ -11,7 +11,7 @@ var thingCtrlStub = { }; var routerStub = { - get: sinon.spy()<% if(filters.mongoose) { %>, + get: sinon.spy()<% if (filters.mongoose) { %>, put: sinon.spy(), patch: sinon.spy(), post: sinon.spy(), @@ -37,15 +37,19 @@ describe('Thing API Router:', function() { describe('GET /api/things', function() { it('should route to thing.controller.index', function() { - routerStub.get.withArgs('/', 'thingCtrl.index').should.have.been.calledOnce; + routerStub.get + .withArgs('/', 'thingCtrl.index') + .should.have.been.calledOnce; }); - });<% if(filters.mongoose) { %> + });<% if (filters.mongoose) { %> describe('GET /api/things/:id', function() { it('should route to thing.controller.show', function() { - routerStub.get.withArgs('/:id', 'thingCtrl.show').should.have.been.calledOnce; + routerStub.get + .withArgs('/:id', 'thingCtrl.show') + .should.have.been.calledOnce; }); }); @@ -53,7 +57,9 @@ describe('Thing API Router:', function() { describe('POST /api/things', function() { it('should route to thing.controller.create', function() { - routerStub.post.withArgs('/', 'thingCtrl.create').should.have.been.calledOnce; + routerStub.post + .withArgs('/', 'thingCtrl.create') + .should.have.been.calledOnce; }); }); @@ -61,7 +67,9 @@ describe('Thing API Router:', function() { describe('PUT /api/things/:id', function() { it('should route to thing.controller.update', function() { - routerStub.put.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + routerStub.put + .withArgs('/:id', 'thingCtrl.update') + .should.have.been.calledOnce; }); }); @@ -69,7 +77,9 @@ describe('Thing API Router:', function() { describe('PATCH /api/things/:id', function() { it('should route to thing.controller.update', function() { - routerStub.patch.withArgs('/:id', 'thingCtrl.update').should.have.been.calledOnce; + routerStub.patch + .withArgs('/:id', 'thingCtrl.update') + .should.have.been.calledOnce; }); }); @@ -77,7 +87,9 @@ describe('Thing API Router:', function() { describe('DELETE /api/things/:id', function() { it('should route to thing.controller.destroy', function() { - routerStub.delete.withArgs('/:id', 'thingCtrl.destroy').should.have.been.calledOnce; + routerStub.delete + .withArgs('/:id', 'thingCtrl.destroy') + .should.have.been.calledOnce; }); });<% } %> diff --git a/app/templates/server/api/thing/thing.controller.js b/app/templates/server/api/thing/thing.controller.js index 23bfd6937..710c7cd38 100644 --- a/app/templates/server/api/thing/thing.controller.js +++ b/app/templates/server/api/thing/thing.controller.js @@ -12,25 +12,25 @@ var _ = require('lodash'); var Thing = require('./thing.model'); -function handleError(res, statusCode){ +function handleError(res, statusCode) { statusCode = statusCode || 500; - return function(err){ + return function(err) { res.send(statusCode, err); }; } -function responseWithResult(res, statusCode){ +function responseWithResult(res, statusCode) { statusCode = statusCode || 200; - return function(entity){ - if(entity){ + return function(entity) { + if (entity) { return res.json(statusCode, entity); } }; } -function handleEntityNotFound(res){ - return function(entity){ - if(!entity){ +function handleEntityNotFound(res) { + return function(entity) { + if (!entity) { res.send(404); return null; } @@ -38,19 +38,19 @@ function handleEntityNotFound(res){ }; } -function saveUpdates(updates){ - return function(entity){ +function saveUpdates(updates) { + return function(entity) { var updated = _.merge(entity, updates); return updated.saveAsync() - .spread(function (updated) { + .spread(function(updated) { return updated; }); }; } -function removeEntity(res){ - return function (entity) { - if(entity){ +function removeEntity(res) { + return function(entity) { + if (entity) { return entity.removeAsync() .then(function() { return res.send(204); @@ -60,28 +60,31 @@ function removeEntity(res){ }<% } %> // Get list of things -exports.index = function(req, res) {<% if (!filters.mongoose) { %> - res.json([ - { - name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' +exports.index = function(req, res) {<% if(!filters.mongoose) { %> + res.json([{ + name : 'Development Tools', + info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + + 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' }, { - name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' + name : 'Server and Client integration', + info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' }, { - name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. Automatic injection of scripts and styles into your index.html' - }, { - name : 'Modular Structure', - info : 'Best practice client and server structures allow for more code reusability and maximum scalability' - }, { - name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript payload, minifies your scripts/css/images, and rewrites asset names for caching.' - },{ - name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift subgenerators' - } - ]);<% } if (filters.mongoose) { %> + name : 'Smart Build System', + info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + + 'Automatic injection of scripts and styles into your index.html' + }, { + name : 'Modular Structure', + info : 'Best practice client and server structures allow for more code reusability and ' + + 'maximum scalability' + }, { + name : 'Optimized Build', + info : 'Build process packs up your templates as a single JavaScript payload, minifies ' + + 'your scripts/css/images, and rewrites asset names for caching.' + }, { + name : 'Deployment Ready', + info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + + 'subgenerators' + }]);<% } if (filters.mongoose) { %> Thing.findAsync() .then(responseWithResult(res)) .catch(handleError(res));<% } %> @@ -104,7 +107,7 @@ exports.create = function(req, res) { // Updates an existing thing in the DB. exports.update = function(req, res) { - if(req.body._id) { + if (req.body._id) { delete req.body._id; } Thing.findByIdAsync(req.params.id) diff --git a/app/templates/server/api/thing/thing.integration.js b/app/templates/server/api/thing/thing.integration.js index 1140df7e9..de7ed7ff5 100644 --- a/app/templates/server/api/thing/thing.integration.js +++ b/app/templates/server/api/thing/thing.integration.js @@ -1,7 +1,7 @@ 'use strict'; var app = require('../../app'); -var request = require('supertest');<% if(filters.mongoose) { %> +var request = require('supertest');<% if (filters.mongoose) { %> var newThing;<% } %> @@ -16,7 +16,9 @@ describe('Thing API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } things = res.body; done(); }); @@ -26,7 +28,7 @@ describe('Thing API:', function() { things.should.be.instanceOf(Array); }); - });<% if(filters.mongoose) { %> + });<% if (filters.mongoose) { %> describe('POST /api/things', function() { beforeEach(function(done) { @@ -39,7 +41,9 @@ describe('Thing API:', function() { .expect(201) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } newThing = res.body; done(); }); @@ -61,7 +65,9 @@ describe('Thing API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } thing = res.body; done(); }); @@ -91,7 +97,9 @@ describe('Thing API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } updatedThing = res.body; done(); }); @@ -115,7 +123,9 @@ describe('Thing API:', function() { .delete('/api/things/' + newThing._id) .expect(204) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } done(); }); }); @@ -125,7 +135,9 @@ describe('Thing API:', function() { .delete('/api/things/' + newThing._id) .expect(404) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } done(); }); }); diff --git a/app/templates/server/api/thing/thing.model(mongoose).js b/app/templates/server/api/thing/thing.model(mongoose).js index a44bc710e..d1e6e49ea 100644 --- a/app/templates/server/api/thing/thing.model(mongoose).js +++ b/app/templates/server/api/thing/thing.model(mongoose).js @@ -1,7 +1,7 @@ 'use strict'; -var mongoose = require('mongoose-bird')(), - Schema = mongoose.Schema; +var mongoose = require('mongoose-bird')(); +var Schema = mongoose.Schema; var ThingSchema = new Schema({ name: String, diff --git a/app/templates/server/api/thing/thing.socket(socketio).js b/app/templates/server/api/thing/thing.socket(socketio).js index d38e73e0d..2d0171cdc 100644 --- a/app/templates/server/api/thing/thing.socket(socketio).js +++ b/app/templates/server/api/thing/thing.socket(socketio).js @@ -7,10 +7,10 @@ var thing = require('./thing.model'); exports.register = function(socket) { - thing.schema.post('save', function (doc) { + thing.schema.post('save', function(doc) { onSave(socket, doc); }); - thing.schema.post('remove', function (doc) { + thing.schema.post('remove', function(doc) { onRemove(socket, doc); }); }; diff --git a/app/templates/server/api/user(auth)/index.spec.js b/app/templates/server/api/user(auth)/index.spec.js index b2510aa00..d2ee914bd 100644 --- a/app/templates/server/api/user(auth)/index.spec.js +++ b/app/templates/server/api/user(auth)/index.spec.js @@ -47,7 +47,9 @@ describe('User API Router:', function() { describe('GET /api/users', function() { it('should verify admin role and route to user.controller.index', function() { - routerStub.get.withArgs('/', 'authService.hasRole.admin', 'userCtrl.index').should.have.been.calledOnce; + routerStub.get + .withArgs('/', 'authService.hasRole.admin', 'userCtrl.index') + .should.have.been.calledOnce; }); }); @@ -55,7 +57,9 @@ describe('User API Router:', function() { describe('DELETE /api/users/:id', function() { it('should verify admin role and route to user.controller.destroy', function() { - routerStub.delete.withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy').should.have.been.calledOnce; + routerStub.delete + .withArgs('/:id', 'authService.hasRole.admin', 'userCtrl.destroy') + .should.have.been.calledOnce; }); }); @@ -63,7 +67,9 @@ describe('User API Router:', function() { describe('GET /api/users/me', function() { it('should be authenticated and route to user.controller.me', function() { - routerStub.get.withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me').should.have.been.calledOnce; + routerStub.get + .withArgs('/me', 'authService.isAuthenticated', 'userCtrl.me') + .should.have.been.calledOnce; }); }); @@ -71,7 +77,9 @@ describe('User API Router:', function() { describe('PUT /api/users/:id/password', function() { it('should be authenticated and route to user.controller.changePassword', function() { - routerStub.put.withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword').should.have.been.calledOnce; + routerStub.put + .withArgs('/:id/password', 'authService.isAuthenticated', 'userCtrl.changePassword') + .should.have.been.calledOnce; }); }); @@ -79,7 +87,9 @@ describe('User API Router:', function() { describe('GET /api/users/:id', function() { it('should be authenticated and route to user.controller.show', function() { - routerStub.get.withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show').should.have.been.calledOnce; + routerStub.get + .withArgs('/:id', 'authService.isAuthenticated', 'userCtrl.show') + .should.have.been.calledOnce; }); }); @@ -87,7 +97,9 @@ describe('User API Router:', function() { describe('POST /api/users', function() { it('should route to user.controller.create', function() { - routerStub.post.withArgs('/', 'userCtrl.create').should.have.been.calledOnce; + routerStub.post + .withArgs('/', 'userCtrl.create') + .should.have.been.calledOnce; }); }); diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index ed0b1749c..793da0255 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -7,21 +7,21 @@ var jwt = require('jsonwebtoken'); var validationError = function(res, statusCode) { statusCode = statusCode || 422; - return function(err){ + return function(err) { res.json(statusCode, err); }; }; -function handleError(res, statusCode){ +function handleError(res, statusCode) { statusCode = statusCode || 500; - return function(err){ + return function(err) { res.send(statusCode, err); }; } -function respondWith(res, statusCode){ +function respondWith(res, statusCode) { statusCode = statusCode || 200; - return function(){ + return function() { res.send(statusCode); }; } @@ -32,7 +32,7 @@ function respondWith(res, statusCode){ */ exports.index = function(req, res) { User.findAsync({}, '-salt -hashedPassword') - .then(function (users) { + .then(function(users) { res.json(200, users); }) .catch(handleError(res)); @@ -41,13 +41,15 @@ exports.index = function(req, res) { /** * Creates a new user */ -exports.create = function (req, res, next) { +exports.create = function(req, res, next) { var newUser = new User(req.body); newUser.provider = 'local'; newUser.role = 'user'; newUser.saveAsync() .spread(function(user) { - var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresInMinutes: 60*5 }); + var token = jwt.sign({ _id: user._id }, config.secrets.session, { + expiresInMinutes: 60 * 5 + }); res.json({ token: token }); }) .catch(validationError(res)); @@ -56,17 +58,17 @@ exports.create = function (req, res, next) { /** * Get a single user */ -exports.show = function (req, res, next) { +exports.show = function(req, res, next) { var userId = req.params.id; User.findByIdAsync(userId) - .then(function (user) { - if(!user) { + .then(function(user) { + if (!user) { return res.send(401); } res.json(user.profile); }) - .catch(function(err){ + .catch(function(err) { return next(err); }); }; @@ -91,7 +93,7 @@ exports.changePassword = function(req, res, next) { User.findByIdAsync(userId) .then(function(user) { - if(user.authenticate(oldPass)) { + if (user.authenticate(oldPass)) { user.password = newPass; return user.saveAsync() .spread(respondWith(res, 200)) @@ -113,7 +115,9 @@ exports.me = function(req, res, next) { if (!user) { return res.json(401); } res.json(user); }) - .catch(function(err){ return next(err); }); + .catch(function(err) { + return next(err); + }); }; /** diff --git a/app/templates/server/api/user(auth)/user.integration.js b/app/templates/server/api/user(auth)/user.integration.js index 917acedd9..ee97d3051 100644 --- a/app/templates/server/api/user(auth)/user.integration.js +++ b/app/templates/server/api/user(auth)/user.integration.js @@ -17,7 +17,9 @@ describe('User API:', function() { }); user.save(function(err) { - if (err) return done(err); + if (err) { + return done(err); + } done(); }); }); diff --git a/app/templates/server/api/user(auth)/user.model.js b/app/templates/server/api/user(auth)/user.model.js index b90386886..201afb4bc 100644 --- a/app/templates/server/api/user(auth)/user.model.js +++ b/app/templates/server/api/user(auth)/user.model.js @@ -2,12 +2,15 @@ var mongoose = require('mongoose-bird')(); var Schema = mongoose.Schema; -var crypto = require('crypto');<% if(filters.oauth) { %> +var crypto = require('crypto');<% if (filters.oauth) { %> var authTypes = ['github', 'twitter', 'facebook', 'google'];<% } %> var UserSchema = new Schema({ name: String, - email: { type: String, lowercase: true }, + email: { + type: String, + lowercase: true + }, role: { type: String, default: 'user' @@ -53,9 +56,9 @@ UserSchema UserSchema .path('email') .validate(function(email) {<% if (filters.oauth) { %> - if (authTypes.indexOf(this.provider) !== -1){ + if (authTypes.indexOf(this.provider) !== -1) { return true; - } <% } %> + }<% } %> return email.length; }, 'Email cannot be blank'); @@ -63,9 +66,9 @@ UserSchema UserSchema .path('password') .validate(function(password) {<% if (filters.oauth) { %> - if (authTypes.indexOf(this.provider) !== -1){ + if (authTypes.indexOf(this.provider) !== -1) { return true; - } <% } %> + }<% } %> return password.length; }, 'Password cannot be blank'); @@ -74,20 +77,20 @@ UserSchema .path('email') .validate(function(value, respond) { var self = this; - return this.constructor.findOneAsync({email: value}) + return this.constructor.findOneAsync({ email: value }) .then(function(user) { - if(user) { - if(self.id === user.id) { + if (user) { + if (self.id === user.id) { return respond(true); } return respond(false); } return respond(true); }) - .catch(function(err){ + .catch(function(err) { throw err; }); -}, 'The specified email address is already in use.'); + }, 'The specified email address is already in use.'); var validatePresenceOf = function(value) { return value && value.length; @@ -100,17 +103,21 @@ UserSchema .pre('save', function(next) { // Handle new/update passwords if (this.password) { - if (!validatePresenceOf(this.password)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) + if (!validatePresenceOf(this.password)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) { next(new Error('Invalid password')); + } // Make salt with a callback var _this = this; this.makeSalt(function(saltErr, salt) { - if (saltErr) next(saltErr); + if (saltErr) { + next(saltErr); + } _this.salt = salt; - // Async hash _this.encryptPassword(_this.password, function(encryptErr, hashedPassword) { - if (encryptErr) next(encryptErr); + if (encryptErr) { + next(encryptErr); + } _this.password = hashedPassword; next(); }); @@ -127,22 +134,26 @@ UserSchema.methods = { /** * Authenticate - check if the passwords are the same * - * @param {String} plainText - * @callback {callback} Optional callback + * @param {String} password + * @param {Function} callback * @return {Boolean} * @api public */ authenticate: function(password, callback) { - if (!callback) + if (!callback) { return this.password === this.encryptPassword(password); + } var _this = this; this.encryptPassword(password, function(err, pwdGen) { - if (err) callback(err); + if (err) { + callback(err); + } if (_this.password === pwdGen) { callback(null, true); - } else { + } + else { callback(null, false); } }); @@ -152,7 +163,7 @@ UserSchema.methods = { * Make salt * * @param {Number} byteSize Optional salt byte size, default to 16 - * @callback {callback} Optional callback + * @param {Function} callback * @return {String} * @api public */ @@ -162,7 +173,8 @@ UserSchema.methods = { if (typeof arguments[0] === 'function') { callback = arguments[0]; byteSize = defaultByteSize; - } else if (typeof arguments[1] === 'function') { + } + else if (typeof arguments[1] === 'function') { callback = arguments[1]; } @@ -175,7 +187,9 @@ UserSchema.methods = { } return crypto.randomBytes(byteSize, function(err, salt) { - if (err) callback(err); + if (err) { + callback(err); + } return callback(null, salt.toString('base64')); }); }, @@ -184,7 +198,7 @@ UserSchema.methods = { * Encrypt password * * @param {String} password - * @callback {callback} Optional callback + * @param {Function} callback * @return {String} * @api public */ @@ -197,11 +211,15 @@ UserSchema.methods = { var defaultKeyLength = 64; var salt = new Buffer(this.salt, 'base64'); - if (!callback) - return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength).toString('base64'); + if (!callback) { + return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) + .toString('base64'); + } return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, function(err, key) { - if (err) callback(err); + if (err) { + callback(err); + } return callback(null, key.toString('base64')); }); } diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec.js index fe51ea2ea..16de6e2de 100644 --- a/app/templates/server/api/user(auth)/user.model.spec.js +++ b/app/templates/server/api/user(auth)/user.model.spec.js @@ -38,11 +38,11 @@ describe('User Model', function() { return user.saveAsync().should.be.rejected; }); - it("should authenticate user if password is valid", function() { + it('should authenticate user if password is valid', function() { user.authenticate('password').should.be.true; }); - it("should not authenticate user if password is invalid", function() { + it('should not authenticate user if password is invalid', function() { user.authenticate('blah').should.not.be.true; }); }); diff --git a/app/templates/server/app.js b/app/templates/server/app.js index 5369e94ef..632dd134f 100644 --- a/app/templates/server/app.js +++ b/app/templates/server/app.js @@ -15,7 +15,7 @@ var config = require('./config/environment'); mongoose.connect(config.mongo.uri, config.mongo.options); // Populate DB with sample data -if(config.seedDB) { require('./config/seed'); } +if (config.seedDB) { require('./config/seed'); } <% } %>// Setup server var app = express(); @@ -29,7 +29,7 @@ require('./config/express')(app); require('./routes')(app); // Start server -server.listen(config.port, config.ip, function () { +server.listen(config.port, config.ip, function() { console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); }); diff --git a/app/templates/server/auth(auth)/auth.service.js b/app/templates/server/auth(auth)/auth.service.js index 101dcc5c5..43ea2851f 100644 --- a/app/templates/server/auth(auth)/auth.service.js +++ b/app/templates/server/auth(auth)/auth.service.js @@ -7,7 +7,9 @@ var jwt = require('jsonwebtoken'); var expressJwt = require('express-jwt'); var compose = require('composable-middleware'); var User = require('../api/user/user.model'); -var validateJwt = expressJwt({ secret: config.secrets.session }); +var validateJwt = expressJwt({ + secret: config.secrets.session +}); /** * Attaches the user object to the request if authenticated @@ -18,7 +20,7 @@ function isAuthenticated() { // Validate jwt .use(function(req, res, next) { // allow access_token to be passed through query parameter as well - if(req.query && req.query.hasOwnProperty('access_token')) { + if (req.query && req.query.hasOwnProperty('access_token')) { req.headers.authorization = 'Bearer ' + req.query.access_token; } validateJwt(req, res, next); @@ -26,14 +28,14 @@ function isAuthenticated() { // Attach user to request .use(function(req, res, next) { User.findByIdAsync(req.user._id) - .then(function (user) { + .then(function(user) { if (!user) { return res.send(401); } req.user = user; next(); }) - .catch(function(err){ + .catch(function(err) { return next(err); }); }); @@ -50,7 +52,8 @@ function hasRole(roleRequired) { return compose() .use(isAuthenticated()) .use(function meetsRequirements(req, res, next) { - if (config.userRoles.indexOf(req.user.role) >= config.userRoles.indexOf(roleRequired)) { + if (config.userRoles.indexOf(req.user.role) >= + config.userRoles.indexOf(roleRequired)) { next(); } else { @@ -63,7 +66,9 @@ function hasRole(roleRequired) { * Returns a jwt token signed by the app secret */ function signToken(id) { - return jwt.sign({ _id: id }, config.secrets.session, { expiresInMinutes: 60*5 }); + return jwt.sign({ _id: id }, config.secrets.session, { + expiresInMinutes: 60 * 5 + }); } /** @@ -71,7 +76,9 @@ function signToken(id) { */ function setTokenCookie(req, res) { if (!req.user) { - return res.json(404, { message: 'Something went wrong, please try again.'}); + return res.json(404, { + message: 'Something went wrong, please try again.' + }); } var token = signToken(req.user._id, req.user.role); res.cookie('token', JSON.stringify(token)); diff --git a/app/templates/server/auth(auth)/facebook(facebookAuth)/index.js b/app/templates/server/auth(auth)/facebook(facebookAuth)/index.js index 4a6f87886..f13d463e1 100644 --- a/app/templates/server/auth(auth)/facebook(facebookAuth)/index.js +++ b/app/templates/server/auth(auth)/facebook(facebookAuth)/index.js @@ -18,4 +18,4 @@ router session: false }), auth.setTokenCookie); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js b/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js index 90ae48939..b29d74c69 100644 --- a/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js +++ b/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js @@ -1,37 +1,38 @@ var passport = require('passport'); var FacebookStrategy = require('passport-facebook').Strategy; -exports.setup = function (User, config) { +exports.setup = function(User, config) { passport.use(new FacebookStrategy({ - clientID: config.facebook.clientID, - clientSecret: config.facebook.clientSecret, - callbackURL: config.facebook.callbackURL + clientID: config.facebook.clientID, + clientSecret: config.facebook.clientSecret, + callbackURL: config.facebook.callbackURL + }, + function(accessToken, refreshToken, profile, done) { + User.findOne({ + 'facebook.id': profile.id }, - function(accessToken, refreshToken, profile, done) { - User.findOne({ - 'facebook.id': profile.id - }, - function(err, user) { - if (err) { - return done(err); - } - if (!user) { - user = new User({ - name: profile.displayName, - email: profile.emails[0].value, - role: 'user', - username: profile.username, - provider: 'facebook', - facebook: profile._json - }); - user.save(function(err) { - if (err) done(err); - return done(err, user); - }); - } else { + function(err, user) { + if (err) { + return done(err); + } + if (!user) { + user = new User({ + name: profile.displayName, + email: profile.emails[0].value, + role: 'user', + username: profile.username, + provider: 'facebook', + facebook: profile._json + }); + user.save(function(err) { + if (err) { + done(err); + } return done(err, user); - } - }) - } - )); -}; \ No newline at end of file + }); + } else { + return done(err, user); + } + }) + })); +}; diff --git a/app/templates/server/auth(auth)/google(googleAuth)/index.js b/app/templates/server/auth(auth)/google(googleAuth)/index.js index 9b1ce39fe..673c22db4 100644 --- a/app/templates/server/auth(auth)/google(googleAuth)/index.js +++ b/app/templates/server/auth(auth)/google(googleAuth)/index.js @@ -21,4 +21,4 @@ router session: false }), auth.setTokenCookie); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/auth(auth)/google(googleAuth)/passport.js b/app/templates/server/auth(auth)/google(googleAuth)/passport.js index d304e8ac9..0e7a3602d 100644 --- a/app/templates/server/auth(auth)/google(googleAuth)/passport.js +++ b/app/templates/server/auth(auth)/google(googleAuth)/passport.js @@ -1,33 +1,34 @@ var passport = require('passport'); var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; -exports.setup = function (User, config) { +exports.setup = function(User, config) { passport.use(new GoogleStrategy({ - clientID: config.google.clientID, - clientSecret: config.google.clientSecret, - callbackURL: config.google.callbackURL - }, - function(accessToken, refreshToken, profile, done) { - User.findOne({ - 'google.id': profile.id - }, function(err, user) { - if (!user) { - user = new User({ - name: profile.displayName, - email: profile.emails[0].value, - role: 'user', - username: profile.username, - provider: 'google', - google: profile._json - }); - user.save(function(err) { - if (err) done(err); - return done(err, user); - }); - } else { + clientID: config.google.clientID, + clientSecret: config.google.clientSecret, + callbackURL: config.google.callbackURL + }, + function(accessToken, refreshToken, profile, done) { + User.findOne({ + 'google.id': profile.id + }, function(err, user) { + if (!user) { + user = new User({ + name: profile.displayName, + email: profile.emails[0].value, + role: 'user', + username: profile.username, + provider: 'google', + google: profile._json + }); + user.save(function(err) { + if (err) { + done(err); + } return done(err, user); - } - }); - } - )); + }); + } else { + return done(err, user); + } + }); + })); }; diff --git a/app/templates/server/auth(auth)/index.js b/app/templates/server/auth(auth)/index.js index e3e6c87ad..b930ad93f 100644 --- a/app/templates/server/auth(auth)/index.js +++ b/app/templates/server/auth(auth)/index.js @@ -18,4 +18,4 @@ router.use('/facebook', require('./facebook'));<% } %><% if (filters.twitterAuth router.use('/twitter', require('./twitter'));<% } %><% if (filters.googleAuth) { %> router.use('/google', require('./google'));<% } %> -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/auth(auth)/local/index.js b/app/templates/server/auth(auth)/local/index.js index 8bf88a046..3a9198d11 100644 --- a/app/templates/server/auth(auth)/local/index.js +++ b/app/templates/server/auth(auth)/local/index.js @@ -7,14 +7,20 @@ var auth = require('../auth.service'); var router = express.Router(); router.post('/', function(req, res, next) { - passport.authenticate('local', function (err, user, info) { + passport.authenticate('local', function(err, user, info) { var error = err || info; - if (error) return res.json(401, error); - if (!user) return res.json(404, {message: 'Something went wrong, please try again.'}); + if (error) { + return res.json(401, error); + } + if (!user) { + return res.json(404, { + message: 'Something went wrong, please try again.' + }); + } var token = auth.signToken(user._id, user.role); - res.json({token: token}); + res.json({ token: token }); })(req, res, next) }); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/auth(auth)/local/passport.js b/app/templates/server/auth(auth)/local/passport.js index 4221f8786..f4898b73a 100644 --- a/app/templates/server/auth(auth)/local/passport.js +++ b/app/templates/server/auth(auth)/local/passport.js @@ -1,29 +1,35 @@ var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; -exports.setup = function (User, config) { +exports.setup = function(User, config) { passport.use(new LocalStrategy({ - usernameField: 'email', - passwordField: 'password' // this is the virtual field on the model - }, - function(email, password, done) { - User.findOne({ - email: email.toLowerCase() - }, function(err, user) { - if (err) return done(err); + usernameField: 'email', + passwordField: 'password' // this is the virtual field on the model + }, function(email, password, done) { + User.findOne({ + email: email.toLowerCase() + }, function(err, user) { + if (err) { + return done(err); + } - if (!user) { - return done(null, false, { message: 'This email is not registered.' }); - } - user.authenticate(password, function(authError, authenticated) { - if (authError) return done(authError); - if (!authenticated) { - return done(null, false, { message: 'This password is not correct.' }); - } else { - return done(null, user); - } + if (!user) { + return done(null, false, { + message: 'This email is not registered.' }); + } + user.authenticate(password, function(authError, authenticated) { + if (authError) { + return done(authError); + } + if (!authenticated) { + return done(null, false, { + message: 'This password is not correct.' + }); + } else { + return done(null, user); + } }); - } - )); + }); + })); }; diff --git a/app/templates/server/auth(auth)/twitter(twitterAuth)/index.js b/app/templates/server/auth(auth)/twitter(twitterAuth)/index.js index 8360247b8..8e6f32b5d 100644 --- a/app/templates/server/auth(auth)/twitter(twitterAuth)/index.js +++ b/app/templates/server/auth(auth)/twitter(twitterAuth)/index.js @@ -17,4 +17,4 @@ router session: false }), auth.setTokenCookie); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js b/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js index a2eb4a537..7428e8afd 100644 --- a/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js +++ b/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js @@ -1,4 +1,4 @@ -exports.setup = function (User, config) { +exports.setup = function(User, config) { var passport = require('passport'); var TwitterStrategy = require('passport-twitter').Strategy; @@ -23,13 +23,14 @@ exports.setup = function (User, config) { twitter: profile._json }); user.save(function(err) { - if (err) return done(err); + if (err) { + return done(err); + } return done(err, user); }); } else { return done(err, user); } }); - } - )); -}; \ No newline at end of file + })); +}; diff --git a/app/templates/server/components/errors/index.js b/app/templates/server/components/errors/index.js index 4c5a57c99..52dba3749 100644 --- a/app/templates/server/components/errors/index.js +++ b/app/templates/server/components/errors/index.js @@ -12,8 +12,10 @@ module.exports[404] = function pageNotFound(req, res) { }; res.status(result.status); - res.render(viewFilePath, function (err) { - if (err) { return res.json(result, result.status); } + res.render(viewFilePath, function(err) { + if (err) { + return res.json(result, result.status); + } res.render(viewFilePath); }); diff --git a/app/templates/server/config/_local.env.js b/app/templates/server/config/_local.env.js index c24fffd3a..12b78192e 100644 --- a/app/templates/server/config/_local.env.js +++ b/app/templates/server/config/_local.env.js @@ -7,7 +7,7 @@ module.exports = { DOMAIN: 'http://localhost:9000', - SESSION_SECRET: "<%= _.slugify(appname) + '-secret' %>",<% if (filters.facebookAuth) { %> + SESSION_SECRET: '<%= _.slugify(appname) + "-secret" %>',<% if (filters.facebookAuth) { %> FACEBOOK_ID: 'app-id', FACEBOOK_SECRET: 'secret',<% } if (filters.twitterAuth) { %> diff --git a/app/templates/server/config/environment/index.js b/app/templates/server/config/environment/index.js index 11d85f4de..2476a7e8c 100644 --- a/app/templates/server/config/environment/index.js +++ b/app/templates/server/config/environment/index.js @@ -4,7 +4,7 @@ var path = require('path'); var _ = require('lodash'); function requiredProcessEnv(name) { - if(!process.env[name]) { + if (!process.env[name]) { throw new Error('You must set the ' + name + ' environment variable'); } return process.env[name]; @@ -40,19 +40,19 @@ var all = { } } }, -<% if(filters.facebookAuth) { %> +<% if (filters.facebookAuth) { %> facebook: { clientID: process.env.FACEBOOK_ID || 'id', clientSecret: process.env.FACEBOOK_SECRET || 'secret', callbackURL: (process.env.DOMAIN || '') + '/auth/facebook/callback' }, -<% } %><% if(filters.twitterAuth) { %> +<% } %><% if (filters.twitterAuth) { %> twitter: { clientID: process.env.TWITTER_ID || 'id', clientSecret: process.env.TWITTER_SECRET || 'secret', callbackURL: (process.env.DOMAIN || '') + '/auth/twitter/callback' }, -<% } %><% if(filters.googleAuth) { %> +<% } %><% if (filters.googleAuth) { %> google: { clientID: process.env.GOOGLE_ID || 'id', clientSecret: process.env.GOOGLE_SECRET || 'secret', @@ -64,4 +64,4 @@ var all = { // ============================================== module.exports = _.merge( all, - require('./' + process.env.NODE_ENV + '.js') || {}); \ No newline at end of file + require('./' + process.env.NODE_ENV + '.js') || {}); diff --git a/app/templates/server/config/environment/production.js b/app/templates/server/config/environment/production.js index 1704df619..e0b77bf97 100644 --- a/app/templates/server/config/environment/production.js +++ b/app/templates/server/config/environment/production.js @@ -17,7 +17,8 @@ module.exports = { mongo: { uri: process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || - process.env.OPENSHIFT_MONGODB_DB_URL+process.env.OPENSHIFT_APP_NAME || + process.env.OPENSHIFT_MONGODB_DB_URL + + process.env.OPENSHIFT_APP_NAME || 'mongodb://localhost/<%= _.slugify(appname) %>' } -}; \ No newline at end of file +}; diff --git a/app/templates/server/config/environment/test.js b/app/templates/server/config/environment/test.js index 711c98660..6ead6e1aa 100644 --- a/app/templates/server/config/environment/test.js +++ b/app/templates/server/config/environment/test.js @@ -7,4 +7,4 @@ module.exports = { mongo: { uri: 'mongodb://localhost/<%= _.slugify(appname) %>-test' } -}; \ No newline at end of file +}; diff --git a/app/templates/server/config/express.js b/app/templates/server/config/express.js index 2403780f1..463f637fd 100644 --- a/app/templates/server/config/express.js +++ b/app/templates/server/config/express.js @@ -30,8 +30,8 @@ module.exports = function(app) { app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(methodOverride()); - app.use(cookieParser()); - <% if (filters.auth) { %>app.use(passport.initialize());<% } %><% if (filters.twitterAuth) { %> + app.use(cookieParser());<% if (filters.auth) { %> + app.use(passport.initialize());<% } %><% if (filters.twitterAuth) { %> // Persist sessions with mongoStore // We need to enable sessions for passport twitter because its an oauth 1.0 strategy @@ -41,7 +41,7 @@ module.exports = function(app) { saveUninitialized: true, store: new mongoStore({ mongoose_connection: mongoose.connection }) })); - <% } %> +<% } %> if ('production' === env) { app.use(favicon(path.join(config.root, 'public', 'favicon.ico'))); app.use(express.static(path.join(config.root, 'public'))); diff --git a/app/templates/server/config/seed(mongoose).js b/app/templates/server/config/seed(mongoose).js index 6d56010b6..1f6945d8d 100644 --- a/app/templates/server/config/seed(mongoose).js +++ b/app/templates/server/config/seed(mongoose).js @@ -6,35 +6,40 @@ 'use strict'; var Thing = require('../api/thing/thing.model'); -<% if (filters.auth) { %> -var User = require('../api/user/user.model'); -<% } %> +<% if (filters.auth) { %>var User = require('../api/user/user.model');<% } %> Thing.find({}).removeAsync() .then(function() { Thing.create({ name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' + info : 'Integration with popular tools such as Bower, Grunt, Karma, ' + + 'Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, ' + + 'Stylus, Sass, CoffeeScript, and Less.' }, { name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' + info : 'Built with a powerful and fun stack: MongoDB, Express, ' + + 'AngularJS, and Node.' }, { name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. Automatic injection of scripts and styles into your index.html' - }, { + info : 'Build system ignores `spec` files, allowing you to keep ' + + 'tests alongside code. Automatic injection of scripts and ' + + 'styles into your index.html' + }, { name : 'Modular Structure', - info : 'Best practice client and server structures allow for more code reusability and maximum scalability' - }, { + info : 'Best practice client and server structures allow for more ' + + 'code reusability and maximum scalability' + }, { name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript payload, minifies your scripts/css/images, and rewrites asset names for caching.' - },{ + info : 'Build process packs up your templates as a single JavaScript ' + + 'payload, minifies your scripts/css/images, and rewrites asset ' + + 'names for caching.' + }, { name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift subgenerators' + info : 'Easily deploy your app to Heroku or Openshift with the heroku ' + + 'and openshift subgenerators' }); }); - <% if (filters.auth) { %> - User.find({}).removeAsync() .then(function() { User.create({ @@ -49,8 +54,7 @@ User.find({}).removeAsync() email: 'admin@admin.com', password: 'admin' }, function() { - console.log('finished populating users'); - } - ); + console.log('finished populating users'); + }); }); -<% } %> +<% } %> \ No newline at end of file diff --git a/app/templates/server/config/socketio(socketio).js b/app/templates/server/config/socketio(socketio).js index 2fbbc07d6..446b49dff 100644 --- a/app/templates/server/config/socketio(socketio).js +++ b/app/templates/server/config/socketio(socketio).js @@ -13,7 +13,7 @@ function onDisconnect(socket) { // When the user connects.. perform this function onConnect(socket) { // When the client emits 'info', this listens and executes - socket.on('info', function (data) { + socket.on('info', function(data) { console.info('[%s] %s', socket.address, JSON.stringify(data, null, 2)); }); @@ -21,7 +21,7 @@ function onConnect(socket) { require('../api/thing/thing.socket').register(socket); } -module.exports = function (socketio) { +module.exports = function(socketio) { // socket.io (v1.x.x) is powered by debug. // In order to see all the debug output, set DEBUG (in server/config/local.env.js) to including the desired scope. // @@ -37,15 +37,16 @@ module.exports = function (socketio) { // handshake: true // })); - socketio.on('connection', function (socket) { - socket.address = socket.handshake.address !== null ? - socket.handshake.address.address + ':' + socket.handshake.address.port : - process.env.DOMAIN; + socketio.on('connection', function(socket) { + socket.address = + socket.handshake.address !== null ? + socket.handshake.address.address + ':' + socket.handshake.address.port : + process.env.DOMAIN; socket.connectedAt = new Date(); // Call onDisconnect. - socket.on('disconnect', function () { + socket.on('disconnect', function() { onDisconnect(socket); console.info('[%s] DISCONNECTED', socket.address); }); @@ -54,4 +55,4 @@ module.exports = function (socketio) { onConnect(socket); console.info('[%s] CONNECTED', socket.address); }); -}; \ No newline at end of file +}; diff --git a/app/templates/server/routes.js b/app/templates/server/routes.js index c2b5acb2e..fff0e5416 100644 --- a/app/templates/server/routes.js +++ b/app/templates/server/routes.js @@ -9,11 +9,11 @@ var errors = require('./components/errors'); module.exports = function(app) { // Insert routes below - app.use('/api/things', require('./api/thing')); - <% if (filters.auth) { %>app.use('/api/users', require('./api/user')); + app.use('/api/things', require('./api/thing'));<% if (filters.auth) { %> + app.use('/api/users', require('./api/user')); app.use('/auth', require('./auth')); - <% } %> +<% } %> // All undefined asset or api routes should return a 404 app.route('/:url(api|auth|components|app|bower_components|assets)/*') .get(errors[404]); diff --git a/endpoint/templates/index.js b/endpoint/templates/index.js index 03fdc9779..3f8c592a6 100644 --- a/endpoint/templates/index.js +++ b/endpoint/templates/index.js @@ -12,4 +12,4 @@ router.put('/:id', controller.update); router.patch('/:id', controller.update); router.delete('/:id', controller.destroy);<% } %> -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index fd1086b15..ccd15ec7e 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -37,7 +37,9 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>', function() { it('should route to <%= name %>.controller.index', function() { - routerStub.get.withArgs('/', '<%= name %>Ctrl.index').should.have.been.calledOnce; + routerStub.get + .withArgs('/', '<%= name %>Ctrl.index') + .should.have.been.calledOnce; }); });<% if(filters.mongoose) { %> @@ -45,7 +47,9 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>/:id', function() { it('should route to <%= name %>.controller.show', function() { - routerStub.get.withArgs('/:id', '<%= name %>Ctrl.show').should.have.been.calledOnce; + routerStub.get + .withArgs('/:id', '<%= name %>Ctrl.show') + .should.have.been.calledOnce; }); }); @@ -53,7 +57,9 @@ describe('<%= classedName %> API Router:', function() { describe('POST <%= route %>', function() { it('should route to <%= name %>.controller.create', function() { - routerStub.post.withArgs('/', '<%= name %>Ctrl.create').should.have.been.calledOnce; + routerStub.post + .withArgs('/', '<%= name %>Ctrl.create') + .should.have.been.calledOnce; }); }); @@ -61,7 +67,9 @@ describe('<%= classedName %> API Router:', function() { describe('PUT <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - routerStub.put.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + routerStub.put + .withArgs('/:id', '<%= name %>Ctrl.update') + .should.have.been.calledOnce; }); }); @@ -69,7 +77,9 @@ describe('<%= classedName %> API Router:', function() { describe('PATCH <%= route %>/:id', function() { it('should route to <%= name %>.controller.update', function() { - routerStub.patch.withArgs('/:id', '<%= name %>Ctrl.update').should.have.been.calledOnce; + routerStub.patch + .withArgs('/:id', '<%= name %>Ctrl.update') + .should.have.been.calledOnce; }); }); @@ -77,7 +87,9 @@ describe('<%= classedName %> API Router:', function() { describe('DELETE <%= route %>/:id', function() { it('should route to <%= name %>.controller.destroy', function() { - routerStub.delete.withArgs('/:id', '<%= name %>Ctrl.destroy').should.have.been.calledOnce; + routerStub.delete + .withArgs('/:id', '<%= name %>Ctrl.destroy') + .should.have.been.calledOnce; }); });<% } %> diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 87dd641de..9cdfb0fb0 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -1,27 +1,27 @@ -'use strict';<% if (filters.mongoose) { %> +'use strict';<% if(filters.mongoose) { %> var _ = require('lodash'); var <%= classedName %> = require('./<%= name %>.model'); -function handleError(res, statusCode){ +function handleError(res, statusCode) { statusCode = statusCode || 500; - return function(err){ + return function(err) { res.send(statusCode, err); }; } -function responseWithResult(res, statusCode){ +function responseWithResult(res, statusCode) { statusCode = statusCode || 200; - return function(entity){ - if(entity){ + return function(entity) { + if (entity) { return res.json(statusCode, entity); } }; } -function handleEntityNotFound(res){ - return function(entity){ - if(!entity){ +function handleEntityNotFound(res) { + return function(entity) { + if (!entity) { res.send(404); return null; } @@ -29,19 +29,19 @@ function handleEntityNotFound(res){ }; } -function saveUpdates(updates){ - return function(entity){ +function saveUpdates(updates) { + return function(entity) { var updated = _.merge(entity, updates); return updated.saveAsync() - .spread(function (updated) { + .spread(function(updated) { return updated; }); }; } -function removeEntity(res){ - return function (entity) { - if(entity){ +function removeEntity(res) { + return function(entity) { + if (entity) { return entity.removeAsync() .then(function() { return res.send(204); @@ -51,12 +51,12 @@ function removeEntity(res){ }<% } %> // Gets list of <%= name %>s from the DB. -exports.index = function(req, res) {<% if (!filters.mongoose) { %> +exports.index = function(req, res) {<% if(!filters.mongoose) { %> res.json([]);<% } if (filters.mongoose) { %> <%= classedName %>.findAsync() .then(responseWithResult(res)) .catch(handleError(res));<% } %> -};<% if (filters.mongoose) { %> +};<% if(filters.mongoose) { %> // Gets a single <%= name %> from the DB. exports.show = function(req, res) { @@ -75,7 +75,7 @@ exports.create = function(req, res) { // Updates an existing <%= name %> in the DB. exports.update = function(req, res) { - if(req.body._id) { + if (req.body._id) { delete req.body._id; } <%= classedName %>.findByIdAsync(req.params.id) diff --git a/endpoint/templates/name.integration.js b/endpoint/templates/name.integration.js index f168f1ca9..a377456a4 100644 --- a/endpoint/templates/name.integration.js +++ b/endpoint/templates/name.integration.js @@ -16,7 +16,9 @@ describe('<%= classedName %> API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } <%= cameledName %>s = res.body; done(); }); @@ -39,7 +41,9 @@ describe('<%= classedName %> API:', function() { .expect(201) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } new<%= classedName %> = res.body; done(); }); @@ -61,7 +65,9 @@ describe('<%= classedName %> API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } <%= cameledName %> = res.body; done(); }); @@ -91,7 +97,9 @@ describe('<%= classedName %> API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } updated<%= classedName %> = res.body; done(); }); @@ -115,7 +123,9 @@ describe('<%= classedName %> API:', function() { .delete('<%= route %>/' + new<%= classedName %>._id) .expect(204) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } done(); }); }); @@ -125,7 +135,9 @@ describe('<%= classedName %> API:', function() { .delete('<%= route %>/' + new<%= classedName %>._id) .expect(404) .end(function(err, res) { - if (err) return done(err); + if (err) { + return done(err); + } done(); }); }); diff --git a/endpoint/templates/name.model(mongoose).js b/endpoint/templates/name.model(mongoose).js index 9b23d9d41..ac7f7f72a 100644 --- a/endpoint/templates/name.model(mongoose).js +++ b/endpoint/templates/name.model(mongoose).js @@ -1,7 +1,7 @@ 'use strict'; -var mongoose = require('mongoose-bird')(), - Schema = mongoose.Schema; +var mongoose = require('mongoose-bird')(); +var Schema = mongoose.Schema; var <%= classedName %>Schema = new Schema({ name: String, diff --git a/endpoint/templates/name.socket(socketio).js b/endpoint/templates/name.socket(socketio).js index aabdadeb8..260c80720 100644 --- a/endpoint/templates/name.socket(socketio).js +++ b/endpoint/templates/name.socket(socketio).js @@ -7,10 +7,10 @@ var <%= classedName %> = require('./<%= name %>.model'); exports.register = function(socket) { - <%= classedName %>.schema.post('save', function (doc) { + <%= classedName %>.schema.post('save', function(doc) { onSave(socket, doc); }); - <%= classedName %>.schema.post('remove', function (doc) { + <%= classedName %>.schema.post('remove', function(doc) { onRemove(socket, doc); }); }; @@ -21,4 +21,4 @@ function onSave(socket, doc, cb) { function onRemove(socket, doc, cb) { socket.emit('<%= name %>:remove', doc); -} \ No newline at end of file +} diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 7db1d4afe..9301c9332 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -206,6 +206,7 @@ describe('angular-fullstack generator', function () { '.gitattributes', '.gitignore', '.travis.yml', + '.jscs.json', '.yo-rc.json', 'Gruntfile.js', 'package.json', @@ -339,6 +340,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); + it('should pass jscs', function(done) { + runTest('grunt jscs', this, done); + }); + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -347,6 +352,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass jscs with generated endpoint', function(done) { + runTest('grunt jscs', this, done, 'foo'); + }); + it('should pass lint with generated endpoint', function(done) { runTest('grunt jshint', this, done, 'foo'); }); @@ -427,6 +436,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); + it('should pass jscs', function(done) { + runTest('grunt jscs', this, done); + }); + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -435,6 +448,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass jscs with generated endpoint', function(done) { + runTest('grunt jscs', this, done, 'foo'); + }); + it('should pass lint with generated snake-case endpoint', function(done) { runTest('grunt jshint', this, done, 'foo-bar'); }); @@ -486,6 +503,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); + it('should pass jscs', function(done) { + runTest('grunt jscs', this, done); + }); + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); @@ -494,6 +515,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done); }); + it('should pass jscs with generated endpoint', function(done) { + runTest('grunt jscs', this, done, 'foo'); + }); + it('should pass lint with generated endpoint', function(done) { runTest('grunt jshint', this, done, 'foo'); }); @@ -544,6 +569,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:client', this, done); }); + it('should pass jscs', function(done) { + runTest('grunt jscs', this, done); + }); + it('should pass lint', function(done) { runTest('grunt jshint', this, done); }); From 9cdcc90a19dcef98bd30a1b80ab96c4f47684f2d Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 28 Sep 2014 16:08:58 -0600 Subject: [PATCH 046/201] fix(server): server should launch in dev mode if production env var is not specified fixes #590 --- app/templates/Gruntfile.js | 30 +++++++++++++------------- app/templates/server/config/express.js | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 224e84c66..274aacbb9 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -287,10 +287,10 @@ module.exports = function (grunt) { dist: { files: { src: [ - '<%%= yeoman.dist %>/public/{,*/}*.js', - '<%%= yeoman.dist %>/public/{,*/}*.css', - '<%%= yeoman.dist %>/public/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', - '<%%= yeoman.dist %>/public/assets/fonts/*' + '<%%= yeoman.dist %>/client/{,*/}*.js', + '<%%= yeoman.dist %>/client/{,*/}*.css', + '<%%= yeoman.dist %>/client/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', + '<%%= yeoman.dist %>/client/assets/fonts/*' ] } } @@ -302,19 +302,19 @@ module.exports = function (grunt) { useminPrepare: { html: ['<%%= yeoman.client %>/index.html'], options: { - dest: '<%%= yeoman.dist %>/public' + dest: '<%%= yeoman.dist %>/client' } }, // Performs rewrites based on rev and the useminPrepare configuration usemin: { - html: ['<%%= yeoman.dist %>/public/{,*/}*.html'], - css: ['<%%= yeoman.dist %>/public/{,*/}*.css'], - js: ['<%%= yeoman.dist %>/public/{,*/}*.js'], + html: ['<%%= yeoman.dist %>/client/{,*/}*.html'], + css: ['<%%= yeoman.dist %>/client/{,*/}*.css'], + js: ['<%%= yeoman.dist %>/client/{,*/}*.js'], options: { assetsDirs: [ - '<%%= yeoman.dist %>/public', - '<%%= yeoman.dist %>/public/assets/images' + '<%%= yeoman.dist %>/client', + '<%%= yeoman.dist %>/client/assets/images' ], // This is so we update image references in our ng-templates patterns: { @@ -332,7 +332,7 @@ module.exports = function (grunt) { expand: true, cwd: '<%%= yeoman.client %>/assets/images', src: '{,*/}*.{png,jpg,jpeg,gif}', - dest: '<%%= yeoman.dist %>/public/assets/images' + dest: '<%%= yeoman.dist %>/client/assets/images' }] } }, @@ -343,7 +343,7 @@ module.exports = function (grunt) { expand: true, cwd: '<%%= yeoman.client %>/assets/images', src: '{,*/}*.svg', - dest: '<%%= yeoman.dist %>/public/assets/images' + dest: '<%%= yeoman.dist %>/client/assets/images' }] } }, @@ -392,7 +392,7 @@ module.exports = function (grunt) { // Replace Google CDN references cdnify: { dist: { - html: ['<%%= yeoman.dist %>/public/*.html'] + html: ['<%%= yeoman.dist %>/client/*.html'] } }, @@ -403,7 +403,7 @@ module.exports = function (grunt) { expand: true, dot: true, cwd: '<%%= yeoman.client %>', - dest: '<%%= yeoman.dist %>/public', + dest: '<%%= yeoman.dist %>/client', src: [ '*.{ico,png,txt}', '.htaccess', @@ -415,7 +415,7 @@ module.exports = function (grunt) { }, { expand: true, cwd: '.tmp/images', - dest: '<%%= yeoman.dist %>/public/assets/images', + dest: '<%%= yeoman.dist %>/client/assets/images', src: ['generated/*'] }, { expand: true, diff --git a/app/templates/server/config/express.js b/app/templates/server/config/express.js index 463f637fd..67e5398f9 100644 --- a/app/templates/server/config/express.js +++ b/app/templates/server/config/express.js @@ -43,9 +43,9 @@ module.exports = function(app) { })); <% } %> if ('production' === env) { - app.use(favicon(path.join(config.root, 'public', 'favicon.ico'))); - app.use(express.static(path.join(config.root, 'public'))); - app.set('appPath', config.root + '/public'); + app.use(favicon(path.join(config.root, 'client', 'favicon.ico'))); + app.use(express.static(path.join(config.root, 'client'))); + app.set('appPath', config.root + '/client'); app.use(morgan('dev')); } From a5edbcdf1a9a7cbb13511e908fdf8df1abbdacb2 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 28 Sep 2014 16:54:34 -0600 Subject: [PATCH 047/201] fix test framework options when scaffolding with existing project --- Gruntfile.js | 1 + app/index.js | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 8edbe3ccd..f204733b5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -139,6 +139,7 @@ module.exports = function (grunt) { bootstrap: true, uibootstrap: true, mongoose: true, + testing: 'jasmine', auth: true, oauth: ['googleAuth', 'twitterAuth'], socketio: true diff --git a/app/index.js b/app/index.js index 7dcee4d55..81c9e40b7 100644 --- a/app/index.js +++ b/app/index.js @@ -52,15 +52,23 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }], function (answers) { this.skipConfig = answers.skipConfig; + this.filters = this._.defaults(this.config.get('filters'), { + bootstrap: true, + uibootstrap: true, + jasmine: true + }); + // NOTE: temp(?) fix for #403 - if(typeof this.oauth==='undefined') { + if(typeof this.filters.oauth==='undefined') { var strategies = Object.keys(this.filters).filter(function(key) { return key.match(/Auth$/) && key; }); - if(strategies.length) this.config.set('oauth', true); + if(strategies.length) this.filters.oauth = true; } + this.config.forceSave(); + cb(); }.bind(this)); } else { @@ -228,9 +236,17 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ } }], function (answers) { this.filters[answers.testing] = true; - if (this.filters.mocha) { + if (answers.testing === 'mocha') { + this.filters.jasmine = false; + this.filters.should = false; + this.filters.expect = false; this.filters[answers.chai] = true; } + if (answers.testing === 'jasmine') { + this.filters.mocha = false; + this.filters.should = false; + this.filters.expect = false; + } cb(); }.bind(this)); @@ -289,11 +305,6 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, ngModules: function() { - this.filters = this._.defaults(this.config.get('filters'), { - bootstrap: true, - uibootstrap: true - }); - var angModules = [ "'ngCookies'", "'ngResource'", From 639131387ce08032d51d1698c86baab709d1f8a7 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 28 Sep 2014 17:21:53 -0600 Subject: [PATCH 048/201] add test for #403 --- test/fixtures/.yo-rc.json | 3 ++- test/test-file-creation.js | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/test/fixtures/.yo-rc.json b/test/fixtures/.yo-rc.json index b4b338ac4..9ab655e54 100644 --- a/test/fixtures/.yo-rc.json +++ b/test/fixtures/.yo-rc.json @@ -13,7 +13,8 @@ "uirouter": true, "socketio": true, "mongoose": true, - "auth": true + "auth": true, + "googleAuth": true } } } \ No newline at end of file diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 9301c9332..c8db89456 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -389,12 +389,34 @@ describe('angular-fullstack generator', function () { gen.run({}, function () { helpers.assertFile([ 'client/app/main/main.less', - 'client/app/main/main.coffee' + 'client/app/main/main.coffee', + 'server/auth/google/passport.js' ]); done(); }); }); + it('should add oauth option if existing config had oauth strategy selected', function(done) { + this.timeout(60000); + fs.copySync(__dirname + '/fixtures/.yo-rc.json', __dirname + '/temp/.yo-rc.json'); + var gen = helpers.createGenerator('angular-fullstack:app', [ + '../../app', + [ + helpers.createDummyGenerator(), + 'ng-component:app' + ] + ]); + gen.options['skip-install'] = true; + helpers.mockPrompt(gen, { + skipConfig: true + }); + gen.run({}, function () { + var yoConfig = require(__dirname + '/temp/.yo-rc.json'); + expect(yoConfig['generator-angular-fullstack'].filters.oauth).to.be.true; + done(); + }); + }); + it('should generate expected files', function (done) { gen.run({}, function () { helpers.assertFile(genFiles(defaultOptions)); From 92858565aaa67b95ebd0d082aad308b2956f934c Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 28 Sep 2014 17:46:02 -0600 Subject: [PATCH 049/201] test(gen): add tests for running the e2e tests in production mode --- app/templates/Gruntfile.js | 41 +++++++++++++------- app/templates/e2e/main/main.spec(jasmine).js | 2 +- app/templates/e2e/main/main.spec(mocha).js | 2 +- test/test-file-creation.js | 16 ++++++++ 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 224e84c66..5adde704c 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -856,20 +856,33 @@ module.exports = function (grunt) { } else if (target === 'e2e') { - return grunt.task.run([ - 'clean:server', - 'env:all', - 'env:test',<% if (filters.stylus) { %> - 'injector:stylus', <% } %><% if (filters.less) { %> - 'injector:less', <% } %><% if (filters.sass) { %> - 'injector:sass', <% } %> - 'concurrent:test', - 'injector', - 'wiredep', - 'autoprefixer', - 'express:dev', - 'protractor' - ]); + + if (option === 'prod') { + return grunt.task.run([ + 'build', + 'env:all', + 'env:prod', + 'express:prod', + 'protractor' + ]); + } + + else { + return grunt.task.run([ + 'clean:server', + 'env:all', + 'env:test',<% if (filters.stylus) { %> + 'injector:stylus', <% } %><% if (filters.less) { %> + 'injector:less', <% } %><% if (filters.sass) { %> + 'injector:sass', <% } %> + 'concurrent:test', + 'injector', + 'wiredep', + 'autoprefixer', + 'express:dev', + 'protractor' + ]); + } } else if (target === 'coverage') { diff --git a/app/templates/e2e/main/main.spec(jasmine).js b/app/templates/e2e/main/main.spec(jasmine).js index 61745a8de..59456e4e8 100644 --- a/app/templates/e2e/main/main.spec(jasmine).js +++ b/app/templates/e2e/main/main.spec(jasmine).js @@ -10,7 +10,7 @@ describe('Main View', function() { it('should include jumbotron with correct data', function() { expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); - expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); + expect(page.imgEl.getAttribute('src')).toMatch(/yeoman.png$/); expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); }); }); diff --git a/app/templates/e2e/main/main.spec(mocha).js b/app/templates/e2e/main/main.spec(mocha).js index 1962ba765..e734af3a0 100644 --- a/app/templates/e2e/main/main.spec(mocha).js +++ b/app/templates/e2e/main/main.spec(mocha).js @@ -10,7 +10,7 @@ describe('Main View', function() { it('should include jumbotron with correct data', function() { <%= does("page.h1El.getText()") %>.eventually.equal('\'Allo, \'Allo!'); - <%= does("page.imgEl.getAttribute('src')") %>.eventually.match(/assets\/images\/yeoman.png$/); + <%= does("page.imgEl.getAttribute('src')") %>.eventually.match(/yeoman.png$/); <%= does("page.imgEl.getAttribute('alt')") %>.eventually.equal('I\'m Yeoman'); }); }); diff --git a/test/test-file-creation.js b/test/test-file-creation.js index c8db89456..c47173f4a 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -433,6 +433,10 @@ describe('angular-fullstack generator', function () { it('should run e2e tests successfully', function(done) { runTest('grunt test:e2e', this, done, 240000); }); + + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); }); describe('with other preprocessors and oauth', function() { @@ -498,6 +502,10 @@ describe('angular-fullstack generator', function () { it('should run e2e tests successfully', function(done) { runTest('grunt test:e2e', this, done, 240000); }); + + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); }); describe('with other preprocessors and no server options', function() { @@ -565,6 +573,10 @@ describe('angular-fullstack generator', function () { it('should run e2e tests successfully', function(done) { runTest('grunt test:e2e', this, done, 240000); }); + + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); }); describe('with no preprocessors and no server options', function() { @@ -619,6 +631,10 @@ describe('angular-fullstack generator', function () { it('should run e2e tests successfully', function(done) { runTest('grunt test:e2e', this, done, 240000); }); + + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); }); }); }); From add986f584c0081843db4d6c6966eaebf631e871 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Sun, 28 Sep 2014 18:59:54 -0600 Subject: [PATCH 050/201] remove production e2e tests because issues with node 0.11.x --- test/test-file-creation.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index c47173f4a..5a239790f 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -434,9 +434,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + //it('should run e2e tests successfully for production app', function(done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); }); describe('with other preprocessors and oauth', function() { @@ -503,9 +503,6 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); }); describe('with other preprocessors and no server options', function() { @@ -574,9 +571,6 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); }); describe('with no preprocessors and no server options', function() { @@ -632,9 +626,6 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); }); }); }); From 68b34f3e9333760a7cbdaa8659d43ac3feb6aee2 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Wed, 1 Oct 2014 19:22:05 -0600 Subject: [PATCH 051/201] add production e2e tests back in, only test against node 0.10.x closes #604 --- .travis.yml | 1 - test/test-file-creation.js | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 598a4b2ae..6646824d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - '0.10' - - '0.11.13' env: global: - SAUCE_USERNAME=fullstack_ci diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 5a239790f..bdb479829 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -434,9 +434,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - //it('should run e2e tests successfully for production app', function(done) { - // runTest('grunt test:e2e:prod', this, done, 240000); - //}); + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); }); describe('with other preprocessors and oauth', function() { @@ -503,6 +503,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + }); describe('with other preprocessors and no server options', function() { @@ -571,6 +575,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + }); describe('with no preprocessors and no server options', function() { @@ -626,6 +634,10 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + }); }); }); From a84f644dd95b32287e7904efbee3c6cdb624c427 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Wed, 1 Oct 2014 20:34:47 -0600 Subject: [PATCH 052/201] test(gen): fix grunt test false positives #closes 606 --- test/test-file-creation.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index bdb479829..e2fdd0e42 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -90,25 +90,17 @@ describe('angular-fullstack generator', function () { self.timeout(timeout || 60000); var execFn = function() { - exec(cmd, function(error, stdout, stderr) { - switch(cmd) { - case 'grunt jshint': - case 'grunt jscs': - expect(stdout).to.contain('Done, without errors.'); - break; - case 'grunt test:client': - case 'grunt test:e2e': - expect(stdout, 'Client tests failed \n' + stdout).to.contain('Done, without errors.'); - break; - case 'grunt test:server': - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - break; - default: - expect(stderr).to.be.empty; + var cmdCode; + var cp = exec(cmd, function(error, stdout, stderr) { + if(cmdCode !== 0) { + console.error(stdout); + throw new Error('Error running command: ' + cmd); } - cb(); }); + cp.on('exit', function (code) { + cmdCode = code; + }); }; if (endpoint) { From 95152ceb2f20762e2f3a8840f31efb2aa64f81b5 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Wed, 1 Oct 2014 21:01:00 -0600 Subject: [PATCH 053/201] test(gen): add grunt test:fast task to generator, for skipping e2e tests --- Gruntfile.js | 18 ++++++++++++ package.json | 1 + test/test-file-creation.js | 56 ++++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index f204733b5..c81bffa5c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -58,6 +58,11 @@ module.exports = function (grunt) { }, all: ['Gruntfile.js', '*/index.js'] }, + env: { + fast: { + SKIP_E2E: true + } + }, mochaTest: { test: { src: [ @@ -252,6 +257,19 @@ module.exports = function (grunt) { 'installFixtures', 'mochaTest' ]); + grunt.registerTask('test', function(target, option) { + if (target === 'fast') { + grunt.task.run([ + 'env:fast' + ]); + } + + return grunt.task.run([ + 'updateFixtures', + 'installFixtures', + 'mochaTest' + ]) + }); grunt.registerTask('demo', [ 'clean:demo', diff --git a/package.json b/package.json index ec61432c7..c9e55b21b 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "grunt-contrib-clean": "^0.6.0", "grunt-contrib-jshint": "^0.10.0", "grunt-conventional-changelog": "~1.0.0", + "grunt-env": "^0.4.1", "grunt-mocha-test": "^0.11.0", "grunt-release": "~0.6.0", "load-grunt-tasks": "~0.2.0", diff --git a/test/test-file-creation.js b/test/test-file-creation.js index e2fdd0e42..bd3a3b146 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -422,13 +422,15 @@ describe('angular-fullstack generator', function () { }); }); - it('should run e2e tests successfully', function(done) { - runTest('grunt test:e2e', this, done, 240000); - }); + if(!process.env.SKIP_E2E) { + it('should run e2e tests successfully', function(done) { + runTest('grunt test:e2e', this, done, 240000); + }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + it('should run e2e tests successfully for production app', function(done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + } }); describe('with other preprocessors and oauth', function() { @@ -491,13 +493,15 @@ describe('angular-fullstack generator', function () { }); }); - it('should run e2e tests successfully', function(done) { - runTest('grunt test:e2e', this, done, 240000); - }); + if(!process.env.SKIP_E2E) { + it('should run e2e tests successfully', function (done) { + runTest('grunt test:e2e', this, done, 240000); + }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + it('should run e2e tests successfully for production app', function (done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + } }); @@ -563,13 +567,15 @@ describe('angular-fullstack generator', function () { }); }); - it('should run e2e tests successfully', function(done) { - runTest('grunt test:e2e', this, done, 240000); - }); + if(!process.env.SKIP_E2E) { + it('should run e2e tests successfully', function (done) { + runTest('grunt test:e2e', this, done, 240000); + }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + it('should run e2e tests successfully for production app', function (done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + } }); @@ -622,13 +628,15 @@ describe('angular-fullstack generator', function () { }); }); - it('should run e2e tests successfully', function(done) { - runTest('grunt test:e2e', this, done, 240000); - }); + if(!process.env.SKIP_E2E) { + it('should run e2e tests successfully', function (done) { + runTest('grunt test:e2e', this, done, 240000); + }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + it('should run e2e tests successfully for production app', function (done) { + runTest('grunt test:e2e:prod', this, done, 240000); + }); + } }); }); From 09b4b601b8ddae9d9cd66e0f10ae285210642a56 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Wed, 1 Oct 2014 21:18:18 -0600 Subject: [PATCH 054/201] comment out e2e production tests again because of flaky results --- test/test-file-creation.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index bd3a3b146..f9ab7183b 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -498,9 +498,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function (done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + //it('should run e2e tests successfully for production app', function (done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); } }); @@ -572,9 +572,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function (done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + //it('should run e2e tests successfully for production app', function (done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); } }); @@ -633,9 +633,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function (done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + //it('should run e2e tests successfully for production app', function (done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); } }); From 499bc8db0117e8866b021f43b632936f63410b87 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Wed, 1 Oct 2014 21:39:55 -0600 Subject: [PATCH 055/201] missed one test that should have been commented out --- test/test-file-creation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index f9ab7183b..99f5c28f8 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -427,9 +427,9 @@ describe('angular-fullstack generator', function () { runTest('grunt test:e2e', this, done, 240000); }); - it('should run e2e tests successfully for production app', function(done) { - runTest('grunt test:e2e:prod', this, done, 240000); - }); + //it('should run e2e tests successfully for production app', function(done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); } }); From f29e907d4388e8a615b61077984c00c9f202820a Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Thu, 2 Oct 2014 21:25:04 -0600 Subject: [PATCH 056/201] fix appPath for serving index.html --- app/templates/server/config/express.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/templates/server/config/express.js b/app/templates/server/config/express.js index 67e5398f9..f44999c1e 100644 --- a/app/templates/server/config/express.js +++ b/app/templates/server/config/express.js @@ -42,18 +42,18 @@ module.exports = function(app) { store: new mongoStore({ mongoose_connection: mongoose.connection }) })); <% } %> + app.set('appPath', path.join(config.root, 'client')); + if ('production' === env) { app.use(favicon(path.join(config.root, 'client', 'favicon.ico'))); - app.use(express.static(path.join(config.root, 'client'))); - app.set('appPath', config.root + '/client'); + app.use(express.static(app.get('appPath'))); app.use(morgan('dev')); } if ('development' === env || 'test' === env) { app.use(require('connect-livereload')()); app.use(express.static(path.join(config.root, '.tmp'))); - app.use(express.static(path.join(config.root, 'client'))); - app.set('appPath', 'client'); + app.use(express.static(app.get('appPath'))); app.use(morgan('dev')); app.use(errorHandler()); // Error handler - has to be last } From 8c9f0f934b4567b646ef88578de0c6adfea15eb1 Mon Sep 17 00:00:00 2001 From: gintsgints Date: Sun, 28 Sep 2014 12:33:35 +0300 Subject: [PATCH 057/201] test(gen): use path.normalize to be windows aware - change function assertOnlyFiles to use a different local variable from global module name - path. - show expected files when a test fails - use path.normalize before search in the array Closes #601 --- test/test-file-creation.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 99f5c28f8..2fef6a3c9 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -42,20 +42,20 @@ describe('angular-fullstack generator', function () { * * @param {Array} expectedFiles - array of files * @param {Function} done - callback(error{Error}) - * @param {String} path - top level path to assert files at (optional) + * @param {String} topLevelPath - top level path to assert files at (optional) * @param {Array} skip - array of paths to skip/ignore (optional) * */ - function assertOnlyFiles(expectedFiles, done, path, skip) { - path = path || './'; + function assertOnlyFiles(expectedFiles, done, topLevelPath, skip) { + topLevelPath = topLevelPath || './'; skip = skip || ['node_modules', 'client/bower_components']; - recursiveReadDir(path, skip, function(err, actualFiles) { + recursiveReadDir(topLevelPath, skip, function(err, actualFiles) { if (err) { return done(err); } var files = actualFiles.concat(); expectedFiles.forEach(function(file, i) { - var index = files.indexOf(file); + var index = files.indexOf(path.normalize(file)); if (index >= 0) { files.splice(index, 1); } @@ -63,7 +63,7 @@ describe('angular-fullstack generator', function () { if (files.length !== 0) { err = new Error('unexpected files found'); - err.expected = ''; + err.expected = expectedFiles.join('\n'); err.actual = files.join('\n'); return done(err); } From 6a196e21036dead1046794a7be4a309832a552bd Mon Sep 17 00:00:00 2001 From: Thiago Sigrist Date: Wed, 22 Oct 2014 20:03:04 -0200 Subject: [PATCH 058/201] fix(deps): use angular ~1.2 before migrated to 1.3 Change angular version spec from ">=1.2.*" to "~1.2" to ensure generator tests run before migration to 1.3 is completed. Closes #654. --- app/templates/_bower.json | 14 +++++++------- test/test-file-creation.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/templates/_bower.json b/app/templates/_bower.json index 8d2e66a8a..4f9167ed6 100644 --- a/app/templates/_bower.json +++ b/app/templates/_bower.json @@ -2,15 +2,15 @@ "name": "<%= _.slugify(_.humanize(appname)) %>", "version": "0.0.0", "dependencies": { - "angular": ">=1.2.*", + "angular": "~1.2", "json3": "~3.3.1", "es5-shim": "~3.0.1",<% if(filters.bootstrap) { %><% if (filters.sass) { %> "bootstrap-sass-official": "~3.1.1",<% } %> "bootstrap": "~3.1.1",<% } %> - "angular-resource": ">=1.2.*", - "angular-cookies": ">=1.2.*", - "angular-sanitize": ">=1.2.*",<% if (filters.ngroute) { %> - "angular-route": ">=1.2.*",<% } %><% if (filters.uibootstrap) { %> + "angular-resource": "~1.2", + "angular-cookies": "~1.2", + "angular-sanitize": "~1.2",<% if (filters.ngroute) { %> + "angular-route": "~1.2",<% } %><% if (filters.uibootstrap) { %> "angular-bootstrap": "~0.11.0",<% } %> "font-awesome": ">=4.1.0", "lodash": "~2.4.1"<% if (filters.socketio) { %>, @@ -18,7 +18,7 @@ "angular-ui-router": "~0.2.10"<% } %> }, "devDependencies": { - "angular-mocks": ">=1.2.*", - "angular-scenario": ">=1.2.*" + "angular-mocks": "~1.2", + "angular-scenario": "~1.2" } } diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 2fef6a3c9..6164b690b 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -314,6 +314,41 @@ describe('angular-fullstack generator', function () { }.bind(this)); }); + describe('making sure test fixtures are present', function() { + + it('should have package.json in fixtures', function() { + helpers.assertFile([ + path.join(__dirname, 'fixtures', 'package.json') + ]); + }); + + it('should have bower.json in fixtures', function() { + helpers.assertFile([ + path.join(__dirname, 'fixtures', 'bower.json') + ]); + }); + + it('should have all npm packages in fixtures/node_modules', function() { + var packageJson = require('./fixtures/package.json'); + var deps = Object.keys(packageJson.dependencies); + deps = deps.concat(Object.keys(packageJson.devDependencies)); + deps = deps.map(function(dep) { + return path.join(__dirname, 'fixtures', 'node_modules', dep); + }); + helpers.assertFile(deps); + }); + + it('should have all bower packages in fixtures/bower_components', function() { + var bowerJson = require('./fixtures/bower.json'); + var deps = Object.keys(bowerJson.dependencies); + deps = deps.concat(Object.keys(bowerJson.devDependencies)); + deps = deps.map(function(dep) { + return path.join(__dirname, 'fixtures', 'bower_components', dep); + }); + helpers.assertFile(deps); + }); + }); + describe('running app', function() { beforeEach(function() { From dedf46c7a0664d5ea5a9f0686cbfa5593fdbc6d1 Mon Sep 17 00:00:00 2001 From: Vasil Velichkov Date: Wed, 26 Nov 2014 02:05:16 +0200 Subject: [PATCH 059/201] fix(openshift): fix processing of rhc app show output rhc returns the following text when application is not found $ rhc app show test Application 'test' not found. --- openshift/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openshift/index.js b/openshift/index.js index 518806b08..7929c0e09 100644 --- a/openshift/index.js +++ b/openshift/index.js @@ -107,7 +107,7 @@ Generator.prototype.rhcAppShow = function rhcAppShow() { this.abort = true; } // No remote found - else if (stdout.search('not found.') < 0) { + else if (stdout.search('not found.') >= 0) { console.log('No existing app found.'); } // Error From 943120e04c454abf2e0e6afc7965318d75c006b0 Mon Sep 17 00:00:00 2001 From: Thiago Sigrist Date: Wed, 26 Nov 2014 10:50:22 -0200 Subject: [PATCH 060/201] feat(server): add support for sequelize Closes #414. --- app/index.js | 55 +++- app/templates/_package.json | 8 +- .../signup/signup.controller(coffee).coffee | 10 +- .../signup/signup.controller(js).js | 12 +- .../app/main/main.controller(coffee).coffee | 2 +- .../client/app/main/main.controller(js).js | 2 +- .../login/login.spec(jasmine).js | 11 +- .../account(auth)/login/login.spec(mocha).js | 14 +- .../logout/logout.spec(jasmine).js | 11 +- .../logout/logout.spec(mocha).js | 14 +- .../signup/signup.spec(jasmine).js | 8 +- .../signup/signup.spec(mocha).js | 11 +- app/templates/protractor.conf.js | 4 +- app/templates/server/api/thing/index.js | 2 +- app/templates/server/api/thing/index.spec.js | 6 +- ...troller.js => thing.controller(models).js} | 78 +++--- .../api/thing/thing.controller(noModels).js | 38 +++ .../server/api/thing/thing.integration.js | 6 +- ...ose).js => thing.model(mongooseModels).js} | 0 .../api/thing/thing.model(sequelizeModels).js | 15 ++ .../api/thing/thing.socket(socketio).js | 21 +- .../server/api/user(auth)/user.controller.js | 65 ++++- .../server/api/user(auth)/user.integration.js | 25 +- ...model.js => user.model(mongooseModels).js} | 0 .../user(auth)/user.model(sequelizeModels).js | 235 ++++++++++++++++++ ....js => user.model.spec(mongooseModels).js} | 0 .../user.model.spec(sequelizeModels).js | 52 ++++ app/templates/server/app.js | 31 ++- .../server/auth(auth)/auth.service.js | 16 +- .../facebook(facebookAuth)/passport.js | 52 ++-- .../auth(auth)/google(googleAuth)/passport.js | 50 ++-- app/templates/server/auth(auth)/index.js | 5 +- .../server/auth(auth)/local/passport.js | 33 ++- .../twitter(twitterAuth)/passport.js | 49 ++-- .../server/config/environment/development.js | 10 + .../server/config/environment/test.js | 10 + app/templates/server/config/express.js | 10 +- .../{seed(mongoose).js => seed(models).js} | 36 ++- .../server/sqldb(sequelize)/index.js | 35 +++ endpoint/index.js | 42 ++++ endpoint/templates/name.model(sequelize).js | 15 ++ endpoint/templates/name.socket(socketio).js | 21 +- test/test-file-creation.js | 94 ++++++- 43 files changed, 974 insertions(+), 240 deletions(-) rename app/templates/server/api/thing/{thing.controller.js => thing.controller(models).js} (52%) create mode 100644 app/templates/server/api/thing/thing.controller(noModels).js rename app/templates/server/api/thing/{thing.model(mongoose).js => thing.model(mongooseModels).js} (100%) create mode 100644 app/templates/server/api/thing/thing.model(sequelizeModels).js rename app/templates/server/api/user(auth)/{user.model.js => user.model(mongooseModels).js} (100%) create mode 100644 app/templates/server/api/user(auth)/user.model(sequelizeModels).js rename app/templates/server/api/user(auth)/{user.model.spec.js => user.model.spec(mongooseModels).js} (100%) create mode 100644 app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js rename app/templates/server/config/{seed(mongoose).js => seed(models).js} (64%) create mode 100644 app/templates/server/sqldb(sequelize)/index.js create mode 100644 endpoint/templates/name.model(sequelize).js diff --git a/app/index.js b/app/index.js index 81c9e40b7..15aaf737f 100644 --- a/app/index.js +++ b/app/index.js @@ -145,15 +145,38 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.log('\n# Server\n'); this.prompt([{ - type: 'confirm', - name: 'mongoose', - message: 'Would you like to use mongoDB with Mongoose for data modeling?' + type: 'checkbox', + name: 'odms', + message: 'What would you like to use for data modeling?', + choices: [ + { + value: 'mongoose', + name: 'Mongoose (MongoDB)', + checked: true + }, + { + value: 'sequelize', + name: 'Sequelize (MySQL, SQLite, MariaDB, PostgreSQL)', + checked: false + } + ] + }, { + type: 'list', + name: 'models', + message: 'What would you like to use for the default models?', + choices: [ 'Mongoose', 'Sequelize' ], + filter: function( val ) { + return val.toLowerCase(); + }, + when: function(answers) { + return answers.odms && answers.odms.length > 1; + } }, { type: 'confirm', name: 'auth', message: 'Would you scaffold out an authentication boilerplate?', when: function (answers) { - return answers.mongoose; + return answers.odms && answers.odms.length !== 0; } }, { type: 'checkbox', @@ -183,15 +206,29 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ type: 'confirm', name: 'socketio', message: 'Would you like to use socket.io?', - // to-do: should not be dependent on mongoose + // to-do: should not be dependent on ODMs when: function (answers) { - return answers.mongoose; + return answers.odms && answers.odms.length !== 0; }, default: true }], function (answers) { if(answers.socketio) this.filters.socketio = true; - if(answers.mongoose) this.filters.mongoose = true; if(answers.auth) this.filters.auth = true; + if(answers.odms.length > 0) { + var models; + if(!answers.models) { + models = answers.odms[0]; + } else { + models = answers.models; + } + this.filters.models = true; + this.filters[models + 'Models'] = true; + answers.odms.forEach(function(odm) { + this.filters[odm] = true; + }.bind(this)); + } else { + this.filters.noModels = true; + } if(answers.oauth) { if(answers.oauth.length) this.filters.oauth = true; answers.oauth.forEach(function(oauthStrategy) { @@ -265,6 +302,10 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.config.set('registerSocketsFile', 'server/config/socketio.js'); this.config.set('socketsNeedle', '// Insert sockets below'); + this.config.set('insertModels', true); + this.config.set('registerModelsFile', 'server/sqldb/index.js'); + this.config.set('modelsNeedle', '// Insert models below'); + this.config.set('filters', this.filters); this.config.forceSave(); }, diff --git a/app/templates/_package.json b/app/templates/_package.json index d33133187..1666ea8b0 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -16,7 +16,9 @@ "jade": "~1.2.0",<% } %><% if (filters.html) { %> "ejs": "~0.8.4",<% } %><% if (filters.mongoose) { %> "mongoose": "~3.8.8", - "mongoose-bird": "~0.0.1",<% } %><% if (filters.auth) { %> + "mongoose-bird": "~0.0.1",<% } %><% if (filters.sequelize) { %> + "sequelize": "^2.0.0-rc2", + "sqlite3": "~3.0.2",<% } %><% if (filters.auth) { %> "jsonwebtoken": "^0.3.0", "express-jwt": "^0.1.3", "passport": "~0.2.0", @@ -24,8 +26,8 @@ "passport-facebook": "latest",<% } %><% if (filters.twitterAuth) { %> "passport-twitter": "latest",<% } %><% if (filters.googleAuth) { %> "passport-google-oauth": "latest",<% } %> - "composable-middleware": "^0.3.0", - "connect-mongo": "^0.4.1"<% if (filters.socketio) { %>, + "composable-middleware": "^0.3.0"<% if (filters.mongoose) { %>, + "connect-mongo": "^0.4.1"<% } %><% if (filters.socketio) { %>, "socket.io": "^1.0.6", "socket.io-client": "^1.0.6", "socketio-jwt": "^2.0.2"<% } %> diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee index 3d96f3bf5..d167b7e30 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee +++ b/app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee @@ -20,11 +20,17 @@ angular.module '<%= scriptAppName %>' .catch (err) -> err = err.data $scope.errors = {} - +<% if (filters.mongooseModels) { %> # Update validity of form fields that match the mongoose errors angular.forEach err.errors, (error, field) -> form[field].$setValidity 'mongoose', false - $scope.errors[field] = error.message + $scope.errors[field] = error.message<% } + if (filters.sequelizeModels) { %> + # Update validity of form fields that match the sequelize errors + if err.name + angular.forEach err.fields, (field) -> + form[field].$setValidity 'mongoose', false + $scope.errors[field] = err.message<% } %> <% if (filters.oauth) {%> $scope.loginOauth = (provider) -> $window.location.href = '/auth/' + provider<% } %> diff --git a/app/templates/client/app/account(auth)/signup/signup.controller(js).js b/app/templates/client/app/account(auth)/signup/signup.controller(js).js index 7e93a6949..346eb7ea7 100644 --- a/app/templates/client/app/account(auth)/signup/signup.controller(js).js +++ b/app/templates/client/app/account(auth)/signup/signup.controller(js).js @@ -21,12 +21,20 @@ angular.module('<%= scriptAppName %>') .catch(function(err) { err = err.data; $scope.errors = {}; - +<% if (filters.mongooseModels) { %> // Update validity of form fields that match the mongoose errors angular.forEach(err.errors, function(error, field) { form[field].$setValidity('mongoose', false); $scope.errors[field] = error.message; - }); + });<% } + if (filters.sequelizeModels) { %> + // Update validity of form fields that match the sequelize errors + if (err.name) { + angular.forEach(err.fields, function(field) { + form[field].$setValidity('mongoose', false); + $scope.errors[field] = err.message; + }); + }<% } %> }); } }; diff --git a/app/templates/client/app/main/main.controller(coffee).coffee b/app/templates/client/app/main/main.controller(coffee).coffee index 3dffae2f7..4b04a951b 100644 --- a/app/templates/client/app/main/main.controller(coffee).coffee +++ b/app/templates/client/app/main/main.controller(coffee).coffee @@ -7,7 +7,7 @@ angular.module '<%= scriptAppName %>' $http.get('/api/things').success (awesomeThings) -> $scope.awesomeThings = awesomeThings <% if (filters.socketio) { %>socket.syncUpdates 'thing', $scope.awesomeThings<% } %> -<% if (filters.mongoose) { %> +<% if (filters.models) { %> $scope.addThing = -> return if $scope.newThing is '' $http.post '/api/things', diff --git a/app/templates/client/app/main/main.controller(js).js b/app/templates/client/app/main/main.controller(js).js index 8164a90dc..345d9909d 100644 --- a/app/templates/client/app/main/main.controller(js).js +++ b/app/templates/client/app/main/main.controller(js).js @@ -8,7 +8,7 @@ angular.module('<%= scriptAppName %>') $scope.awesomeThings = awesomeThings;<% if (filters.socketio) { %> socket.syncUpdates('thing', $scope.awesomeThings);<% } %> }); -<% if (filters.mongoose) { %> +<% if (filters.models) { %> $scope.addThing = function() { if ($scope.newThing === '') { return; diff --git a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js index d3f0d48ed..e690c2601 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Login View', function() { var page; @@ -18,9 +19,11 @@ describe('Login View', function() { }; beforeEach(function(done) { - UserModel.removeAsync() + <% if (filters.mongooseModels) { %>UserModel.removeAsync()<% } + if (filters.sequelizeModels) { %>UserModel.destroy()<% } %> .then(function() { - return UserModel.createAsync(testUser); + <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } + if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> }) .then(loadPage) .finally(done); diff --git a/app/templates/e2e/account(auth)/login/login.spec(mocha).js b/app/templates/e2e/account(auth)/login/login.spec(mocha).js index a2c986f32..3335cf3b4 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(mocha).js +++ b/app/templates/e2e/account(auth)/login/login.spec(mocha).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Login View', function() { var page; @@ -19,15 +20,18 @@ describe('Login View', function() { before(function() { return UserModel - .removeAsync() + <% if (filters.mongooseModels) { %>.removeAsync()<% } + if (filters.sequelizeModels) { %>.destroy()<% } %> .then(function() { - return UserModel.createAsync(testUser); + <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } + if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> }) .then(loadPage); }); after(function() { - return UserModel.removeAsync(); + <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } + if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> }); it('should include login form with correct inputs and submit button', function() { diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js index f496459d8..f3149865c 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Logout View', function() { var login = function(user) { @@ -16,9 +17,11 @@ describe('Logout View', function() { }; beforeEach(function(done) { - UserModel.removeAsync() + <% if (filters.mongooseModels) { %>UserModel.removeAsync()<% } + if (filters.sequelizeModels) { %>UserModel.destroy()<% } %> .then(function() { - return UserModel.createAsync(testUser); + <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } + if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> }) .then(function() { return login(testUser); diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js index 3adba51f8..85d92cf75 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Logout View', function() { var login = function(user) { @@ -17,9 +18,11 @@ describe('Logout View', function() { beforeEach(function() { return UserModel - .removeAsync() + <% if (filters.mongooseModels) { %>.removeAsync()<% } + if (filters.sequelizeModels) { %>.destroy()<% } %> .then(function() { - return UserModel.createAsync(testUser); + <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } + if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> }) .then(function() { return login(testUser); @@ -27,7 +30,8 @@ describe('Logout View', function() { }); after(function() { - return UserModel.removeAsync(); + <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } + if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> }) describe('with local auth', function() { diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js index 856786e4a..abbfc98a4 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Signup View', function() { var page; @@ -35,7 +36,8 @@ describe('Signup View', function() { describe('with local auth', function() { it('should signup a new user, log them in, and redirecting to "/"', function(done) { - UserModel.remove(function() { + <% if (filters.mongooseModels) { %>UserModel.remove(function() {<% } + if (filters.sequelizeModels) { %>UserModel.destroy().then(function() {<% } %> page.signup(testUser); var navbar = require('../../components/navbar/navbar.po'); diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js index 6a6b0a775..5351ea75d 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js @@ -1,7 +1,8 @@ 'use strict'; -var config = protractor.getInstance().params; -var UserModel = require(config.serverConfig.root + '/server/api/user/user.model'); +var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> describe('Signup View', function() { var page; @@ -22,7 +23,8 @@ describe('Signup View', function() { }); after(function() { - return UserModel.removeAsync(); + <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } + if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> }); it('should include signup form with correct inputs and submit button', function() { @@ -39,7 +41,8 @@ describe('Signup View', function() { describe('with local auth', function() { it('should signup a new user, log them in, and redirecting to "/"', function(done) { - UserModel.remove(function() { + <% if (filters.mongooseModels) { %>UserModel.remove(function() {<% } + if (filters.sequelizeModels) { %>UserModel.destroy().then(function() {<% } %> page.signup(testUser); var navbar = require('../../components/navbar/navbar.po'); diff --git a/app/templates/protractor.conf.js b/app/templates/protractor.conf.js index f0061ff86..a5c42a390 100644 --- a/app/templates/protractor.conf.js +++ b/app/templates/protractor.conf.js @@ -75,10 +75,10 @@ var config = { ); <% } %> var serverConfig = config.params.serverConfig; - +<% if (filters.mongoose) { %> // Setup mongo for tests var mongoose = require('mongoose-bird')(); - mongoose.connect(serverConfig.mongo.uri, serverConfig.mongo.options); // Connect to database + mongoose.connect(serverConfig.mongo.uri, serverConfig.mongo.options); // Connect to database<% } %> } }; diff --git a/app/templates/server/api/thing/index.js b/app/templates/server/api/thing/index.js index ea697d38b..fde8f3968 100644 --- a/app/templates/server/api/thing/index.js +++ b/app/templates/server/api/thing/index.js @@ -5,7 +5,7 @@ var controller = require('./thing.controller'); var router = express.Router(); -router.get('/', controller.index);<% if (filters.mongoose) { %> +router.get('/', controller.index);<% if (filters.models) { %> router.get('/:id', controller.show); router.post('/', controller.create); router.put('/:id', controller.update); diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js index 899b22d79..91f02f6df 100644 --- a/app/templates/server/api/thing/index.spec.js +++ b/app/templates/server/api/thing/index.spec.js @@ -3,7 +3,7 @@ var proxyquire = require('proxyquire').noPreserveCache(); var thingCtrlStub = { - index: 'thingCtrl.index'<% if (filters.mongoose) { %>, + index: 'thingCtrl.index'<% if (filters.models) { %>, show: 'thingCtrl.show', create: 'thingCtrl.create', update: 'thingCtrl.update', @@ -11,7 +11,7 @@ var thingCtrlStub = { }; var routerStub = { - get: sinon.spy()<% if (filters.mongoose) { %>, + get: sinon.spy()<% if (filters.models) { %>, put: sinon.spy(), patch: sinon.spy(), post: sinon.spy(), @@ -42,7 +42,7 @@ describe('Thing API Router:', function() { .should.have.been.calledOnce; }); - });<% if (filters.mongoose) { %> + });<% if (filters.models) { %> describe('GET /api/things/:id', function() { diff --git a/app/templates/server/api/thing/thing.controller.js b/app/templates/server/api/thing/thing.controller(models).js similarity index 52% rename from app/templates/server/api/thing/thing.controller.js rename to app/templates/server/api/thing/thing.controller(models).js index 710c7cd38..a14fbd4b3 100644 --- a/app/templates/server/api/thing/thing.controller.js +++ b/app/templates/server/api/thing/thing.controller(models).js @@ -7,10 +7,12 @@ * DELETE /things/:id -> destroy */ -'use strict';<% if (filters.mongoose) { %> +'use strict'; -var _ = require('lodash'); -var Thing = require('./thing.model'); +var _ = require('lodash');<% if (filters.mongooseModels) { %> +var Thing = require('./thing.model');<% } %><% if (filters.sequelizeModels) { %> +var sqldb = require('../../sqldb') +var Thing = sqldb.Thing;<% } %> function handleError(res, statusCode) { statusCode = statusCode || 500; @@ -40,9 +42,11 @@ function handleEntityNotFound(res) { function saveUpdates(updates) { return function(entity) { - var updated = _.merge(entity, updates); + <% if (filters.mongooseModels) { %>var updated = _.merge(entity, updates); return updated.saveAsync() - .spread(function(updated) { + .spread(function(updated) {<% } + if (filters.sequelizeModels) { %>return entity.updateAttributes(updates) + .then(function(updated) {<% } %> return updated; }); }; @@ -51,48 +55,31 @@ function saveUpdates(updates) { function removeEntity(res) { return function(entity) { if (entity) { - return entity.removeAsync() + <% if (filters.mongooseModels) { %>return entity.removeAsync()<% } + if (filters.sequelizeModels) { %>return entity.destroy()<% } %> .then(function() { return res.send(204); }); } }; -}<% } %> +} // Get list of things -exports.index = function(req, res) {<% if(!filters.mongoose) { %> - res.json([{ - name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + - 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' - }, { - name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' - }, { - name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + - 'Automatic injection of scripts and styles into your index.html' - }, { - name : 'Modular Structure', - info : 'Best practice client and server structures allow for more code reusability and ' + - 'maximum scalability' - }, { - name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript payload, minifies ' + - 'your scripts/css/images, and rewrites asset names for caching.' - }, { - name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + - 'subgenerators' - }]);<% } if (filters.mongoose) { %> - Thing.findAsync() +exports.index = function(req, res) { + <% if (filters.mongooseModels) { %>Thing.findAsync()<% } + if (filters.sequelizeModels) { %>Thing.findAll()<% } %> .then(responseWithResult(res)) - .catch(handleError(res));<% } %> -};<% if (filters.mongoose) { %> + .catch(handleError(res)); +}; // Get a single thing exports.show = function(req, res) { - Thing.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %>Thing.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(responseWithResult(res)) .catch(handleError(res)); @@ -100,7 +87,8 @@ exports.show = function(req, res) { // Creates a new thing in the DB. exports.create = function(req, res) { - Thing.createAsync(req.body) + <% if (filters.mongooseModels) { %>Thing.createAsync(req.body)<% } + if (filters.sequelizeModels) { %>Thing.create(req.body)<% } %> .then(responseWithResult(res, 201)) .catch(handleError(res)); }; @@ -110,7 +98,12 @@ exports.update = function(req, res) { if (req.body._id) { delete req.body._id; } - Thing.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %>Thing.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(saveUpdates(req.body)) .then(responseWithResult(res)) @@ -119,8 +112,13 @@ exports.update = function(req, res) { // Deletes a thing from the DB. exports.destroy = function(req, res) { - Thing.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %>Thing.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(removeEntity(res)) .catch(handleError(res)); -};<% } %> +}; diff --git a/app/templates/server/api/thing/thing.controller(noModels).js b/app/templates/server/api/thing/thing.controller(noModels).js new file mode 100644 index 000000000..02b2410c5 --- /dev/null +++ b/app/templates/server/api/thing/thing.controller(noModels).js @@ -0,0 +1,38 @@ +/** + * Using Rails-like standard naming convention for endpoints. + * GET /things -> index + * POST /things -> create + * GET /things/:id -> show + * PUT /things/:id -> update + * DELETE /things/:id -> destroy + */ + +'use strict'; + +// Get list of things +exports.index = function(req, res) { + res.json([{ + name : 'Development Tools', + info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + + 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' + }, { + name : 'Server and Client integration', + info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' + }, { + name : 'Smart Build System', + info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + + 'Automatic injection of scripts and styles into your index.html' + }, { + name : 'Modular Structure', + info : 'Best practice client and server structures allow for more code reusability and ' + + 'maximum scalability' + }, { + name : 'Optimized Build', + info : 'Build process packs up your templates as a single JavaScript payload, minifies ' + + 'your scripts/css/images, and rewrites asset names for caching.' + }, { + name : 'Deployment Ready', + info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + + 'subgenerators' + }]); +}; diff --git a/app/templates/server/api/thing/thing.integration.js b/app/templates/server/api/thing/thing.integration.js index de7ed7ff5..3eb5d05d8 100644 --- a/app/templates/server/api/thing/thing.integration.js +++ b/app/templates/server/api/thing/thing.integration.js @@ -1,7 +1,7 @@ 'use strict'; var app = require('../../app'); -var request = require('supertest');<% if (filters.mongoose) { %> +var request = require('supertest');<% if (filters.models) { %> var newThing;<% } %> @@ -28,7 +28,7 @@ describe('Thing API:', function() { things.should.be.instanceOf(Array); }); - });<% if (filters.mongoose) { %> + });<% if (filters.models) { %> describe('POST /api/things', function() { beforeEach(function(done) { @@ -130,7 +130,7 @@ describe('Thing API:', function() { }); }); - it('should respond with 404 when thing does not exsist', function(done) { + it('should respond with 404 when thing does not exist', function(done) { request(app) .delete('/api/things/' + newThing._id) .expect(404) diff --git a/app/templates/server/api/thing/thing.model(mongoose).js b/app/templates/server/api/thing/thing.model(mongooseModels).js similarity index 100% rename from app/templates/server/api/thing/thing.model(mongoose).js rename to app/templates/server/api/thing/thing.model(mongooseModels).js diff --git a/app/templates/server/api/thing/thing.model(sequelizeModels).js b/app/templates/server/api/thing/thing.model(sequelizeModels).js new file mode 100644 index 000000000..8e8072da4 --- /dev/null +++ b/app/templates/server/api/thing/thing.model(sequelizeModels).js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = function(sequelize, DataTypes) { + return sequelize.define('Thing', { + _id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true + }, + name: DataTypes.STRING, + info: DataTypes.STRING, + active: DataTypes.BOOLEAN + }); +}; diff --git a/app/templates/server/api/thing/thing.socket(socketio).js b/app/templates/server/api/thing/thing.socket(socketio).js index 2d0171cdc..d0d98a6ca 100644 --- a/app/templates/server/api/thing/thing.socket(socketio).js +++ b/app/templates/server/api/thing/thing.socket(socketio).js @@ -3,15 +3,24 @@ */ 'use strict'; +<% if (filters.mongooseModels) { %> +var thing = require('./thing.model');<% } %><% if (filters.sequelizeModels) { %> +var thing = require('../../sqldb').Thing;<% } %> -var thing = require('./thing.model'); - -exports.register = function(socket) { - thing.schema.post('save', function(doc) { +exports.register = function(socket) {<% if (filters.sequelizeModels) { %> + thing.hook('afterCreate', function(doc, fields, fn) { onSave(socket, doc); + fn(null); + });<% } %> + <% if (filters.mongooseModels) { %>thing.schema.post('save', function(doc) {<% } + if (filters.sequelizeModels) { %>thing.hook('afterUpdate', function(doc, fields, fn) {<% } %> + onSave(socket, doc);<% if (filters.sequelizeModels) { %> + fn(null);<% } %> }); - thing.schema.post('remove', function(doc) { - onRemove(socket, doc); + <% if (filters.mongooseModels) { %>thing.schema.post('remove', function(doc) {<% } + if (filters.sequelizeModels) { %>thing.hook('afterDestroy', function(doc, fields, fn) {<% } %> + onRemove(socket, doc);<% if (filters.sequelizeModels) { %> + fn(null);<% } %> }); }; diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index 793da0255..8b7f4e0b8 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -1,6 +1,9 @@ 'use strict'; - -var User = require('./user.model'); +<% if (filters.mongooseModels) { %> +var User = require('./user.model');<% } %><% if (filters.sequelizeModels) { %> +var _ = require('lodash'); +var sqldb = require('../../sqldb'); +var User = sqldb.User;<% } %> var passport = require('passport'); var config = require('../../config/environment'); var jwt = require('jsonwebtoken'); @@ -31,7 +34,16 @@ function respondWith(res, statusCode) { * restriction: 'admin' */ exports.index = function(req, res) { - User.findAsync({}, '-salt -hashedPassword') + <% if (filters.mongooseModels) { %>User.findAsync({}, '-salt -hashedPassword')<% } + if (filters.sequelizeModels) { %>User.findAll({ + attributes: [ + '_id', + 'name', + 'email', + 'role', + 'provider' + ] + })<% } %> .then(function(users) { res.json(200, users); }) @@ -42,11 +54,16 @@ exports.index = function(req, res) { * Creates a new user */ exports.create = function(req, res, next) { - var newUser = new User(req.body); + <% if (filters.mongooseModels) { %>var newUser = new User(req.body); newUser.provider = 'local'; newUser.role = 'user'; - newUser.saveAsync() - .spread(function(user) { + newUser.saveAsync()<% } + if (filters.sequelizeModels) { %>var newUser = User.build(req.body); + newUser.setDataValue('provider', 'local'); + newUser.setDataValue('role', 'user'); + newUser.save()<% } %> + <% if (filters.mongooseModels) { %>.spread(function(user) {<% } + if (filters.sequelizeModels) { %>.then(function(user) {<% } %> var token = jwt.sign({ _id: user._id }, config.secrets.session, { expiresInMinutes: 60 * 5 }); @@ -61,7 +78,12 @@ exports.create = function(req, res, next) { exports.show = function(req, res, next) { var userId = req.params.id; - User.findByIdAsync(userId) + <% if (filters.mongooseModels) { %>User.findByIdAsync(userId)<% } + if (filters.sequelizeModels) { %>User.find({ + where: { + _id: userId + } + })<% } %> .then(function(user) { if (!user) { return res.send(401); @@ -78,7 +100,8 @@ exports.show = function(req, res, next) { * restriction: 'admin' */ exports.destroy = function(req, res) { - User.findByIdAndRemoveAsync(req.params.id) + <% if (filters.mongooseModels) { %>User.findByIdAndRemoveAsync(req.params.id)<% } + if (filters.sequelizeModels) { %>User.destroy({ _id: req.params.id })<% } %> .then(respondWith(res, 204)) .catch(handleError(res)); }; @@ -91,12 +114,18 @@ exports.changePassword = function(req, res, next) { var oldPass = String(req.body.oldPassword); var newPass = String(req.body.newPassword); - User.findByIdAsync(userId) + <% if (filters.mongooseModels) { %>User.findByIdAsync(userId)<% } + if (filters.sequelizeModels) { %>User.find({ + where: { + _id: userId + } + })<% } %> .then(function(user) { if (user.authenticate(oldPass)) { user.password = newPass; - return user.saveAsync() - .spread(respondWith(res, 200)) + <% if (filters.mongooseModels) { %>return user.saveAsync()<% } + if (filters.sequelizeModels) { %>return user.save()<% } %> + .then(respondWith(res, 200)) .catch(validationError(res)); } else { return res.send(403); @@ -110,7 +139,19 @@ exports.changePassword = function(req, res, next) { exports.me = function(req, res, next) { var userId = req.user._id; - User.findOneAsync({ _id: userId }, '-salt -hashedPassword') + <% if (filters.mongooseModels) { %>User.findOneAsync({ _id: userId }, '-salt -hashedPassword')<% } + if (filters.sequelizeModels) { %>User.find({ + where: { + _id: userId + }, + attributes: [ + '_id', + 'name', + 'email', + 'role', + 'provider' + ] + })<% } %> .then(function(user) { // don't ever give out the password or salt if (!user) { return res.json(401); } res.json(user); diff --git a/app/templates/server/api/user(auth)/user.integration.js b/app/templates/server/api/user(auth)/user.integration.js index ee97d3051..35bcdb573 100644 --- a/app/templates/server/api/user(auth)/user.integration.js +++ b/app/templates/server/api/user(auth)/user.integration.js @@ -1,7 +1,8 @@ 'use strict'; -var app = require('../../app'); -var User = require('./user.model'); +var app = require('../../app');<% if (filters.mongooseModels) { %> +var User = require('./user.model');<% } %><% if (filters.sequelizeModels) { %> +var User = require('../../sqldb').User;<% } %> var request = require('supertest'); describe('User API:', function() { @@ -9,25 +10,33 @@ describe('User API:', function() { // Clear users before testing before(function(done) { - User.remove(function() { - user = new User({ + <% if (filters.mongooseModels) { %>User.remove(function() {<% } + if (filters.sequelizeModels) { %>User.destroy().then(function() {<% } %> + <% if (filters.mongooseModels) { %>user = new User({<% } + if (filters.sequelizeModels) { %>user = User.build({<% } %> name: 'Fake User', email: 'test@test.com', password: 'password' }); - user.save(function(err) { + <% if (filters.mongooseModels) { %>user.save(function(err) { if (err) { return done(err); } done(); - }); + });<% } + if (filters.sequelizeModels) { %>user.save().then(function() { + done(); + }, function(err) { + return done(err); + });<% } %> }); }); // Clear users after testing after(function() { - return User.remove().exec(); + <% if (filters.mongooseModels) { %>return User.remove().exec();<% } + if (filters.sequelizeModels) { %>return User.destroy();<% } %> }); describe('GET /api/users/me', function() { @@ -55,7 +64,7 @@ describe('User API:', function() { .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { - res.body._id.should.equal(user._id.toString()); + res.body._id.toString().should.equal(user._id.toString()); done(); }); }); diff --git a/app/templates/server/api/user(auth)/user.model.js b/app/templates/server/api/user(auth)/user.model(mongooseModels).js similarity index 100% rename from app/templates/server/api/user(auth)/user.model.js rename to app/templates/server/api/user(auth)/user.model(mongooseModels).js diff --git a/app/templates/server/api/user(auth)/user.model(sequelizeModels).js b/app/templates/server/api/user(auth)/user.model(sequelizeModels).js new file mode 100644 index 000000000..af593157a --- /dev/null +++ b/app/templates/server/api/user(auth)/user.model(sequelizeModels).js @@ -0,0 +1,235 @@ +'use strict'; + +var crypto = require('crypto');<% if (filters.oauth) { %> +var authTypes = ['github', 'twitter', 'facebook', 'google'];<% } %> + +var validatePresenceOf = function(value) { + return value && value.length; +}; + +module.exports = function(sequelize, DataTypes) { + var User = sequelize.define('User', { + + _id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true + }, + name: DataTypes.STRING, + email: { + type: DataTypes.STRING, + unique: { + msg: 'The specified email address is already in use.' + }, + validate: { + isEmail: true + } + }, + role: { + type: DataTypes.STRING, + defaultValue: 'user' + }, + password: { + type: DataTypes.STRING, + validate: { + notEmpty: true + } + }, + provider: DataTypes.STRING, + salt: DataTypes.STRING<% if (filters.oauth) { %>,<% if (filters.facebookAuth) { %> + facebook: DataTypes.TEXT,<% } %><% if (filters.twitterAuth) { %> + twitter: DataTypes.TEXT,<% } %><% if (filters.googleAuth) { %> + google: DataTypes.TEXT,<% } %> + github: DataTypes.TEXT<% } %> + + }, { + + /** + * Virtual Getters + */ + getterMethods: { + // Public profile information + profile: function() { + return { + 'name': this.name, + 'role': this.role + }; + }, + + // Non-sensitive info we'll be putting in the token + token: function() { + return { + '_id': this._id, + 'role': this.role + }; + } + }, + + /** + * Pre-save hooks + */ + hooks: { + beforeBulkCreate: function(users, fields, fn) { + var totalUpdated = 0; + users.forEach(function(user) { + user.updatePassword(function(err) { + if (err) { + return fn(err); + } + totalUpdated += 1; + if (totalUpdated === users.length) { + return fn(); + } + }); + }); + }, + beforeCreate: function(user, fields, fn) { + user.updatePassword(fn); + }, + beforeUpdate: function(user, fields, fn) { + if (user.changed('password')) { + user.updatePassword(fn); + } + } + }, + + /** + * Instance Methods + */ + instanceMethods: { + /** + * Authenticate - check if the passwords are the same + * + * @param {String} password + * @param {Function} callback + * @return {Boolean} + * @api public + */ + authenticate: function(password, callback) { + if (!callback) { + return this.password === this.encryptPassword(password); + } + + var _this = this; + this.encryptPassword(password, function(err, pwdGen) { + if (err) { + callback(err); + } + + if (_this.password === pwdGen) { + callback(null, true); + } + else { + callback(null, false); + } + }); + }, + + /** + * Make salt + * + * @param {Number} byteSize Optional salt byte size, default to 16 + * @param {Function} callback + * @return {String} + * @api public + */ + makeSalt: function(byteSize, callback) { + var defaultByteSize = 16; + + if (typeof arguments[0] === 'function') { + callback = arguments[0]; + byteSize = defaultByteSize; + } + else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + + if (!byteSize) { + byteSize = defaultByteSize; + } + + if (!callback) { + return crypto.randomBytes(byteSize).toString('base64'); + } + + return crypto.randomBytes(byteSize, function(err, salt) { + if (err) { + callback(err); + } + return callback(null, salt.toString('base64')); + }); + }, + + /** + * Encrypt password + * + * @param {String} password + * @param {Function} callback + * @return {String} + * @api public + */ + encryptPassword: function(password, callback) { + if (!password || !this.salt) { + if (!callback) { + return null; + } + return callback(null); + } + + var defaultIterations = 10000; + var defaultKeyLength = 64; + var salt = new Buffer(this.salt, 'base64'); + + if (!callback) { + return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) + .toString('base64'); + } + + return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, + function(err, key) { + if (err) { + callback(err); + } + return callback(null, key.toString('base64')); + }); + }, + + /** + * Update password field + * + * @param {Function} fn + * @return {String} + * @api public + */ + updatePassword: function(fn) { + // Handle new/update passwords + if (this.password) { + if (!validatePresenceOf(this.password)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) { + fn(new Error('Invalid password')); + } + + // Make salt with a callback + var _this = this; + this.makeSalt(function(saltErr, salt) { + if (saltErr) { + fn(saltErr); + } + _this.salt = salt; + _this.encryptPassword(_this.password, function(encryptErr, hashedPassword) { + if (encryptErr) { + fn(encryptErr); + } + _this.password = hashedPassword; + fn(null); + }); + }); + } else { + fn(null); + } + } + } + }); + + return User; +}; diff --git a/app/templates/server/api/user(auth)/user.model.spec.js b/app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js similarity index 100% rename from app/templates/server/api/user(auth)/user.model.spec.js rename to app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js diff --git a/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js new file mode 100644 index 000000000..88156151b --- /dev/null +++ b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js @@ -0,0 +1,52 @@ +'use strict'; + +var app = require('../../app'); +var User = require('../../sqldb').User; + +var userTemplate = { + provider: 'local', + name: 'Fake User', + email: 'test@test.com', + password: 'password' +}; + +var user = User.build(userTemplate); + +describe('User Model', function() { + before(function() { + // Sync and clear users before testing + User.sync().then(function() { + return User.destroy(); + }); + }); + + afterEach(function() { + return User.destroy(); + }); + + it('should begin with no users', function() { + return User.findAll() + .should.eventually.have.length(0); + }); + + it('should fail when saving a duplicate user', function() { + return user.save() + .then(function() { + var userDup = User.build(userTemplate); + return userDup.save(); + }).should.be.rejected; + }); + + it('should fail when saving without an email', function() { + user.email = ''; + return user.save().should.be.rejected; + }); + + it('should authenticate user if password is valid', function() { + user.authenticate('password').should.be.true; + }); + + it('should not authenticate user if password is invalid', function() { + user.authenticate('blah').should.not.be.true; + }); +}); diff --git a/app/templates/server/app.js b/app/templates/server/app.js index 632dd134f..7c668a881 100644 --- a/app/templates/server/app.js +++ b/app/templates/server/app.js @@ -8,16 +8,17 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development'; var express = require('express');<% if (filters.mongoose) { %> -var mongoose = require('mongoose-bird')();<% } %> +var mongoose = require('mongoose-bird')();<% } %><% if (filters.sequelize) { %> +var sqldb = require('./sqldb');<% } %> var config = require('./config/environment'); <% if (filters.mongoose) { %> -// Connect to database +// Connect to MongoDB mongoose.connect(config.mongo.uri, config.mongo.options); - -// Populate DB with sample data +<% } %><% if (filters.models) { %> +// Populate databases with sample data if (config.seedDB) { require('./config/seed'); } - -<% } %>// Setup server +<% } %> +// Setup server var app = express(); var server = require('http').createServer(app);<% if (filters.socketio) { %> var socketio = require('socket.io')(server, { @@ -29,9 +30,19 @@ require('./config/express')(app); require('./routes')(app); // Start server -server.listen(config.port, config.ip, function() { - console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); -}); - +function startServer() { + server.listen(config.port, config.ip, function() { + console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); + }); +} +<% if (filters.sequelize) { %> +sqldb.sequelize.sync() + .then(startServer) + .catch(function(err) { + console.log('Server failed to start due to error: %s', err); + }); +<% } else { %> +setImmediate(startServer); +<% } %> // Expose app exports = module.exports = app; diff --git a/app/templates/server/auth(auth)/auth.service.js b/app/templates/server/auth(auth)/auth.service.js index 43ea2851f..5b9a6d66f 100644 --- a/app/templates/server/auth(auth)/auth.service.js +++ b/app/templates/server/auth(auth)/auth.service.js @@ -1,12 +1,13 @@ 'use strict'; - -var mongoose = require('mongoose-bird')(); +<% if (filters.mongooseModels) { %> +var mongoose = require('mongoose-bird')();<% } %> var passport = require('passport'); var config = require('../config/environment'); var jwt = require('jsonwebtoken'); var expressJwt = require('express-jwt'); -var compose = require('composable-middleware'); -var User = require('../api/user/user.model'); +var compose = require('composable-middleware');<% if (filters.mongooseModels) { %> +var User = require('../api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var User = require('../sqldb').User;<% } %> var validateJwt = expressJwt({ secret: config.secrets.session }); @@ -27,7 +28,12 @@ function isAuthenticated() { }) // Attach user to request .use(function(req, res, next) { - User.findByIdAsync(req.user._id) + <% if (filters.mongooseModels) { %>User.findByIdAsync(req.user._id)<% } + if (filters.sequelizeModels) { %>User.find({ + where: { + _id: req.user._id + } + })<% } %> .then(function(user) { if (!user) { return res.send(401); diff --git a/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js b/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js index b29d74c69..92911b22f 100644 --- a/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js +++ b/app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js @@ -8,31 +8,35 @@ exports.setup = function(User, config) { callbackURL: config.facebook.callbackURL }, function(accessToken, refreshToken, profile, done) { - User.findOne({ + <% if (filters.mongooseModels) { %>User.findOneAsync({<% } + if (filters.sequelizeModels) { %>User.find({<% } %> 'facebook.id': profile.id - }, - function(err, user) { - if (err) { - return done(err); - } - if (!user) { - user = new User({ - name: profile.displayName, - email: profile.emails[0].value, - role: 'user', - username: profile.username, - provider: 'facebook', - facebook: profile._json - }); - user.save(function(err) { - if (err) { - done(err); - } - return done(err, user); - }); - } else { - return done(err, user); - } }) + .then(function(user) { + if (!user) { + <% if (filters.mongooseModels) { %>user = new User({<% } + if (filters.sequelizeModels) { %>user = User.build({<% } %> + name: profile.displayName, + email: profile.emails[0].value, + role: 'user', + username: profile.username, + provider: 'facebook', + facebook: profile._json + }); + <% if (filters.mongooseModels) { %>user.saveAsync()<% } + if (filters.sequelizeModels) { %>user.save()<% } %> + .then(function(user) { + return done(null, user); + }) + .catch(function(err) { + return done(err); + }); + } else { + return done(null, user); + } + }) + .catch(function(err) { + return done(err); + }); })); }; diff --git a/app/templates/server/auth(auth)/google(googleAuth)/passport.js b/app/templates/server/auth(auth)/google(googleAuth)/passport.js index 0e7a3602d..0c9462a8d 100644 --- a/app/templates/server/auth(auth)/google(googleAuth)/passport.js +++ b/app/templates/server/auth(auth)/google(googleAuth)/passport.js @@ -8,27 +8,35 @@ exports.setup = function(User, config) { callbackURL: config.google.callbackURL }, function(accessToken, refreshToken, profile, done) { - User.findOne({ + <% if (filters.mongooseModels) { %>User.findOneAsync({<% } + if (filters.sequelizeModels) { %>User.find({<% } %> 'google.id': profile.id - }, function(err, user) { - if (!user) { - user = new User({ - name: profile.displayName, - email: profile.emails[0].value, - role: 'user', - username: profile.username, - provider: 'google', - google: profile._json - }); - user.save(function(err) { - if (err) { - done(err); - } - return done(err, user); - }); - } else { - return done(err, user); - } - }); + }) + .then(function(user) { + if (!user) { + <% if (filters.mongooseModels) { %>user = new User({<% } + if (filters.sequelizeModels) { %>user = User.build({<% } %> + name: profile.displayName, + email: profile.emails[0].value, + role: 'user', + username: profile.username, + provider: 'google', + google: profile._json + }); + <% if (filters.mongooseModels) { %>user.saveAsync()<% } + if (filters.sequelizeModels) { %>user.save()<% } %> + .then(function(user) { + return done(null, user); + }) + .catch(function(err) { + return done(err); + }); + } else { + return done(null, user); + } + }) + .catch(function(err) { + return done(err); + }); })); }; diff --git a/app/templates/server/auth(auth)/index.js b/app/templates/server/auth(auth)/index.js index b930ad93f..75ddfdcb8 100644 --- a/app/templates/server/auth(auth)/index.js +++ b/app/templates/server/auth(auth)/index.js @@ -2,8 +2,9 @@ var express = require('express'); var passport = require('passport'); -var config = require('../config/environment'); -var User = require('../api/user/user.model'); +var config = require('../config/environment');<% if (filters.mongooseModels) { %> +var User = require('../api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> +var User = require('../sqldb').User;<% } %> // Passport Configuration require('./local/passport').setup(User, config);<% if (filters.facebookAuth) { %> diff --git a/app/templates/server/auth(auth)/local/passport.js b/app/templates/server/auth(auth)/local/passport.js index f4898b73a..2bd3366f8 100644 --- a/app/templates/server/auth(auth)/local/passport.js +++ b/app/templates/server/auth(auth)/local/passport.js @@ -1,18 +1,16 @@ var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; -exports.setup = function(User, config) { - passport.use(new LocalStrategy({ - usernameField: 'email', - passwordField: 'password' // this is the virtual field on the model - }, function(email, password, done) { - User.findOne({ +function localAuthenticate(User, email, password, done) { + <% if (filters.mongooseModels) { %>User.findOneAsync({ + email: email.toLowerCase() + })<% } + if (filters.sequelizeModels) { %>User.find({ + where: { email: email.toLowerCase() - }, function(err, user) { - if (err) { - return done(err); - } - + } + })<% } %> + .then(function(user) { if (!user) { return done(null, false, { message: 'This email is not registered.' @@ -30,6 +28,17 @@ exports.setup = function(User, config) { return done(null, user); } }); + }) + .catch(function(err) { + return done(err); }); - })); +} + +exports.setup = function(User, config) { + passport.use(new LocalStrategy({ + usernameField: 'email', + passwordField: 'password' // this is the virtual field on the model + }, function(email, password, done) {<% if (filters.models) { %> + return localAuthenticate(User, email, password, done); +<% } %> })); }; diff --git a/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js b/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js index 7428e8afd..bf23bd3ba 100644 --- a/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js +++ b/app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js @@ -8,29 +8,34 @@ exports.setup = function(User, config) { callbackURL: config.twitter.callbackURL }, function(token, tokenSecret, profile, done) { - User.findOne({ + <% if (filters.mongooseModels) { %>User.findOneAsync({<% } + if (filters.sequelizeModels) { %>User.find({<% } %> 'twitter.id_str': profile.id - }, function(err, user) { - if (err) { + }) + .then(function(user) { + if (!user) { + <% if (filters.mongooseModels) { %>user = new User({<% } + if (filters.sequelizeModels) { %>user = User.build({<% } %> + name: profile.displayName, + username: profile.username, + role: 'user', + provider: 'twitter', + twitter: profile._json + }); + <% if (filters.mongooseModels) { %>user.saveAsync()<% } + if (filters.sequelizeModels) { %>user.save()<% } %> + .then(function(user) { + return done(null, user); + }) + .catch(function(err) { + return done(err); + }); + } else { + return done(null, user); + } + }) + .catch(function(err) { return done(err); - } - if (!user) { - user = new User({ - name: profile.displayName, - username: profile.username, - role: 'user', - provider: 'twitter', - twitter: profile._json - }); - user.save(function(err) { - if (err) { - return done(err); - } - return done(err, user); - }); - } else { - return done(err, user); - } - }); + }); })); }; diff --git a/app/templates/server/config/environment/development.js b/app/templates/server/config/environment/development.js index fb33d6eab..20656595b 100644 --- a/app/templates/server/config/environment/development.js +++ b/app/templates/server/config/environment/development.js @@ -7,6 +7,16 @@ module.exports = { mongo: { uri: 'mongodb://localhost/<%= _.slugify(appname) %>-dev' }, + sequelize: { + uri: 'sqlite://', + options: { + logging: false, + storage: 'dev.sqlite', + define: { + timestamps: false + } + } + }, seedDB: true }; diff --git a/app/templates/server/config/environment/test.js b/app/templates/server/config/environment/test.js index 6ead6e1aa..021938424 100644 --- a/app/templates/server/config/environment/test.js +++ b/app/templates/server/config/environment/test.js @@ -6,5 +6,15 @@ module.exports = { // MongoDB connection options mongo: { uri: 'mongodb://localhost/<%= _.slugify(appname) %>-test' + }, + sequelize: { + uri: 'sqlite://', + options: { + logging: false, + storage: 'test.sqlite', + define: { + timestamps: false + } + } } }; diff --git a/app/templates/server/config/express.js b/app/templates/server/config/express.js index f44999c1e..9a2018263 100644 --- a/app/templates/server/config/express.js +++ b/app/templates/server/config/express.js @@ -15,9 +15,9 @@ var errorHandler = require('errorhandler'); var path = require('path'); var config = require('./environment');<% if (filters.auth) { %> var passport = require('passport');<% } %><% if (filters.twitterAuth) { %> -var session = require('express-session'); +var session = require('express-session');<% if (filters.mongoose) { %> var mongoStore = require('connect-mongo')(session); -var mongoose = require('mongoose-bird')();<% } %> +var mongoose = require('mongoose-bird')();<% } %><% } %> module.exports = function(app) { var env = app.get('env'); @@ -33,13 +33,13 @@ module.exports = function(app) { app.use(cookieParser());<% if (filters.auth) { %> app.use(passport.initialize());<% } %><% if (filters.twitterAuth) { %> - // Persist sessions with mongoStore + // Persist sessions with mongoStore / sequelizeStore // We need to enable sessions for passport twitter because its an oauth 1.0 strategy app.use(session({ secret: config.secrets.session, resave: true, - saveUninitialized: true, - store: new mongoStore({ mongoose_connection: mongoose.connection }) + saveUninitialized: true<% if (filters.mongoose) { %>, + store: new mongoStore({ mongoose_connection: mongoose.connection })<% } %> })); <% } %> app.set('appPath', path.join(config.root, 'client')); diff --git a/app/templates/server/config/seed(mongoose).js b/app/templates/server/config/seed(models).js similarity index 64% rename from app/templates/server/config/seed(mongoose).js rename to app/templates/server/config/seed(models).js index 1f6945d8d..635658010 100644 --- a/app/templates/server/config/seed(mongoose).js +++ b/app/templates/server/config/seed(models).js @@ -4,13 +4,22 @@ */ 'use strict'; - +<% if (filters.mongooseModels) { %> var Thing = require('../api/thing/thing.model'); <% if (filters.auth) { %>var User = require('../api/user/user.model');<% } %> - -Thing.find({}).removeAsync() +<% } %><% if (filters.sequelizeModels) { %> +var sqldb = require('../sqldb'); +var Thing = sqldb.Thing; +<% if (filters.auth) { %>var User = sqldb.User;<% } %> +<% } %> +<% if (filters.mongooseModels) { %>Thing.find({}).removeAsync()<% } + if (filters.sequelizeModels) { %>Thing.sync() + .then(function() { + return Thing.destroy(); + })<% } %> .then(function() { - Thing.create({ + <% if (filters.mongooseModels) { %>Thing.create({<% } + if (filters.sequelizeModels) { %>Thing.bulkCreate([{<% } %> name : 'Development Tools', info : 'Integration with popular tools such as Bower, Grunt, Karma, ' + 'Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, ' + @@ -37,12 +46,18 @@ Thing.find({}).removeAsync() name : 'Deployment Ready', info : 'Easily deploy your app to Heroku or Openshift with the heroku ' + 'and openshift subgenerators' - }); + <% if (filters.mongooseModels) { %>});<% } + if (filters.sequelizeModels) { %>}]);<% } %> }); <% if (filters.auth) { %> -User.find({}).removeAsync() +<% if (filters.mongooseModels) { %>User.find({}).removeAsync()<% } + if (filters.sequelizeModels) { %>User.sync() + .then(function() { + User.destroy(); + })<% } %> .then(function() { - User.create({ + <% if (filters.mongooseModels) { %>User.createAsync({<% } + if (filters.sequelizeModels) { %>User.bulkCreate([{<% } %> provider: 'local', name: 'Test User', email: 'test@test.com', @@ -53,8 +68,9 @@ User.find({}).removeAsync() name: 'Admin', email: 'admin@admin.com', password: 'admin' - }, function() { + <% if (filters.mongooseModels) { %>})<% } + if (filters.sequelizeModels) { %>}])<% } %> + .then(function() { console.log('finished populating users'); }); - }); -<% } %> \ No newline at end of file + });<% } %> diff --git a/app/templates/server/sqldb(sequelize)/index.js b/app/templates/server/sqldb(sequelize)/index.js new file mode 100644 index 000000000..231db9823 --- /dev/null +++ b/app/templates/server/sqldb(sequelize)/index.js @@ -0,0 +1,35 @@ +/** + * Sequelize initialization module + */ + +'use strict'; + +var path = require('path'); +var config = require('../config/environment'); + +var Sequelize = require('sequelize'); + +var db = { + Sequelize: Sequelize, + sequelize: new Sequelize(config.sequelize.uri, config.sequelize.options) +}; +<% if (filters.sequelizeModels) { %> +db.Thing = db.sequelize.import(path.join( + config.root, + 'server', + 'api', + 'thing', + 'thing.model' +)); +<% if (filters.auth) { %> +db.User = db.sequelize.import(path.join( + config.root, + 'server', + 'api', + 'user', + 'user.model' +)); +<% } %><% } %> +// Insert models below + +module.exports = db; diff --git a/endpoint/index.js b/endpoint/index.js index d67f78e51..f870c265f 100644 --- a/endpoint/index.js +++ b/endpoint/index.js @@ -25,11 +25,24 @@ Generator.prototype.askFor = function askFor() { name = name + 's'; } + var self = this; var prompts = [ { name: 'route', message: 'What will the url of your endpoint to be?', default: base + name + }, + { + type: 'list', + name: 'models', + message: 'What would you like to use for the endpoint\'s models?', + choices: [ 'Mongoose', 'Sequelize' ], + filter: function( val ) { + return val.toLowerCase(); + }, + when: function() { + return self.filters.mongoose && self.filters.sequelize; + } } ]; @@ -39,6 +52,16 @@ Generator.prototype.askFor = function askFor() { } this.route = props.route; + + if (props.models) { + delete this.filters.mongoose; + delete this.filters.mongooseModels; + delete this.filters.sequelize; + delete this.filters.sequelizeModels; + + this.filters[props.models] = true; + this.filters[props.models + 'Models'] = true; + } done(); }.bind(this)); }; @@ -67,6 +90,25 @@ Generator.prototype.registerEndpoint = function registerEndpoint() { ngUtil.rewriteFile(socketConfig); } } + + if (this.filters.sequelize) { + if (this.config.get('insertModels')) { + var modelConfig = { + file: this.config.get('registerModelsFile'), + needle: this.config.get('modelsNeedle'), + splicable: [ + "db." + this.classedName + " = db.sequelize.import(path.join(\n" + + " config.root,\n" + + " 'server',\n" + + " 'api',\n" + + " '" + this.name + "',\n" + + " '" + this.name + ".model'\n" + + "));" + ] + }; + ngUtil.rewriteFile(modelConfig); + } + } }; Generator.prototype.createFiles = function createFiles() { diff --git a/endpoint/templates/name.model(sequelize).js b/endpoint/templates/name.model(sequelize).js new file mode 100644 index 000000000..051c5daf2 --- /dev/null +++ b/endpoint/templates/name.model(sequelize).js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = function(sequelize, DataTypes) { + return sequelize.define('<%= classedName %>', { + _id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true + }, + name: DataTypes.STRING, + info: DataTypes.STRING, + active: DataTypes.BOOLEAN + }); +}; diff --git a/endpoint/templates/name.socket(socketio).js b/endpoint/templates/name.socket(socketio).js index 260c80720..e55dfcac0 100644 --- a/endpoint/templates/name.socket(socketio).js +++ b/endpoint/templates/name.socket(socketio).js @@ -3,15 +3,24 @@ */ 'use strict'; +<% if (filters.mongoose) { %> +var <%= classedName %> = require('./<%= name %>.model');<% } %><% if (filters.sequelize) { %> +var <%= classedName %> = require('../../sqldb').<%= classedName %>;<% } %> -var <%= classedName %> = require('./<%= name %>.model'); - -exports.register = function(socket) { - <%= classedName %>.schema.post('save', function(doc) { +exports.register = function(socket) {<% if (filters.sequelize) { %> + <%= classedName %>.hook('afterCreate', function(doc, fields, fn) { onSave(socket, doc); + fn(null); + });<% } %> + <% if (filters.mongoose) { %><%= classedName %>.schema.post('save', function(doc) {<% } + if (filters.sequelize) { %><%= classedName %>.hook('afterUpdate', function(doc, fields, fn) {<% } %> + onSave(socket, doc);<% if (filters.sequelize) { %> + fn(null);<% } %> }); - <%= classedName %>.schema.post('remove', function(doc) { - onRemove(socket, doc); + <% if (filters.mongoose) { %><%= classedName %>.schema.post('remove', function(doc) {<% } + if (filters.sequelize) { %><%= classedName %>.hook('afterDestroy', function(doc, fields, fn) {<% } %> + onRemove(socket, doc);<% if (filters.sequelize) { %> + fn(null);<% } %> }); }; diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 6164b690b..0e227efef 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -18,7 +18,7 @@ describe('angular-fullstack generator', function () { chai: 'expect', bootstrap: true, uibootstrap: true, - mongoose: true, + odms: [ 'mongoose' ], auth: true, oauth: [], socketio: true @@ -153,7 +153,8 @@ describe('angular-fullstack generator', function () { var script = mapping.script[ops.script], markup = mapping.markup[ops.markup], - stylesheet = mapping.stylesheet[ops.stylesheet]; + stylesheet = mapping.stylesheet[ops.stylesheet], + models = ops.models ? ops.models : ops.odms[0]; /* Core Files */ files = files.concat([ @@ -224,14 +225,21 @@ describe('angular-fullstack generator', function () { ]); } - /* Mongoose */ - if (ops.mongoose) { + /* Models - Mongoose or Sequelize */ + if (models) { files = files.concat([ 'server/api/thing/thing.model.js', 'server/config/seed.js' ]); } + /* Sequelize */ + if (ops.odms.indexOf('sequelize') !== -1) { + files = files.concat([ + 'server/sqldb/index.js' + ]); + } + /* Authentication */ if (ops.auth) { files = files.concat([ @@ -475,7 +483,79 @@ describe('angular-fullstack generator', function () { stylesheet: 'less', router: 'uirouter', testing: 'jasmine', - mongoose: true, + odms: [ 'mongoose' ], + auth: true, + oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], + socketio: true, + bootstrap: true, + uibootstrap: true + }; + + beforeEach(function() { + helpers.mockPrompt(gen, testOptions); + }); + + it('should run client tests successfully', function(done) { + runTest('grunt test:client', this, done); + }); + + it('should pass jscs', function(done) { + runTest('grunt jscs', this, done); + }); + + it('should pass lint', function(done) { + runTest('grunt jshint', this, done); + }); + + it('should run server tests successfully', function(done) { + runTest('grunt test:server', this, done); + }); + + it('should pass jscs with generated endpoint', function(done) { + runTest('grunt jscs', this, done, 'foo'); + }); + + it('should pass lint with generated snake-case endpoint', function(done) { + runTest('grunt jshint', this, done, 'foo-bar'); + }); + + it('should run server tests successfully with generated snake-case endpoint', function(done) { + runTest('grunt test:server', this, done, 'foo-bar'); + }); + + it('should generate expected files', function (done) { + gen.run({}, function () { + helpers.assertFile(genFiles(testOptions)); + done(); + }); + }); + + it('should not generate unexpected files', function (done) { + gen.run({}, function () { + assertOnlyFiles(genFiles(testOptions), done); + }); + }); + + if(!process.env.SKIP_E2E) { + it('should run e2e tests successfully', function (done) { + runTest('grunt test:e2e', this, done, 240000); + }); + + //it('should run e2e tests successfully for production app', function (done) { + // runTest('grunt test:e2e:prod', this, done, 240000); + //}); + } + + }); + + describe('with sequelize models, auth', function() { + var testOptions = { + script: 'js', + markup: 'jade', + stylesheet: 'stylus', + router: 'uirouter', + testing: 'jasmine', + odms: [ 'sequelize' ], auth: true, oauth: ['twitterAuth', 'facebookAuth', 'googleAuth'], socketio: true, @@ -548,7 +628,7 @@ describe('angular-fullstack generator', function () { router: 'ngroute', testing: 'mocha', chai: 'should', - mongoose: false, + odms: [], auth: false, oauth: [], socketio: false, @@ -621,7 +701,7 @@ describe('angular-fullstack generator', function () { stylesheet: 'css', router: 'ngroute', testing: 'jasmine', - mongoose: false, + odms: [], auth: false, oauth: [], socketio: false, From 38c0d7cf68a74bc7f2bcf8b43697a30b695e2066 Mon Sep 17 00:00:00 2001 From: dotch Date: Thu, 27 Nov 2014 14:07:02 +0100 Subject: [PATCH 061/201] fix: return a 404 when no user is found fixes #711 --- app/templates/server/api/user(auth)/user.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index 793da0255..8c25c85f6 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -64,7 +64,7 @@ exports.show = function(req, res, next) { User.findByIdAsync(userId) .then(function(user) { if (!user) { - return res.send(401); + return res.send(404); } res.json(user.profile); }) From bb4d92e3050c2ca08a571f32632dab50ac430b5b Mon Sep 17 00:00:00 2001 From: Mark Chapman Date: Wed, 31 Dec 2014 16:31:11 +0000 Subject: [PATCH 062/201] fix(gen:build): Adds missing slash fix(gen:build): Adds missing slash Adds missing slash --- app/templates/Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 6755db958..6cf80f394 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -137,7 +137,7 @@ module.exports = function (grunt) { '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.css', '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.html', '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.js', - '!{.tmp,<%%= yeoman.client %>}{app,components}/**/*.spec.js', + '!{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.spec.js', '!{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.mock.js', '<%%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}' ], From af69a682f60daf9842df388877f4876d4fae9178 Mon Sep 17 00:00:00 2001 From: Tyler Henkel Date: Fri, 23 Jan 2015 00:10:58 -0700 Subject: [PATCH 063/201] style(jscs): update jscs definition to use settings closer to the angular repo --- app/templates/.jscs.json | 42 ++++++++++++++++--- .../api/thing/thing.controller(noModels).js | 34 +++++++-------- .../server/config/environment/index.js | 12 +++--- app/templates/server/config/seed(models).js | 24 +++++------ 4 files changed, 72 insertions(+), 40 deletions(-) diff --git a/app/templates/.jscs.json b/app/templates/.jscs.json index 1c278d0c4..31df3b6cb 100644 --- a/app/templates/.jscs.json +++ b/app/templates/.jscs.json @@ -1,12 +1,44 @@ { - "preset": "google", "maximumLineLength": { "value": 100, "allowComments": true, "allowRegex": true }, - "requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties", - "requireSpacesInsideObjectBrackets": "all", - "disallowSpacesInsideObjectBrackets": "nested", - "requireSpacesInConditionalExpression": true + "disallowMixedSpacesAndTabs": true, + "disallowMultipleLineStrings": true, + "disallowNewlineBeforeBlockStatements": true, + "disallowSpaceAfterObjectKeys": true, + "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], + "disallowSpaceBeforeBinaryOperators": [","], + "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], + "disallowSpacesInAnonymousFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInFunctionDeclaration": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInNamedFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInsideArrayBrackets": true, + "disallowSpacesInsideParentheses": true, + "disallowTrailingComma": true, + "disallowTrailingWhitespace": true, + "requireCommaBeforeLineBreak": true, + "requireLineFeedAtFileEnd": true, + "requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"], + "requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"], + "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], + "requireSpaceBeforeBlockStatements": true, + "requireSpacesInConditionalExpression": { + "afterTest": true, + "beforeConsequent": true, + "afterConsequent": true, + "beforeAlternate": true + }, + "requireSpacesInFunction": { + "beforeOpeningCurlyBrace": true + }, + "validateLineBreaks": "LF", + "validateParameterSeparator": ", " } \ No newline at end of file diff --git a/app/templates/server/api/thing/thing.controller(noModels).js b/app/templates/server/api/thing/thing.controller(noModels).js index 02b2410c5..a39041258 100644 --- a/app/templates/server/api/thing/thing.controller(noModels).js +++ b/app/templates/server/api/thing/thing.controller(noModels).js @@ -12,27 +12,27 @@ // Get list of things exports.index = function(req, res) { res.json([{ - name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + - 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' + name: 'Development Tools', + info: 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + + 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' }, { - name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' + name: 'Server and Client integration', + info: 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' }, { - name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + - 'Automatic injection of scripts and styles into your index.html' + name: 'Smart Build System', + info: 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + + 'Automatic injection of scripts and styles into your index.html' }, { - name : 'Modular Structure', - info : 'Best practice client and server structures allow for more code reusability and ' + - 'maximum scalability' + name: 'Modular Structure', + info: 'Best practice client and server structures allow for more code reusability and ' + + 'maximum scalability' }, { - name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript payload, minifies ' + - 'your scripts/css/images, and rewrites asset names for caching.' + name: 'Optimized Build', + info: 'Build process packs up your templates as a single JavaScript payload, minifies ' + + 'your scripts/css/images, and rewrites asset names for caching.' }, { - name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + - 'subgenerators' + name: 'Deployment Ready', + info: 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + + 'sub-generators' }]); }; diff --git a/app/templates/server/config/environment/index.js b/app/templates/server/config/environment/index.js index 2476a7e8c..fa98bbe03 100644 --- a/app/templates/server/config/environment/index.js +++ b/app/templates/server/config/environment/index.js @@ -39,20 +39,20 @@ var all = { safe: true } } - }, -<% if (filters.facebookAuth) { %> + }<% if (filters.facebookAuth) { %>, + facebook: { clientID: process.env.FACEBOOK_ID || 'id', clientSecret: process.env.FACEBOOK_SECRET || 'secret', callbackURL: (process.env.DOMAIN || '') + '/auth/facebook/callback' - }, -<% } %><% if (filters.twitterAuth) { %> + }<% } %><% if (filters.twitterAuth) { %>, + twitter: { clientID: process.env.TWITTER_ID || 'id', clientSecret: process.env.TWITTER_SECRET || 'secret', callbackURL: (process.env.DOMAIN || '') + '/auth/twitter/callback' - }, -<% } %><% if (filters.googleAuth) { %> + }<% } %><% if (filters.googleAuth) { %>, + google: { clientID: process.env.GOOGLE_ID || 'id', clientSecret: process.env.GOOGLE_SECRET || 'secret', diff --git a/app/templates/server/config/seed(models).js b/app/templates/server/config/seed(models).js index 635658010..6591f16bc 100644 --- a/app/templates/server/config/seed(models).js +++ b/app/templates/server/config/seed(models).js @@ -20,31 +20,31 @@ var Thing = sqldb.Thing; .then(function() { <% if (filters.mongooseModels) { %>Thing.create({<% } if (filters.sequelizeModels) { %>Thing.bulkCreate([{<% } %> - name : 'Development Tools', - info : 'Integration with popular tools such as Bower, Grunt, Karma, ' + + name: 'Development Tools', + info: 'Integration with popular tools such as Bower, Grunt, Karma, ' + 'Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, ' + 'Stylus, Sass, CoffeeScript, and Less.' }, { - name : 'Server and Client integration', - info : 'Built with a powerful and fun stack: MongoDB, Express, ' + + name: 'Server and Client integration', + info: 'Built with a powerful and fun stack: MongoDB, Express, ' + 'AngularJS, and Node.' }, { - name : 'Smart Build System', - info : 'Build system ignores `spec` files, allowing you to keep ' + + name: 'Smart Build System', + info: 'Build system ignores `spec` files, allowing you to keep ' + 'tests alongside code. Automatic injection of scripts and ' + 'styles into your index.html' }, { - name : 'Modular Structure', - info : 'Best practice client and server structures allow for more ' + + name: 'Modular Structure', + info: 'Best practice client and server structures allow for more ' + 'code reusability and maximum scalability' }, { - name : 'Optimized Build', - info : 'Build process packs up your templates as a single JavaScript ' + + name: 'Optimized Build', + info: 'Build process packs up your templates as a single JavaScript ' + 'payload, minifies your scripts/css/images, and rewrites asset ' + 'names for caching.' }, { - name : 'Deployment Ready', - info : 'Easily deploy your app to Heroku or Openshift with the heroku ' + + name: 'Deployment Ready', + info: 'Easily deploy your app to Heroku or Openshift with the heroku ' + 'and openshift subgenerators' <% if (filters.mongooseModels) { %>});<% } if (filters.sequelizeModels) { %>}]);<% } %> From 061c2d148819dff66da9abe8f8f25dd476cefe05 Mon Sep 17 00:00:00 2001 From: Kevin Woo Date: Sat, 11 Apr 2015 00:31:12 -0700 Subject: [PATCH 064/201] feat:app: grunt-build-control to v0.4.0 Update grunt-build-control to v0.4.0 --- app/templates/_package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 1666ea8b0..98cd616ac 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -64,7 +64,7 @@ "grunt-protractor-runner": "^1.1.0", "grunt-injector": "~0.5.4", "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control",<% if (filters.sass) { %> + "grunt-build-control": "~0.4.0",<% if (filters.sass) { %> "grunt-contrib-sass": "^0.7.3",<% } %><% if (filters.stylus) { %> "grunt-contrib-stylus": "latest",<% } %> "jit-grunt": "^0.5.0", From 366d03297e3cc76928a7fa7aaac0e209baad2221 Mon Sep 17 00:00:00 2001 From: Denis Ciccale Date: Tue, 2 Jun 2015 11:28:46 +0200 Subject: [PATCH 065/201] chore(admin): splice user without iteration --- .../client/app/admin(auth)/admin.controller(coffee).coffee | 2 +- .../client/app/admin(auth)/admin.controller(js).js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/templates/client/app/admin(auth)/admin.controller(coffee).coffee b/app/templates/client/app/admin(auth)/admin.controller(coffee).coffee index 7a16032da..5183df059 100644 --- a/app/templates/client/app/admin(auth)/admin.controller(coffee).coffee +++ b/app/templates/client/app/admin(auth)/admin.controller(coffee).coffee @@ -9,4 +9,4 @@ angular.module '<%= scriptAppName %>' $scope.delete = (user) -> User.remove id: user._id - _.remove $scope.users, user \ No newline at end of file + $scope.users.splice @$index, 1 diff --git a/app/templates/client/app/admin(auth)/admin.controller(js).js b/app/templates/client/app/admin(auth)/admin.controller(js).js index 51a52b759..3cbfd4b7f 100644 --- a/app/templates/client/app/admin(auth)/admin.controller(js).js +++ b/app/templates/client/app/admin(auth)/admin.controller(js).js @@ -8,10 +8,6 @@ angular.module('<%= scriptAppName %>') $scope.delete = function(user) { User.remove({ id: user._id }); - angular.forEach($scope.users, function(u, i) { - if (u === user) { - $scope.users.splice(i, 1); - } - }); + $scope.users.splice(this.$index, 1); }; }); From 955912c03e0e642009c417156a4eaf6a0f178af4 Mon Sep 17 00:00:00 2001 From: Pawel Wszola Date: Mon, 28 Apr 2014 14:25:55 +0200 Subject: [PATCH 066/201] feat(app): Add experimental Gulp option This is from an old PR and needs to be updated + tested --- app/index.js | 7 +- app/templates/Gulpfile.js | 275 ++++++++++++++++++++++++++++++++++++ app/templates/_package.json | 34 ++++- 3 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 app/templates/Gulpfile.js diff --git a/app/index.js b/app/index.js index 194b337a6..b0bf1e6cc 100644 --- a/app/index.js +++ b/app/index.js @@ -66,6 +66,11 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ this.log('# Client\n'); this.prompt([{ + type: 'confirm', + name: 'gulp', + message: 'Would you like to use Gulp (experimental) instead of Grunt?', + default: false + }, { type: "list", name: "script", message: "What would you like to write scripts with?", @@ -117,7 +122,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ return answers.bootstrap; } }], function (answers) { - + this.filters.gulp = !!answers.gulp; this.filters.babel = !!answers.babel; if(this.filters.babel){ this.filters.js = true; } this.filters[answers.script] = true; diff --git a/app/templates/Gulpfile.js b/app/templates/Gulpfile.js new file mode 100644 index 000000000..22381fdc0 --- /dev/null +++ b/app/templates/Gulpfile.js @@ -0,0 +1,275 @@ +// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> +'use strict'; + +var gulp = require('gulp'); +var $ = require('gulp-load-plugins')(); +var http = require('http'); +var openURL = require('open'); +var lazypipe = require('lazypipe'); +var wiredep = require('wiredep').stream; +var nodemon = require('nodemon'); +var runSequence = require('run-sequence'); +var path = require('path');<% if (stylus) { %> +var nib = require('nib');<% } %> +var config; + +var yeoman = { + app: require('./bower.json').appPath || 'app', + dist: 'dist' +}; + +var paths = { + client: { + scripts: [yeoman.app + '/scripts/**/*.<% if (coffee) { %>coffee<% } else { %>js<% } %>'], + styles: [yeoman.app + '/styles/**/*.<% if (stylus) { %>styl<% } else if (sass) { %>scss<% } else { %>css<% } %>'], + test: ['test/client/**/*.<% if (coffee) { %>coffee<% } else { %>js<% } %>'], + testRequire: [ + yeoman.app + '/bower_components/angular/angular.js', + yeoman.app + '/bower_components/angular-mocks/angular-mocks.js', + yeoman.app + '/bower_components/angular-resource/angular-resource.js', + yeoman.app + '/bower_components/angular-cookies/angular-cookies.js', + yeoman.app + '/bower_components/angular-sanitize/angular-sanitize.js', + yeoman.app + '/bower_components/angular-route/angular-route.js',<% if (coffee) { %> + 'test/mock/**/*.coffee', + 'test/spec/**/*.coffee'<% } else { %> + 'test/mock/**/*.js', + 'test/spec/**/*.js'<% } %> + ] + }, + server: {<% if (coffee) { %> + scripts: ['lib/**/*.coffee'], + test: ['test/server/**/*.coffee'],<% } else { %> + scripts: ['lib/**/*.js'], + test: ['test/server/**/*.js'],<% } %> + + }, + views: {<% if (jade) { %> + main: yeoman.app + '/views/index.jade', + files: [yeoman.app + '/views/**/*.jade']<% } else {%> + main: yeoman.app + '/views/index.html', + files: [yeoman.app + '/views/**/*.html']<% } %> + }, + karma: 'karma.conf.js' +}; + +////////////////////// +// Helper functions // +////////////////////// + +function onServerLog(log) { + console.log($.util.colors.white('[') + $.util.colors.yellow('nodemon') + $.util.colors.white('] ') + log.message); +} + +function checkAppReady(cb) { + var options = { + host: 'localhost', + port: config.port, + }; + http.get(options, function() { + cb(true); + }).on('error', function() { + cb(false); + }); +} + +// Call page until first success +function whenServerReady (cb) { + var serverReady = false; + var appReadyInterval = setInterval(function () { + checkAppReady(function(ready){ + if (!ready || serverReady) { return; } + clearInterval(appReadyInterval); + serverReady = true; + cb(); + }); + }, 100); +} + +//////////////////////// +// Reusable pipelines // +//////////////////////// + +var lintScripts = lazypipe()<% if (coffee) { %> + .pipe($.coffeelint) + .pipe($.coffeelint.reporter);<% } else { %> + .pipe($.jshint, '.jshintrc') + .pipe($.jshint.reporter, 'jshint-stylish');<% } %> + +var styles = lazypipe()<% if (stylus) { %> + .pipe($.stylus, { + use: [nib()], + errors: true + })<% } %><% if (sass) { %> + .pipe($.rubySass, { + style: 'expanded', + precision: 10 + })<% } %> + .pipe($.autoprefixer, 'last 1 version') + .pipe(gulp.dest, '.tmp/styles'); + +/////////// +// Tasks // +/////////// + +gulp.task('styles', function () { + return gulp.src(paths.client.styles) + .pipe(styles()); +});<% if (coffee) { %> + +gulp.task('coffee', function() { + return gulp.src(paths.client.scripts) + .pipe(lintScripts()) + .pipe($.coffee({bare: true}).on('error', $.util.log)) + .pipe(gulp.dest('.tmp/scripts')); +});<% } %> + +gulp.task('lint:scripts', function () { + var scripts = paths.client.scripts.concat(paths.server.scripts); + return gulp.src(scripts).pipe(lintScripts()); +}); + +gulp.task('clean:tmp', function () { + return gulp.src('.tmp', {read: false}).pipe($.clean()); +}); + +gulp.task('start:client', [<% if (coffee) { %>'coffee', <% } %>'styles'], function (callback) { + whenServerReady(function () { + openURL('http://localhost:' + config.port); + callback(); + }); +}); + +gulp.task('start:server', function () { + process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + config = require('./lib/config/config'); + nodemon('-w lib server.js') + .on('log', onServerLog); +}); + +gulp.task('watch', function () { + var testFiles = paths.client.test.concat(paths.server.test); + + $.watch({glob: paths.client.styles}) + .pipe($.plumber()) + .pipe(styles()) + .pipe($.livereload()); + + $.watch({glob: paths.views.files}) + .pipe($.plumber()) + .pipe($.livereload()); + + $.watch({glob: paths.client.scripts}) + .pipe($.plumber()) + .pipe(lintScripts())<% if (coffee) { %> + .pipe($.coffee({bare: true}).on('error', $.util.log)) + .pipe(gulp.dest('.tmp/scripts'))<% } %> + .pipe($.livereload()); + + $.watch({glob: paths.server.scripts.concat(testFiles)}) + .pipe($.plumber()) + .pipe(lintScripts()); + + gulp.watch('bower.json', ['bower']); +}); + +gulp.task('serve', function (callback) { + runSequence('clean:tmp', + ['lint:scripts'], + ['start:server', 'start:client'], + 'watch', callback); +}); + +gulp.task('test:server', function () { + process.env.NODE_ENV = 'test'; + return gulp.src(paths.server.test) + .pipe($.mocha({reporter: 'spec'})); +}); + +gulp.task('test:client', function () { + var testFiles = paths.client.testRequire.concat(paths.client.test) + gulp.src(testFiles) + .pipe($.karma({ + configFile: paths.karma, + action: 'watch' + })); +}); + +// inject bower components +gulp.task('bower', function () { + return gulp.src(paths.views.main) + .pipe(wiredep({ + directory: yeoman.app + '/bower_components', + ignorePath: '..' + })) + .pipe(gulp.dest(yeoman.app + '/views/')); +}); + +/////////// +// Build // +/////////// + +gulp.task('build', function (callback) { + runSequence('clean:dist', + ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], + callback); +}); + +gulp.task('clean:dist', function () { + return gulp.src('dist', {read: false}).pipe($.clean()); +}); + +gulp.task('client:build', ['html'], function () { + var jsFilter = $.filter('**/*.js'); + var cssFilter = $.filter('**/*.css');<% if (jade) { %> + var assets = $.filter('**/*.{js,css}');<% } %> + + return gulp.src(paths.views.main)<% if (jade) { %> + .pipe($.jade({pretty: true}))<% } %> + .pipe($.useref.assets({searchPath: [yeoman.app, '.tmp']})) + .pipe(jsFilter) + .pipe($.ngmin()) + .pipe($.uglify()) + .pipe(jsFilter.restore()) + .pipe(cssFilter) + .pipe($.minifyCss({cache: true})) + .pipe(cssFilter.restore()) + .pipe($.rev()) + .pipe($.useref.restore()) + .pipe($.revReplace()) + .pipe($.useref())<% if (jade) { %> + .pipe(assets)<% } %> + .pipe(gulp.dest(yeoman.dist + '/public')); +}); + +gulp.task('html', function () { + return gulp.src(yeoman.app + '/views/**/*') + .pipe(gulp.dest(yeoman.dist + '/public/views')); +}); + +gulp.task('images', function () { + return gulp.src(yeoman.app + '/images/**/*') + .pipe($.cache($.imagemin({ + optimizationLevel: 5, + progressive: true, + interlaced: true + }))) + .pipe(gulp.dest(yeoman.dist + '/public/images')); +}); + +gulp.task('copy:extras', function () { + return gulp.src(yeoman.app + '/*.*', { dot: true }) + .pipe(gulp.dest(yeoman.dist + '/public')); +}); + +gulp.task('copy:fonts', function () { + return gulp.src(yeoman.app + '/fonts/**/*') + .pipe(gulp.dest(yeoman.dist + '/fonts')); +}); + +gulp.task('copy:server', function(){ + return gulp.src([ + 'package.json', + 'server.js', + 'lib/**/*' + ], {cwdbase: true}).pipe(gulp.dest(yeoman.dist)); +}); diff --git a/app/templates/_package.json b/app/templates/_package.json index fc374be27..f28363a09 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -29,7 +29,37 @@ "socket.io-client": "^1.0.6", "socketio-jwt": "^3.0.0"<% } %> }, - "devDependencies": { + "devDependencies": {<% if (gulp) { %> + "gulp": "^3.6.2", + "gulp-autoprefixer": "0.0.7", + "gulp-cache": "^0.1.3", + "gulp-clean": "^0.2.4", + "gulp-filter": "^0.4.1", + "gulp-imagemin": "^0.5.0", + "gulp-jshint": "^1.5.5", + "gulp-karma": "0.0.4", + "gulp-livereload": "^1.3.1", + "gulp-load-plugins": "^0.5.0", + "gulp-plumber": "^0.6.1", + "gulp-rev": "^0.3.2", + "gulp-rev-replace": "^0.1.0", + "gulp-uglify": "^0.2.1", + "gulp-useref": "^0.4.2", + "gulp-minify-css": "^0.3.4", + "gulp-util": "^2.2.14", + "gulp-watch": "^0.6.2", + "gulp-ngmin": "^0.2.0", + "utile": "~0.2.1", + "nodemon": "^1.0.17", + "run-sequence": "^0.3.6", + "wiredep": "^1.4.4",<% if (jade) { %> + "gulp-jade": "^0.5.0",<% } %> + "lazypipe": "^0.2.1",<% if (stylus) { %> + "gulp-stylus": "^1.0.0", + "nib": "^1.0.2",<% } %><% if (sass) { %> + "gulp-ruby-sass": "^0.4.3",<% } %><% if (coffee) { %> + "gulp-coffeelint": "^0.3.2", + "gulp-coffee": "^1.4.2",<% } %><% } else { %> "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-wiredep": "~1.8.0", @@ -65,7 +95,7 @@ "grunt-build-control": "~0.4.0", "grunt-mocha-test": "~0.10.2",<% if(filters.sass) { %> "grunt-contrib-sass": "^0.7.3",<% } %><% if(filters.stylus) { %> - "grunt-contrib-stylus": "latest",<% } %> + "grunt-contrib-stylus": "latest",<% } %><% } %> "jit-grunt": "^0.5.0", "time-grunt": "~0.3.1", "grunt-express-server": "~0.4.17", From 3d369662551671425718413e241179ce68666f25 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 17 Jun 2015 13:22:53 -0400 Subject: [PATCH 067/201] fix(generator): Add missing `filters.` --- app/templates/Gulpfile.js | 32 ++++++++++++++++---------------- app/templates/_package.json | 10 +++++----- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/templates/Gulpfile.js b/app/templates/Gulpfile.js index 22381fdc0..e5e85b03a 100644 --- a/app/templates/Gulpfile.js +++ b/app/templates/Gulpfile.js @@ -9,7 +9,7 @@ var lazypipe = require('lazypipe'); var wiredep = require('wiredep').stream; var nodemon = require('nodemon'); var runSequence = require('run-sequence'); -var path = require('path');<% if (stylus) { %> +var path = require('path');<% if(filters.stylus) { %> var nib = require('nib');<% } %> var config; @@ -20,30 +20,30 @@ var yeoman = { var paths = { client: { - scripts: [yeoman.app + '/scripts/**/*.<% if (coffee) { %>coffee<% } else { %>js<% } %>'], - styles: [yeoman.app + '/styles/**/*.<% if (stylus) { %>styl<% } else if (sass) { %>scss<% } else { %>css<% } %>'], - test: ['test/client/**/*.<% if (coffee) { %>coffee<% } else { %>js<% } %>'], + scripts: [yeoman.app + '/scripts/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], + styles: [yeoman.app + '/styles/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], + test: ['test/client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], testRequire: [ yeoman.app + '/bower_components/angular/angular.js', yeoman.app + '/bower_components/angular-mocks/angular-mocks.js', yeoman.app + '/bower_components/angular-resource/angular-resource.js', yeoman.app + '/bower_components/angular-cookies/angular-cookies.js', yeoman.app + '/bower_components/angular-sanitize/angular-sanitize.js', - yeoman.app + '/bower_components/angular-route/angular-route.js',<% if (coffee) { %> + yeoman.app + '/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> 'test/mock/**/*.coffee', 'test/spec/**/*.coffee'<% } else { %> 'test/mock/**/*.js', 'test/spec/**/*.js'<% } %> ] }, - server: {<% if (coffee) { %> + server: {<% if(filters.coffee) { %> scripts: ['lib/**/*.coffee'], test: ['test/server/**/*.coffee'],<% } else { %> scripts: ['lib/**/*.js'], test: ['test/server/**/*.js'],<% } %> }, - views: {<% if (jade) { %> + views: {<% if(filters.jade) { %> main: yeoman.app + '/views/index.jade', files: [yeoman.app + '/views/**/*.jade']<% } else {%> main: yeoman.app + '/views/index.html', @@ -89,17 +89,17 @@ function whenServerReady (cb) { // Reusable pipelines // //////////////////////// -var lintScripts = lazypipe()<% if (coffee) { %> +var lintScripts = lazypipe()<% if(filters.coffee) { %> .pipe($.coffeelint) .pipe($.coffeelint.reporter);<% } else { %> .pipe($.jshint, '.jshintrc') .pipe($.jshint.reporter, 'jshint-stylish');<% } %> -var styles = lazypipe()<% if (stylus) { %> +var styles = lazypipe()<% if(filters.stylus) { %> .pipe($.stylus, { use: [nib()], errors: true - })<% } %><% if (sass) { %> + })<% } %><% if(filters.sass) { %> .pipe($.rubySass, { style: 'expanded', precision: 10 @@ -114,7 +114,7 @@ var styles = lazypipe()<% if (stylus) { %> gulp.task('styles', function () { return gulp.src(paths.client.styles) .pipe(styles()); -});<% if (coffee) { %> +});<% if(filters.coffee) { %> gulp.task('coffee', function() { return gulp.src(paths.client.scripts) @@ -132,7 +132,7 @@ gulp.task('clean:tmp', function () { return gulp.src('.tmp', {read: false}).pipe($.clean()); }); -gulp.task('start:client', [<% if (coffee) { %>'coffee', <% } %>'styles'], function (callback) { +gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], function (callback) { whenServerReady(function () { openURL('http://localhost:' + config.port); callback(); @@ -160,7 +160,7 @@ gulp.task('watch', function () { $.watch({glob: paths.client.scripts}) .pipe($.plumber()) - .pipe(lintScripts())<% if (coffee) { %> + .pipe(lintScripts())<% if(filters.coffee) { %> .pipe($.coffee({bare: true}).on('error', $.util.log)) .pipe(gulp.dest('.tmp/scripts'))<% } %> .pipe($.livereload()); @@ -220,10 +220,10 @@ gulp.task('clean:dist', function () { gulp.task('client:build', ['html'], function () { var jsFilter = $.filter('**/*.js'); - var cssFilter = $.filter('**/*.css');<% if (jade) { %> + var cssFilter = $.filter('**/*.css');<% if(filters.jade) { %> var assets = $.filter('**/*.{js,css}');<% } %> - return gulp.src(paths.views.main)<% if (jade) { %> + return gulp.src(paths.views.main)<% if(filters.jade) { %> .pipe($.jade({pretty: true}))<% } %> .pipe($.useref.assets({searchPath: [yeoman.app, '.tmp']})) .pipe(jsFilter) @@ -236,7 +236,7 @@ gulp.task('client:build', ['html'], function () { .pipe($.rev()) .pipe($.useref.restore()) .pipe($.revReplace()) - .pipe($.useref())<% if (jade) { %> + .pipe($.useref())<% if(filters.jade) { %> .pipe(assets)<% } %> .pipe(gulp.dest(yeoman.dist + '/public')); }); diff --git a/app/templates/_package.json b/app/templates/_package.json index f28363a09..941490d1c 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -29,7 +29,7 @@ "socket.io-client": "^1.0.6", "socketio-jwt": "^3.0.0"<% } %> }, - "devDependencies": {<% if (gulp) { %> + "devDependencies": {<% if(filters.gulp) { %> "gulp": "^3.6.2", "gulp-autoprefixer": "0.0.7", "gulp-cache": "^0.1.3", @@ -52,12 +52,12 @@ "utile": "~0.2.1", "nodemon": "^1.0.17", "run-sequence": "^0.3.6", - "wiredep": "^1.4.4",<% if (jade) { %> + "wiredep": "^1.4.4",<% if(filters.jade) { %> "gulp-jade": "^0.5.0",<% } %> - "lazypipe": "^0.2.1",<% if (stylus) { %> + "lazypipe": "^0.2.1",<% if(filters.stylus) { %> "gulp-stylus": "^1.0.0", - "nib": "^1.0.2",<% } %><% if (sass) { %> - "gulp-ruby-sass": "^0.4.3",<% } %><% if (coffee) { %> + "nib": "^1.0.2",<% } %><% if(filters.sass) { %> + "gulp-ruby-sass": "^0.4.3",<% } %><% if(filters.coffee) { %> "gulp-coffeelint": "^0.3.2", "gulp-coffee": "^1.4.2",<% } %><% } else { %> "grunt": "~0.4.4", From 1e977640aa07159c9a1db41ec5a058fd85ea1721 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 17 Jun 2015 14:48:01 -0400 Subject: [PATCH 068/201] feat(gulp): Update to Gulp 3.9.0 and rename Gulpfile.js to gulpfile.babel.js --- app/templates/_package.json | 2 +- app/templates/{Gulpfile.js => gulpfile.babel.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename app/templates/{Gulpfile.js => gulpfile.babel.js} (100%) diff --git a/app/templates/_package.json b/app/templates/_package.json index 941490d1c..181ec02db 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -30,7 +30,7 @@ "socketio-jwt": "^3.0.0"<% } %> }, "devDependencies": {<% if(filters.gulp) { %> - "gulp": "^3.6.2", + "gulp": "^3.9.0", "gulp-autoprefixer": "0.0.7", "gulp-cache": "^0.1.3", "gulp-clean": "^0.2.4", diff --git a/app/templates/Gulpfile.js b/app/templates/gulpfile.babel.js similarity index 100% rename from app/templates/Gulpfile.js rename to app/templates/gulpfile.babel.js From c67f1e553aba6d01ff2351c2f24e3fe49092bc2f Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 17 Jun 2015 15:32:02 -0400 Subject: [PATCH 069/201] refactor(gulp): Rename $ to plugins --- app/templates/gulpfile.babel.js | 78 ++++++++++++++++----------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index e5e85b03a..4525e3ef2 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -2,7 +2,7 @@ 'use strict'; var gulp = require('gulp'); -var $ = require('gulp-load-plugins')(); +var plugins = require('gulp-load-plugins')(); var http = require('http'); var openURL = require('open'); var lazypipe = require('lazypipe'); @@ -57,7 +57,7 @@ var paths = { ////////////////////// function onServerLog(log) { - console.log($.util.colors.white('[') + $.util.colors.yellow('nodemon') + $.util.colors.white('] ') + log.message); + console.log(plugins.util.colors.white('[') + plugins.util.colors.yellow('nodemon') + plugins.util.colors.white('] ') + log.message); } function checkAppReady(cb) { @@ -90,21 +90,21 @@ function whenServerReady (cb) { //////////////////////// var lintScripts = lazypipe()<% if(filters.coffee) { %> - .pipe($.coffeelint) - .pipe($.coffeelint.reporter);<% } else { %> - .pipe($.jshint, '.jshintrc') - .pipe($.jshint.reporter, 'jshint-stylish');<% } %> + .pipe(plugins.coffeelint) + .pipe(plugins.coffeelint.reporter);<% } else { %> + .pipe(plugins.jshint, '.jshintrc') + .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> var styles = lazypipe()<% if(filters.stylus) { %> - .pipe($.stylus, { + .pipe(plugins.stylus, { use: [nib()], errors: true })<% } %><% if(filters.sass) { %> - .pipe($.rubySass, { + .pipe(plugins.rubySass, { style: 'expanded', precision: 10 })<% } %> - .pipe($.autoprefixer, 'last 1 version') + .pipe(plugins.autoprefixer, 'last 1 version') .pipe(gulp.dest, '.tmp/styles'); /////////// @@ -119,7 +119,7 @@ gulp.task('styles', function () { gulp.task('coffee', function() { return gulp.src(paths.client.scripts) .pipe(lintScripts()) - .pipe($.coffee({bare: true}).on('error', $.util.log)) + .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts')); });<% } %> @@ -129,7 +129,7 @@ gulp.task('lint:scripts', function () { }); gulp.task('clean:tmp', function () { - return gulp.src('.tmp', {read: false}).pipe($.clean()); + return gulp.src('.tmp', {read: false}).pipe(plugins.clean()); }); gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], function (callback) { @@ -149,24 +149,24 @@ gulp.task('start:server', function () { gulp.task('watch', function () { var testFiles = paths.client.test.concat(paths.server.test); - $.watch({glob: paths.client.styles}) - .pipe($.plumber()) + plugins.watch({glob: paths.client.styles}) + .pipe(plugins.plumber()) .pipe(styles()) - .pipe($.livereload()); + .pipe(plugins.livereload()); - $.watch({glob: paths.views.files}) - .pipe($.plumber()) - .pipe($.livereload()); + plugins.watch({glob: paths.views.files}) + .pipe(plugins.plumber()) + .pipe(plugins.livereload()); - $.watch({glob: paths.client.scripts}) - .pipe($.plumber()) + plugins.watch({glob: paths.client.scripts}) + .pipe(plugins.plumber()) .pipe(lintScripts())<% if(filters.coffee) { %> - .pipe($.coffee({bare: true}).on('error', $.util.log)) + .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts'))<% } %> - .pipe($.livereload()); + .pipe(plugins.livereload()); - $.watch({glob: paths.server.scripts.concat(testFiles)}) - .pipe($.plumber()) + plugins.watch({glob: paths.server.scripts.concat(testFiles)}) + .pipe(plugins.plumber()) .pipe(lintScripts()); gulp.watch('bower.json', ['bower']); @@ -182,13 +182,13 @@ gulp.task('serve', function (callback) { gulp.task('test:server', function () { process.env.NODE_ENV = 'test'; return gulp.src(paths.server.test) - .pipe($.mocha({reporter: 'spec'})); + .pipe(plugins.mocha({reporter: 'spec'})); }); gulp.task('test:client', function () { var testFiles = paths.client.testRequire.concat(paths.client.test) gulp.src(testFiles) - .pipe($.karma({ + .pipe(plugins.karma({ configFile: paths.karma, action: 'watch' })); @@ -215,28 +215,28 @@ gulp.task('build', function (callback) { }); gulp.task('clean:dist', function () { - return gulp.src('dist', {read: false}).pipe($.clean()); + return gulp.src('dist', {read: false}).pipe(plugins.clean()); }); gulp.task('client:build', ['html'], function () { - var jsFilter = $.filter('**/*.js'); - var cssFilter = $.filter('**/*.css');<% if(filters.jade) { %> - var assets = $.filter('**/*.{js,css}');<% } %> + var jsFilter = plugins.filter('**/*.js'); + var cssFilter = plugins.filter('**/*.css');<% if(filters.jade) { %> + var assets = plugins.filter('**/*.{js,css}');<% } %> return gulp.src(paths.views.main)<% if(filters.jade) { %> - .pipe($.jade({pretty: true}))<% } %> - .pipe($.useref.assets({searchPath: [yeoman.app, '.tmp']})) + .pipe(plugins.jade({pretty: true}))<% } %> + .pipe(plugins.useref.assets({searchPath: [yeoman.app, '.tmp']})) .pipe(jsFilter) - .pipe($.ngmin()) - .pipe($.uglify()) + .pipe(plugins.ngmin()) + .pipe(plugins.uglify()) .pipe(jsFilter.restore()) .pipe(cssFilter) - .pipe($.minifyCss({cache: true})) + .pipe(plugins.minifyCss({cache: true})) .pipe(cssFilter.restore()) - .pipe($.rev()) - .pipe($.useref.restore()) - .pipe($.revReplace()) - .pipe($.useref())<% if(filters.jade) { %> + .pipe(plugins.rev()) + .pipe(plugins.useref.restore()) + .pipe(plugins.revReplace()) + .pipe(plugins.useref())<% if(filters.jade) { %> .pipe(assets)<% } %> .pipe(gulp.dest(yeoman.dist + '/public')); }); @@ -248,7 +248,7 @@ gulp.task('html', function () { gulp.task('images', function () { return gulp.src(yeoman.app + '/images/**/*') - .pipe($.cache($.imagemin({ + .pipe(plugins.cache(plugins.imagemin({ optimizationLevel: 5, progressive: true, interlaced: true From e9af2b21dae4575884f4fd28532cc7806b6adcab Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 17 Jun 2015 15:32:33 -0400 Subject: [PATCH 070/201] refactor(gulp): Use import for gulp and path --- app/templates/gulpfile.babel.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 4525e3ef2..eae6a910a 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -1,7 +1,9 @@ // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 'use strict'; -var gulp = require('gulp'); +import gulp from 'gulp'; +import path from 'path'; + var plugins = require('gulp-load-plugins')(); var http = require('http'); var openURL = require('open'); @@ -9,7 +11,6 @@ var lazypipe = require('lazypipe'); var wiredep = require('wiredep').stream; var nodemon = require('nodemon'); var runSequence = require('run-sequence'); -var path = require('path');<% if(filters.stylus) { %> var nib = require('nib');<% } %> var config; From 10708a46b37c7c6902a74713dd1e0cc690bc3fec Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 17 Jun 2015 15:33:13 -0400 Subject: [PATCH 071/201] fix(gulp): Add if(filters.stylus) statement back --- app/templates/gulpfile.babel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index eae6a910a..3a1c61fc3 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -10,7 +10,7 @@ var openURL = require('open'); var lazypipe = require('lazypipe'); var wiredep = require('wiredep').stream; var nodemon = require('nodemon'); -var runSequence = require('run-sequence'); +var runSequence = require('run-sequence');<% if(filters.stylus) { %> var nib = require('nib');<% } %> var config; From d1ba9ef63ddece2ef8a4449bf2854b0d4698529d Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Thu, 18 Jun 2015 00:47:27 -0400 Subject: [PATCH 072/201] feat(gulp): Fix a bunch of things, update a buttload of packages.. It's still not working, but there's progress. It seems like none of my files are getting put into the .tmp directory, and wiredep isn't putting anything in index.html --- app/templates/_package.json | 55 ++++++++++++++-------------- app/templates/gulpfile.babel.js | 63 ++++++++++++++++----------------- 2 files changed, 58 insertions(+), 60 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 181ec02db..ad713fdc4 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -31,35 +31,36 @@ }, "devDependencies": {<% if(filters.gulp) { %> "gulp": "^3.9.0", - "gulp-autoprefixer": "0.0.7", - "gulp-cache": "^0.1.3", - "gulp-clean": "^0.2.4", - "gulp-filter": "^0.4.1", - "gulp-imagemin": "^0.5.0", - "gulp-jshint": "^1.5.5", + "gulp-autoprefixer": "2.3.1", + "gulp-cache": "^0.2.10", + "gulp-clean": "^0.3.1", + "gulp-filter": "^2.0.2", + "gulp-imagemin": "^2.2.1", + "gulp-jshint": "^1.11.0", "gulp-karma": "0.0.4", - "gulp-livereload": "^1.3.1", - "gulp-load-plugins": "^0.5.0", - "gulp-plumber": "^0.6.1", - "gulp-rev": "^0.3.2", - "gulp-rev-replace": "^0.1.0", - "gulp-uglify": "^0.2.1", + "gulp-livereload": "^3.8.0", + "gulp-load-plugins": "^1.0.0-rc.1", + "gulp-minify-css": "^1.1.6", + "gulp-ngmin": "^0.3.0", + "gulp-plumber": "^1.0.1", + "gulp-rev": "^5.0.0", + "gulp-rev-replace": "^0.4.2", + "gulp-svgmin": "^1.1.2", + "gulp-uglify": "^1.2.0", "gulp-useref": "^0.4.2", - "gulp-minify-css": "^0.3.4", - "gulp-util": "^2.2.14", - "gulp-watch": "^0.6.2", - "gulp-ngmin": "^0.2.0", - "utile": "~0.2.1", - "nodemon": "^1.0.17", - "run-sequence": "^0.3.6", - "wiredep": "^1.4.4",<% if(filters.jade) { %> - "gulp-jade": "^0.5.0",<% } %> - "lazypipe": "^0.2.1",<% if(filters.stylus) { %> - "gulp-stylus": "^1.0.0", - "nib": "^1.0.2",<% } %><% if(filters.sass) { %> - "gulp-ruby-sass": "^0.4.3",<% } %><% if(filters.coffee) { %> - "gulp-coffeelint": "^0.3.2", - "gulp-coffee": "^1.4.2",<% } %><% } else { %> + "gulp-util": "^3.0.5", + "gulp-watch": "^4.2.4", + "utile": "~0.3.0", + "nodemon": "^1.3.7", + "run-sequence": "^1.1.0", + "lazypipe": "^0.2.3", + "wiredep": "^2.2.2",<% if(filters.jade) { %> + "gulp-jade": "^1.0.1",<% } %><% if(filters.stylus) { %> + "gulp-stylus": "^2.0.4", + "nib": "^1.1.0",<% } %><% if(filters.sass) { %> + "gulp-ruby-sass": "^1.0.5",<% } %><% if(filters.coffee) { %> + "gulp-coffeelint": "^0.5.0", + "gulp-coffee": "^2.3.1",<% } %><% } else { %> "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-wiredep": "~1.8.0", diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 3a1c61fc3..ff10d0b10 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -21,34 +21,35 @@ var yeoman = { var paths = { client: { - scripts: [yeoman.app + '/scripts/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], - styles: [yeoman.app + '/styles/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], - test: ['test/client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], + scripts: [ + 'client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>', + '!client/bower_components/**/*.js' + ], + styles: ['client/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], + test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], testRequire: [ - yeoman.app + '/bower_components/angular/angular.js', - yeoman.app + '/bower_components/angular-mocks/angular-mocks.js', - yeoman.app + '/bower_components/angular-resource/angular-resource.js', - yeoman.app + '/bower_components/angular-cookies/angular-cookies.js', - yeoman.app + '/bower_components/angular-sanitize/angular-sanitize.js', - yeoman.app + '/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> - 'test/mock/**/*.coffee', - 'test/spec/**/*.coffee'<% } else { %> - 'test/mock/**/*.js', - 'test/spec/**/*.js'<% } %> + 'client/bower_components/angular/angular.js', + 'client/bower_components/angular-mocks/angular-mocks.js', + 'client/bower_components/angular-resource/angular-resource.js', + 'client/bower_components/angular-cookies/angular-cookies.js', + 'client/bower_components/angular-sanitize/angular-sanitize.js', + 'client/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> + 'client/**/*.spec.coffee'<% } else { %> + 'client/**/*.spec.js'<% } %> ] }, server: {<% if(filters.coffee) { %> - scripts: ['lib/**/*.coffee'], - test: ['test/server/**/*.coffee'],<% } else { %> - scripts: ['lib/**/*.js'], - test: ['test/server/**/*.js'],<% } %> + scripts: ['server/**/*.coffee'], + test: ['server/**/*.spec.coffee'],<% } else { %> + scripts: ['server/**/*.js'], + test: ['server/**/*.spec.js'],<% } %> }, views: {<% if(filters.jade) { %> - main: yeoman.app + '/views/index.jade', - files: [yeoman.app + '/views/**/*.jade']<% } else {%> - main: yeoman.app + '/views/index.html', - files: [yeoman.app + '/views/**/*.html']<% } %> + main: 'client/app/index.jade', + files: ['client/app/**/*.jade']<% } else {%> + main: 'client/app/index.html', + files: ['client/app/**/*.html']<% } %> }, karma: 'karma.conf.js' }; @@ -101,10 +102,7 @@ var styles = lazypipe()<% if(filters.stylus) { %> use: [nib()], errors: true })<% } %><% if(filters.sass) { %> - .pipe(plugins.rubySass, { - style: 'expanded', - precision: 10 - })<% } %> + .pipe(plugins.rubySass, paths.client.styles)<% } %> .pipe(plugins.autoprefixer, 'last 1 version') .pipe(gulp.dest, '.tmp/styles'); @@ -113,8 +111,7 @@ var styles = lazypipe()<% if(filters.stylus) { %> /////////// gulp.task('styles', function () { - return gulp.src(paths.client.styles) - .pipe(styles()); + return styles(); });<% if(filters.coffee) { %> gulp.task('coffee', function() { @@ -142,31 +139,31 @@ gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], gulp.task('start:server', function () { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; - config = require('./lib/config/config'); - nodemon('-w lib server.js') + config = require('./server/config/environment'); + nodemon('-w lib server/app.js') .on('log', onServerLog); }); gulp.task('watch', function () { var testFiles = paths.client.test.concat(paths.server.test); - plugins.watch({glob: paths.client.styles}) + plugins.watch(paths.client.styles) .pipe(plugins.plumber()) .pipe(styles()) .pipe(plugins.livereload()); - plugins.watch({glob: paths.views.files}) + plugins.watch(paths.views.files) .pipe(plugins.plumber()) .pipe(plugins.livereload()); - plugins.watch({glob: paths.client.scripts}) + plugins.watch(paths.client.scripts) .pipe(plugins.plumber()) .pipe(lintScripts())<% if(filters.coffee) { %> .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts'))<% } %> .pipe(plugins.livereload()); - plugins.watch({glob: paths.server.scripts.concat(testFiles)}) + plugins.watch(paths.server.scripts.concat(testFiles)) .pipe(plugins.plumber()) .pipe(lintScripts()); From 39e0667e03171452b01b6cac304d7d27e25865ee Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Thu, 18 Jun 2015 00:57:16 -0400 Subject: [PATCH 073/201] refactor(gulp): Convert the rest of the require statements to ES2015 imports --- app/templates/gulpfile.babel.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index ff10d0b10..70825398f 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -3,15 +3,16 @@ import gulp from 'gulp'; import path from 'path'; - -var plugins = require('gulp-load-plugins')(); -var http = require('http'); -var openURL = require('open'); -var lazypipe = require('lazypipe'); -var wiredep = require('wiredep').stream; -var nodemon = require('nodemon'); -var runSequence = require('run-sequence');<% if(filters.stylus) { %> -var nib = require('nib');<% } %> +import gulpLoadPlugins from 'gulp-load-plugins'; +import http from 'http'; +import open from 'open'; +import lazypipe from 'lazypipe'; +import {stream as wiredep} from 'wiredep'; +import nodemon from 'nodemon'; +import runSequence from 'run-sequence';<% if(filters.stylus) { %> +import nib from 'nib';<% } %> + +var plugins = gulpLoadPlugins(); var config; var yeoman = { @@ -132,7 +133,7 @@ gulp.task('clean:tmp', function () { gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], function (callback) { whenServerReady(function () { - openURL('http://localhost:' + config.port); + open('http://localhost:' + config.port); callback(); }); }); From d2811661fbaba81e9c33a9837f7c1828c225a5af Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 20 Jun 2015 04:57:05 -0400 Subject: [PATCH 074/201] chore(test): update chai related test libs --- app/templates/_package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 98cd616ac..8549daba0 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -76,11 +76,11 @@ "connect-livereload": "~0.4.0", "grunt-mocha-test": "~0.10.2", "grunt-mocha-istanbul": "^2.0.0", - "chai-as-promised": "^4.1.1", + "chai-as-promised": "^5.1.0", "chai-things": "^0.2.0", - "sinon-chai": "^2.5.0",<% if (filters.mocha) { %> + "sinon-chai": "^2.8.0",<% if (filters.mocha) { %> "karma-mocha": "^0.1.9", - "karma-chai-plugins": "^0.2.3",<% } if (filters.jasmine) { %> + "karma-chai-plugins": "^0.6.0",<% } if (filters.jasmine) { %> "karma-jasmine": "~0.1.5",<% } %> "karma-ng-scenario": "~0.1.0", "karma-firefox-launcher": "~0.1.3", From 8df999229c5984b33fcccddd5335f2aeffc4e8c9 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 20 Jun 2015 05:42:40 -0400 Subject: [PATCH 075/201] fix(test): update sequelize destroy usage --- .../login/login.spec(jasmine).js | 2 +- .../account(auth)/login/login.spec(mocha).js | 4 ++-- .../logout/logout.spec(jasmine).js | 2 +- .../logout/logout.spec(mocha).js | 4 ++-- .../signup/signup.spec(jasmine).js | 2 +- .../signup/signup.spec(mocha).js | 4 ++-- .../server/api/user(auth)/user.integration.js | 23 ++++++------------- .../user.model.spec(sequelizeModels).js | 6 ++--- 8 files changed, 19 insertions(+), 28 deletions(-) diff --git a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js index e690c2601..c738f9370 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js @@ -20,7 +20,7 @@ describe('Login View', function() { beforeEach(function(done) { <% if (filters.mongooseModels) { %>UserModel.removeAsync()<% } - if (filters.sequelizeModels) { %>UserModel.destroy()<% } %> + if (filters.sequelizeModels) { %>UserModel.destroy({ where: {} })<% } %> .then(function() { <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> diff --git a/app/templates/e2e/account(auth)/login/login.spec(mocha).js b/app/templates/e2e/account(auth)/login/login.spec(mocha).js index 3335cf3b4..6b3158726 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(mocha).js +++ b/app/templates/e2e/account(auth)/login/login.spec(mocha).js @@ -21,7 +21,7 @@ describe('Login View', function() { before(function() { return UserModel <% if (filters.mongooseModels) { %>.removeAsync()<% } - if (filters.sequelizeModels) { %>.destroy()<% } %> + if (filters.sequelizeModels) { %>.destroy({ where: {} })<% } %> .then(function() { <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> @@ -31,7 +31,7 @@ describe('Login View', function() { after(function() { <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } - if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> + if (filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> }); it('should include login form with correct inputs and submit button', function() { diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js index f3149865c..ae4bb23a0 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js @@ -18,7 +18,7 @@ describe('Logout View', function() { beforeEach(function(done) { <% if (filters.mongooseModels) { %>UserModel.removeAsync()<% } - if (filters.sequelizeModels) { %>UserModel.destroy()<% } %> + if (filters.sequelizeModels) { %>UserModel.destroy({ where: {} })<% } %> .then(function() { <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js index 85d92cf75..ef9f6d4da 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js @@ -19,7 +19,7 @@ describe('Logout View', function() { beforeEach(function() { return UserModel <% if (filters.mongooseModels) { %>.removeAsync()<% } - if (filters.sequelizeModels) { %>.destroy()<% } %> + if (filters.sequelizeModels) { %>.destroy({ where: {} })<% } %> .then(function() { <% if (filters.mongooseModels) { %>return UserModel.createAsync(testUser);<% } if (filters.sequelizeModels) { %>return UserModel.create(testUser);<% } %> @@ -31,7 +31,7 @@ describe('Logout View', function() { after(function() { <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } - if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> + if (filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> }) describe('with local auth', function() { diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js index abbfc98a4..511a84933 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js @@ -37,7 +37,7 @@ describe('Signup View', function() { it('should signup a new user, log them in, and redirecting to "/"', function(done) { <% if (filters.mongooseModels) { %>UserModel.remove(function() {<% } - if (filters.sequelizeModels) { %>UserModel.destroy().then(function() {<% } %> + if (filters.sequelizeModels) { %>UserModel.destroy({ where: {} }).then(function() {<% } %> page.signup(testUser); var navbar = require('../../components/navbar/navbar.po'); diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js index 5351ea75d..852a3cb71 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js @@ -24,7 +24,7 @@ describe('Signup View', function() { after(function() { <% if (filters.mongooseModels) { %>return UserModel.removeAsync();<% } - if (filters.sequelizeModels) { %>return UserModel.destroy();<% } %> + if (filters.sequelizeModels) { %>return UserModel.destroy({ where: {} });<% } %> }); it('should include signup form with correct inputs and submit button', function() { @@ -42,7 +42,7 @@ describe('Signup View', function() { it('should signup a new user, log them in, and redirecting to "/"', function(done) { <% if (filters.mongooseModels) { %>UserModel.remove(function() {<% } - if (filters.sequelizeModels) { %>UserModel.destroy().then(function() {<% } %> + if (filters.sequelizeModels) { %>UserModel.destroy({ where: {} }).then(function() {<% } %> page.signup(testUser); var navbar = require('../../components/navbar/navbar.po'); diff --git a/app/templates/server/api/user(auth)/user.integration.js b/app/templates/server/api/user(auth)/user.integration.js index 35bcdb573..5273be72a 100644 --- a/app/templates/server/api/user(auth)/user.integration.js +++ b/app/templates/server/api/user(auth)/user.integration.js @@ -9,9 +9,9 @@ describe('User API:', function() { var user; // Clear users before testing - before(function(done) { - <% if (filters.mongooseModels) { %>User.remove(function() {<% } - if (filters.sequelizeModels) { %>User.destroy().then(function() {<% } %> + before(function() { + return <% if (filters.mongooseModels) { %>User.removeAsync().then(function() {<% } + if (filters.sequelizeModels) { %>User.destroy({ where: {} }).then(function() {<% } %> <% if (filters.mongooseModels) { %>user = new User({<% } if (filters.sequelizeModels) { %>user = User.build({<% } %> name: 'Fake User', @@ -19,24 +19,15 @@ describe('User API:', function() { password: 'password' }); - <% if (filters.mongooseModels) { %>user.save(function(err) { - if (err) { - return done(err); - } - done(); - });<% } - if (filters.sequelizeModels) { %>user.save().then(function() { - done(); - }, function(err) { - return done(err); - });<% } %> + return <% if (filters.mongooseModels) { %>user.saveAsync();<% } + if (filters.sequelizeModels) { %>user.save();<% } %> }); }); // Clear users after testing after(function() { - <% if (filters.mongooseModels) { %>return User.remove().exec();<% } - if (filters.sequelizeModels) { %>return User.destroy();<% } %> + <% if (filters.mongooseModels) { %>return User.removeAsync();<% } + if (filters.sequelizeModels) { %>return User.destroy({ where: {} });<% } %> }); describe('GET /api/users/me', function() { diff --git a/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js index 88156151b..f499667cd 100644 --- a/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js +++ b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js @@ -15,13 +15,13 @@ var user = User.build(userTemplate); describe('User Model', function() { before(function() { // Sync and clear users before testing - User.sync().then(function() { - return User.destroy(); + return User.sync().then(function() { + return User.destroy({ where: {} }); }); }); afterEach(function() { - return User.destroy(); + return User.destroy({ where: {} }); }); it('should begin with no users', function() { From c7f6c360dca99c7741695158a5b6cfda969e3594 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 20 Jun 2015 06:41:12 -0400 Subject: [PATCH 076/201] fix(test): change `protractor.getInstance` to `browser` --- app/templates/e2e/account(auth)/login/login.spec(jasmine).js | 2 +- app/templates/e2e/account(auth)/login/login.spec(mocha).js | 2 +- app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js | 2 +- app/templates/e2e/account(auth)/logout/logout.spec(mocha).js | 2 +- app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js | 2 +- app/templates/e2e/account(auth)/signup/signup.spec(mocha).js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js index c738f9370..8b31d4d6b 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/login/login.spec(jasmine).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> diff --git a/app/templates/e2e/account(auth)/login/login.spec(mocha).js b/app/templates/e2e/account(auth)/login/login.spec(mocha).js index 6b3158726..57222c1e4 100644 --- a/app/templates/e2e/account(auth)/login/login.spec(mocha).js +++ b/app/templates/e2e/account(auth)/login/login.spec(mocha).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js index ae4bb23a0..fc10a1684 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(jasmine).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> diff --git a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js index ef9f6d4da..5268456de 100644 --- a/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js +++ b/app/templates/e2e/account(auth)/logout/logout.spec(mocha).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js index 511a84933..1613d3ae8 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(jasmine).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> diff --git a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js index 852a3cb71..e4855cc11 100644 --- a/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js +++ b/app/templates/e2e/account(auth)/signup/signup.spec(mocha).js @@ -1,6 +1,6 @@ 'use strict'; -var config = protractor.getInstance().params;<% if (filters.mongooseModels) { %> +var config = browser.params;<% if (filters.mongooseModels) { %> var UserModel = require(config.serverConfig.root + '/server/api/user/user.model');<% } %><% if (filters.sequelizeModels) { %> var UserModel = require(config.serverConfig.root + '/server/sqldb').User;<% } %> From 1d5fd55496f8ca6e33b24816034439f4a1f2eea8 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 14:01:40 -0400 Subject: [PATCH 077/201] fix(travis): Remove node 10 & 11 targets --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5434c4542..8937d71b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js node_js: - - '0.10' - - '0.11' - '0.12' before_install: - gem update --system From 236417884ebb53ef8bedca9f42303be7e241e156 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 15:26:00 -0400 Subject: [PATCH 078/201] fix(gulp): Make wiredep work for the bower task, and refactor a few path variables --- app/templates/gulpfile.babel.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 70825398f..22bd4239f 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -16,8 +16,7 @@ var plugins = gulpLoadPlugins(); var config; var yeoman = { - app: require('./bower.json').appPath || 'app', - dist: 'dist' + app: require('./bower.json').appPath || 'client/app' }; var paths = { @@ -37,7 +36,8 @@ var paths = { 'client/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> 'client/**/*.spec.coffee'<% } else { %> 'client/**/*.spec.js'<% } %> - ] + ], + bower: 'client/bower_components/' }, server: {<% if(filters.coffee) { %> scripts: ['server/**/*.coffee'], @@ -47,12 +47,13 @@ var paths = { }, views: {<% if(filters.jade) { %> - main: 'client/app/index.jade', + main: 'client/index.jade', files: ['client/app/**/*.jade']<% } else {%> - main: 'client/app/index.html', + main: 'client/index.html', files: ['client/app/**/*.html']<% } %> }, - karma: 'karma.conf.js' + karma: 'karma.conf.js', + dist: 'dist' }; ////////////////////// @@ -174,6 +175,7 @@ gulp.task('watch', function () { gulp.task('serve', function (callback) { runSequence('clean:tmp', ['lint:scripts'], + 'bower', ['start:server', 'start:client'], 'watch', callback); }); @@ -197,10 +199,9 @@ gulp.task('test:client', function () { gulp.task('bower', function () { return gulp.src(paths.views.main) .pipe(wiredep({ - directory: yeoman.app + '/bower_components', - ignorePath: '..' + exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] })) - .pipe(gulp.dest(yeoman.app + '/views/')); + .pipe(gulp.dest('client/')); }); /////////// @@ -237,12 +238,12 @@ gulp.task('client:build', ['html'], function () { .pipe(plugins.revReplace()) .pipe(plugins.useref())<% if(filters.jade) { %> .pipe(assets)<% } %> - .pipe(gulp.dest(yeoman.dist + '/public')); + .pipe(gulp.dest(paths.dist + '/public')); }); gulp.task('html', function () { return gulp.src(yeoman.app + '/views/**/*') - .pipe(gulp.dest(yeoman.dist + '/public/views')); + .pipe(gulp.dest(paths.dist + '/public/views')); }); gulp.task('images', function () { @@ -252,17 +253,17 @@ gulp.task('images', function () { progressive: true, interlaced: true }))) - .pipe(gulp.dest(yeoman.dist + '/public/images')); + .pipe(gulp.dest(paths.dist + '/public/images')); }); gulp.task('copy:extras', function () { return gulp.src(yeoman.app + '/*.*', { dot: true }) - .pipe(gulp.dest(yeoman.dist + '/public')); + .pipe(gulp.dest(paths.dist + '/public')); }); gulp.task('copy:fonts', function () { return gulp.src(yeoman.app + '/fonts/**/*') - .pipe(gulp.dest(yeoman.dist + '/fonts')); + .pipe(gulp.dest(paths.dist + '/fonts')); }); gulp.task('copy:server', function(){ @@ -270,5 +271,5 @@ gulp.task('copy:server', function(){ 'package.json', 'server.js', 'lib/**/*' - ], {cwdbase: true}).pipe(gulp.dest(yeoman.dist)); + ], {cwdbase: true}).pipe(gulp.dest(paths.dist)); }); From 58bafcd963cf6adce1309a7e568229f2e07f8dc6 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 19:53:53 -0400 Subject: [PATCH 079/201] style(gulp): Use 4-space tabs --- app/templates/gulpfile.babel.js | 323 ++++++++++++++++---------------- 1 file changed, 162 insertions(+), 161 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 22bd4239f..a8226fa14 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -16,44 +16,43 @@ var plugins = gulpLoadPlugins(); var config; var yeoman = { - app: require('./bower.json').appPath || 'client/app' + app: require('./bower.json').appPath || 'client/app' }; var paths = { - client: { - scripts: [ - 'client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>', - '!client/bower_components/**/*.js' - ], - styles: ['client/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], - test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], - testRequire: [ - 'client/bower_components/angular/angular.js', - 'client/bower_components/angular-mocks/angular-mocks.js', - 'client/bower_components/angular-resource/angular-resource.js', - 'client/bower_components/angular-cookies/angular-cookies.js', - 'client/bower_components/angular-sanitize/angular-sanitize.js', - 'client/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> - 'client/**/*.spec.coffee'<% } else { %> - 'client/**/*.spec.js'<% } %> - ], - bower: 'client/bower_components/' - }, - server: {<% if(filters.coffee) { %> - scripts: ['server/**/*.coffee'], - test: ['server/**/*.spec.coffee'],<% } else { %> - scripts: ['server/**/*.js'], - test: ['server/**/*.spec.js'],<% } %> - - }, - views: {<% if(filters.jade) { %> - main: 'client/index.jade', - files: ['client/app/**/*.jade']<% } else {%> - main: 'client/index.html', - files: ['client/app/**/*.html']<% } %> - }, - karma: 'karma.conf.js', - dist: 'dist' + client: { + scripts: [ + 'client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>', + '!client/bower_components/**/*.js' + ], + styles: ['client/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], + test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], + testRequire: [ + 'client/bower_components/angular/angular.js', + 'client/bower_components/angular-mocks/angular-mocks.js', + 'client/bower_components/angular-resource/angular-resource.js', + 'client/bower_components/angular-cookies/angular-cookies.js', + 'client/bower_components/angular-sanitize/angular-sanitize.js', + 'client/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> + 'client/**/*.spec.coffee'<% } else { %> + 'client/**/*.spec.js'<% } %> + ], + bower: 'client/bower_components/' + }, + server: {<% if(filters.coffee) { %> + scripts: ['server/**/*.coffee'], + test: ['server/**/*.spec.coffee'],<% } else { %> + scripts: ['server/**/*.js'], + test: ['server/**/*.spec.js'],<% } %> + }, + views: {<% if(filters.jade) { %> + main: 'client/index.jade', + files: ['client/app/**/*.jade']<% } else {%> + main: 'client/index.html', + files: ['client/app/**/*.html']<% } %> + }, + karma: 'karma.conf.js', + dist: 'dist' }; ////////////////////// @@ -61,32 +60,34 @@ var paths = { ////////////////////// function onServerLog(log) { - console.log(plugins.util.colors.white('[') + plugins.util.colors.yellow('nodemon') + plugins.util.colors.white('] ') + log.message); + console.log(plugins.util.colors.white('[') + plugins.util.colors.yellow('nodemon') + plugins.util.colors.white('] ') + log.message); } function checkAppReady(cb) { - var options = { - host: 'localhost', - port: config.port, - }; - http.get(options, function() { - cb(true); - }).on('error', function() { - cb(false); - }); + var options = { + host: 'localhost', + port: config.port, + }; + http.get(options, function() { + cb(true); + }).on('error', function() { + cb(false); + }); } // Call page until first success -function whenServerReady (cb) { - var serverReady = false; - var appReadyInterval = setInterval(function () { - checkAppReady(function(ready){ - if (!ready || serverReady) { return; } - clearInterval(appReadyInterval); - serverReady = true; - cb(); - }); - }, 100); +function whenServerReady(cb) { + var serverReady = false; + var appReadyInterval = setInterval(function() { + checkAppReady(function(ready) { + if(!ready || serverReady) { + return; + } + clearInterval(appReadyInterval); + serverReady = true; + cb(); + }); + }, 100); } //////////////////////// @@ -94,114 +95,114 @@ function whenServerReady (cb) { //////////////////////// var lintScripts = lazypipe()<% if(filters.coffee) { %> - .pipe(plugins.coffeelint) - .pipe(plugins.coffeelint.reporter);<% } else { %> - .pipe(plugins.jshint, '.jshintrc') - .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> + .pipe(plugins.coffeelint) + .pipe(plugins.coffeelint.reporter);<% } else { %> + .pipe(plugins.jshint, '.jshintrc') + .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> var styles = lazypipe()<% if(filters.stylus) { %> - .pipe(plugins.stylus, { - use: [nib()], - errors: true - })<% } %><% if(filters.sass) { %> - .pipe(plugins.rubySass, paths.client.styles)<% } %> - .pipe(plugins.autoprefixer, 'last 1 version') - .pipe(gulp.dest, '.tmp/styles'); + .pipe(plugins.stylus, { + use: [nib()], + errors: true + })<% } %><% if(filters.sass) { %> + .pipe(plugins.rubySass, paths.client.styles)<% } %> + .pipe(plugins.autoprefixer, 'last 1 version') + .pipe(gulp.dest, '.tmp/styles'); /////////// // Tasks // /////////// gulp.task('styles', function () { - return styles(); + return styles(); });<% if(filters.coffee) { %> gulp.task('coffee', function() { - return gulp.src(paths.client.scripts) - .pipe(lintScripts()) - .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) - .pipe(gulp.dest('.tmp/scripts')); + return gulp.src(paths.client.scripts) + .pipe(lintScripts()) + .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) + .pipe(gulp.dest('.tmp/scripts')); });<% } %> gulp.task('lint:scripts', function () { - var scripts = paths.client.scripts.concat(paths.server.scripts); - return gulp.src(scripts).pipe(lintScripts()); + var scripts = paths.client.scripts.concat(paths.server.scripts); + return gulp.src(scripts).pipe(lintScripts()); }); gulp.task('clean:tmp', function () { - return gulp.src('.tmp', {read: false}).pipe(plugins.clean()); + return gulp.src('.tmp', {read: false}).pipe(plugins.clean()); }); gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], function (callback) { - whenServerReady(function () { - open('http://localhost:' + config.port); - callback(); - }); + whenServerReady(function () { + open('http://localhost:' + config.port); + callback(); + }); }); gulp.task('start:server', function () { - process.env.NODE_ENV = process.env.NODE_ENV || 'development'; - config = require('./server/config/environment'); - nodemon('-w lib server/app.js') - .on('log', onServerLog); + process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + config = require('./server/config/environment'); + nodemon('-w lib server/app.js') + .on('log', onServerLog); }); gulp.task('watch', function () { - var testFiles = paths.client.test.concat(paths.server.test); + var testFiles = paths.client.test.concat(paths.server.test); - plugins.watch(paths.client.styles) - .pipe(plugins.plumber()) - .pipe(styles()) - .pipe(plugins.livereload()); + plugins.watch(paths.client.styles) + .pipe(plugins.plumber()) + .pipe(styles()) + .pipe(plugins.livereload()); - plugins.watch(paths.views.files) - .pipe(plugins.plumber()) - .pipe(plugins.livereload()); + plugins.watch(paths.views.files) + .pipe(plugins.plumber()) + .pipe(plugins.livereload()); - plugins.watch(paths.client.scripts) - .pipe(plugins.plumber()) - .pipe(lintScripts())<% if(filters.coffee) { %> - .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) - .pipe(gulp.dest('.tmp/scripts'))<% } %> - .pipe(plugins.livereload()); + plugins.watch(paths.client.scripts) + .pipe(plugins.plumber()) + .pipe(lintScripts())<% if(filters.coffee) { %> + .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) + .pipe(gulp.dest('.tmp/scripts'))<% } %> + .pipe(plugins.livereload()); - plugins.watch(paths.server.scripts.concat(testFiles)) - .pipe(plugins.plumber()) - .pipe(lintScripts()); + plugins.watch(paths.server.scripts.concat(testFiles)) + .pipe(plugins.plumber()) + .pipe(lintScripts()); - gulp.watch('bower.json', ['bower']); + gulp.watch('bower.json', ['bower']); }); gulp.task('serve', function (callback) { - runSequence('clean:tmp', - ['lint:scripts'], - 'bower', - ['start:server', 'start:client'], - 'watch', callback); + runSequence('clean:tmp', + ['lint:scripts'], + 'bower', + ['start:server', 'start:client'], + 'watch', callback); }); gulp.task('test:server', function () { - process.env.NODE_ENV = 'test'; - return gulp.src(paths.server.test) - .pipe(plugins.mocha({reporter: 'spec'})); + process.env.NODE_ENV = 'test'; + return gulp.src(paths.server.test) + .pipe(plugins.mocha({reporter: 'spec'})); }); gulp.task('test:client', function () { - var testFiles = paths.client.testRequire.concat(paths.client.test) - gulp.src(testFiles) - .pipe(plugins.karma({ - configFile: paths.karma, - action: 'watch' - })); + var testFiles = paths.client.testRequire.concat(paths.client.test) + gulp.src(testFiles) + .pipe(plugins.karma({ + configFile: paths.karma, + action: 'watch' + })); }); // inject bower components gulp.task('bower', function () { - return gulp.src(paths.views.main) - .pipe(wiredep({ - exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] - })) - .pipe(gulp.dest('client/')); + return gulp.src(paths.views.main) + .pipe(wiredep({ + exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] + })) + .pipe(gulp.dest('client/')); }); /////////// @@ -209,67 +210,67 @@ gulp.task('bower', function () { /////////// gulp.task('build', function (callback) { - runSequence('clean:dist', - ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], - callback); + runSequence('clean:dist', + ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], + callback); }); gulp.task('clean:dist', function () { - return gulp.src('dist', {read: false}).pipe(plugins.clean()); + return gulp.src('dist', {read: false}).pipe(plugins.clean()); }); gulp.task('client:build', ['html'], function () { - var jsFilter = plugins.filter('**/*.js'); - var cssFilter = plugins.filter('**/*.css');<% if(filters.jade) { %> - var assets = plugins.filter('**/*.{js,css}');<% } %> - - return gulp.src(paths.views.main)<% if(filters.jade) { %> - .pipe(plugins.jade({pretty: true}))<% } %> - .pipe(plugins.useref.assets({searchPath: [yeoman.app, '.tmp']})) - .pipe(jsFilter) - .pipe(plugins.ngmin()) - .pipe(plugins.uglify()) - .pipe(jsFilter.restore()) - .pipe(cssFilter) - .pipe(plugins.minifyCss({cache: true})) - .pipe(cssFilter.restore()) - .pipe(plugins.rev()) - .pipe(plugins.useref.restore()) - .pipe(plugins.revReplace()) - .pipe(plugins.useref())<% if(filters.jade) { %> - .pipe(assets)<% } %> - .pipe(gulp.dest(paths.dist + '/public')); + var jsFilter = plugins.filter('**/*.js'); + var cssFilter = plugins.filter('**/*.css');<% if(filters.jade) { %> + var assets = plugins.filter('**/*.{js,css}');<% } %> + + return gulp.src(paths.views.main)<% if(filters.jade) { %> + .pipe(plugins.jade({pretty: true}))<% } %> + .pipe(plugins.useref.assets({searchPath: [yeoman.app, '.tmp']})) + .pipe(jsFilter) + .pipe(plugins.ngmin()) + .pipe(plugins.uglify()) + .pipe(jsFilter.restore()) + .pipe(cssFilter) + .pipe(plugins.minifyCss({cache: true})) + .pipe(cssFilter.restore()) + .pipe(plugins.rev()) + .pipe(plugins.useref.restore()) + .pipe(plugins.revReplace()) + .pipe(plugins.useref())<% if(filters.jade) { %> + .pipe(assets)<% } %> + .pipe(gulp.dest(paths.dist + '/public')); }); gulp.task('html', function () { - return gulp.src(yeoman.app + '/views/**/*') - .pipe(gulp.dest(paths.dist + '/public/views')); + return gulp.src(yeoman.app + '/views/**/*') + .pipe(gulp.dest(paths.dist + '/public/views')); }); gulp.task('images', function () { - return gulp.src(yeoman.app + '/images/**/*') - .pipe(plugins.cache(plugins.imagemin({ - optimizationLevel: 5, - progressive: true, - interlaced: true - }))) - .pipe(gulp.dest(paths.dist + '/public/images')); + return gulp.src(yeoman.app + '/images/**/*') + .pipe(plugins.cache(plugins.imagemin({ + optimizationLevel: 5, + progressive: true, + interlaced: true + }))) + .pipe(gulp.dest(paths.dist + '/public/images')); }); gulp.task('copy:extras', function () { - return gulp.src(yeoman.app + '/*.*', { dot: true }) - .pipe(gulp.dest(paths.dist + '/public')); + return gulp.src(yeoman.app + '/*.*', { dot: true }) + .pipe(gulp.dest(paths.dist + '/public')); }); gulp.task('copy:fonts', function () { - return gulp.src(yeoman.app + '/fonts/**/*') - .pipe(gulp.dest(paths.dist + '/fonts')); + return gulp.src(yeoman.app + '/fonts/**/*') + .pipe(gulp.dest(paths.dist + '/fonts')); }); gulp.task('copy:server', function(){ - return gulp.src([ - 'package.json', - 'server.js', - 'lib/**/*' - ], {cwdbase: true}).pipe(gulp.dest(paths.dist)); + return gulp.src([ + 'package.json', + 'server.js', + 'lib/**/*' + ], {cwdbase: true}).pipe(gulp.dest(paths.dist)); }); From d78e0f64f6f9e500b59430c8d9f8c29b4a7af314 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 20:50:59 -0400 Subject: [PATCH 080/201] refactor(gulp): Use arrow functions in a bunch of places [ci skip] --- app/templates/gulpfile.babel.js | 107 +++++++++++++++----------------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index a8226fa14..e4e2df599 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -68,26 +68,24 @@ function checkAppReady(cb) { host: 'localhost', port: config.port, }; - http.get(options, function() { - cb(true); - }).on('error', function() { - cb(false); - }); + http + .get(options, () => cb(true)) + .on('error', () => cb(false)); } // Call page until first success function whenServerReady(cb) { var serverReady = false; - var appReadyInterval = setInterval(function() { - checkAppReady(function(ready) { + var appReadyInterval = setInterval(() => + checkAppReady((ready) => { if(!ready || serverReady) { return; } clearInterval(appReadyInterval); serverReady = true; cb(); - }); - }, 100); + }), + 100); } //////////////////////// @@ -113,41 +111,34 @@ var styles = lazypipe()<% if(filters.stylus) { %> // Tasks // /////////// -gulp.task('styles', function () { - return styles(); -});<% if(filters.coffee) { %> +gulp.task('styles', () => styles());<% if(filters.coffee) { %> -gulp.task('coffee', function() { - return gulp.src(paths.client.scripts) +gulp.task('coffee', () => + gulp.src(paths.client.scripts) .pipe(lintScripts()) .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts')); -});<% } %> +);<% } %> -gulp.task('lint:scripts', function () { - var scripts = paths.client.scripts.concat(paths.server.scripts); - return gulp.src(scripts).pipe(lintScripts()); -}); +gulp.task('lint:scripts', () => gulp.src(paths.client.scripts.concat(paths.server.scripts)).pipe(lintScripts())); -gulp.task('clean:tmp', function () { - return gulp.src('.tmp', {read: false}).pipe(plugins.clean()); -}); +gulp.task('clean:tmp', () => gulp.src('.tmp', {read: false}).pipe(plugins.clean())); -gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], function (callback) { - whenServerReady(function () { +gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], (callback) => { + whenServerReady(() => { open('http://localhost:' + config.port); callback(); }); }); -gulp.task('start:server', function () { +gulp.task('start:server', () => { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; config = require('./server/config/environment'); nodemon('-w lib server/app.js') .on('log', onServerLog); }); -gulp.task('watch', function () { +gulp.task('watch', () => { var testFiles = paths.client.test.concat(paths.server.test); plugins.watch(paths.client.styles) @@ -173,23 +164,24 @@ gulp.task('watch', function () { gulp.watch('bower.json', ['bower']); }); -gulp.task('serve', function (callback) { +gulp.task('serve', (callback) => runSequence('clean:tmp', ['lint:scripts'], 'bower', ['start:server', 'start:client'], - 'watch', callback); -}); + 'watch', + callback); +); -gulp.task('test:server', function () { +gulp.task('test:server', () => { process.env.NODE_ENV = 'test'; return gulp.src(paths.server.test) .pipe(plugins.mocha({reporter: 'spec'})); }); -gulp.task('test:client', function () { +gulp.task('test:client', () => { var testFiles = paths.client.testRequire.concat(paths.client.test) - gulp.src(testFiles) + return gulp.src(testFiles) .pipe(plugins.karma({ configFile: paths.karma, action: 'watch' @@ -197,29 +189,27 @@ gulp.task('test:client', function () { }); // inject bower components -gulp.task('bower', function () { - return gulp.src(paths.views.main) +gulp.task('bower', () => + gulp.src(paths.views.main) .pipe(wiredep({ exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] })) - .pipe(gulp.dest('client/')); -}); + .pipe(gulp.dest('client/')); +); /////////// // Build // /////////// -gulp.task('build', function (callback) { +gulp.task('build', (callback) => runSequence('clean:dist', ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], callback); -}); +); -gulp.task('clean:dist', function () { - return gulp.src('dist', {read: false}).pipe(plugins.clean()); -}); +gulp.task('clean:dist', () => gulp.src('dist', {read: false}).pipe(plugins.clean())); -gulp.task('client:build', ['html'], function () { +gulp.task('client:build', ['html'], () => { var jsFilter = plugins.filter('**/*.js'); var cssFilter = plugins.filter('**/*.css');<% if(filters.jade) { %> var assets = plugins.filter('**/*.{js,css}');<% } %> @@ -242,35 +232,36 @@ gulp.task('client:build', ['html'], function () { .pipe(gulp.dest(paths.dist + '/public')); }); -gulp.task('html', function () { - return gulp.src(yeoman.app + '/views/**/*') +gulp.task('html', () => + gulp.src(yeoman.app + '/views/**/*') .pipe(gulp.dest(paths.dist + '/public/views')); -}); +); -gulp.task('images', function () { - return gulp.src(yeoman.app + '/images/**/*') +gulp.task('images', () => + gulp.src(yeoman.app + '/images/**/*') .pipe(plugins.cache(plugins.imagemin({ optimizationLevel: 5, progressive: true, interlaced: true }))) .pipe(gulp.dest(paths.dist + '/public/images')); -}); +); -gulp.task('copy:extras', function () { - return gulp.src(yeoman.app + '/*.*', { dot: true }) +gulp.task('copy:extras', () => + gulp.src(yeoman.app + '/*.*', { dot: true }) .pipe(gulp.dest(paths.dist + '/public')); -}); +); -gulp.task('copy:fonts', function () { - return gulp.src(yeoman.app + '/fonts/**/*') +gulp.task('copy:fonts', () => + gulp.src(yeoman.app + '/fonts/**/*') .pipe(gulp.dest(paths.dist + '/fonts')); -}); +); -gulp.task('copy:server', function(){ - return gulp.src([ +gulp.task('copy:server', () => + gulp.src([ 'package.json', 'server.js', 'lib/**/*' - ], {cwdbase: true}).pipe(gulp.dest(paths.dist)); -}); + ], {cwdbase: true}) + .pipe(gulp.dest(paths.dist)); +); From 69c88fafac2199c582b765b1459ff604c037434b Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 20:52:43 -0400 Subject: [PATCH 081/201] feat(gulp): Include lodash and use it to replace array.concat(array) with _.union(array, array) --- app/templates/gulpfile.babel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index e4e2df599..f242728ac 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -1,6 +1,7 @@ // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 'use strict'; +import _ from '_'; import gulp from 'gulp'; import path from 'path'; import gulpLoadPlugins from 'gulp-load-plugins'; @@ -120,7 +121,7 @@ gulp.task('coffee', () => .pipe(gulp.dest('.tmp/scripts')); );<% } %> -gulp.task('lint:scripts', () => gulp.src(paths.client.scripts.concat(paths.server.scripts)).pipe(lintScripts())); +gulp.task('lint:scripts', () => gulp.src(_.union(paths.client.scripts, paths.server.scripts)).pipe(lintScripts())); gulp.task('clean:tmp', () => gulp.src('.tmp', {read: false}).pipe(plugins.clean())); From 7362262863ba60a8c1b49c1e3afbdd2426b61d52 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 21:13:01 -0400 Subject: [PATCH 082/201] fix(gulp): Fix lodash import and missing braces --- app/templates/gulpfile.babel.js | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index f242728ac..fdad78cb6 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -1,7 +1,7 @@ // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 'use strict'; -import _ from '_'; +import _ from 'lodash'; import gulp from 'gulp'; import path from 'path'; import gulpLoadPlugins from 'gulp-load-plugins'; @@ -140,7 +140,7 @@ gulp.task('start:server', () => { }); gulp.task('watch', () => { - var testFiles = paths.client.test.concat(paths.server.test); + var testFiles = _.union(paths.client.test, paths.server.test); plugins.watch(paths.client.styles) .pipe(plugins.plumber()) @@ -158,21 +158,21 @@ gulp.task('watch', () => { .pipe(gulp.dest('.tmp/scripts'))<% } %> .pipe(plugins.livereload()); - plugins.watch(paths.server.scripts.concat(testFiles)) + plugins.watch(_.union(paths.server.scripts, testFiles)) .pipe(plugins.plumber()) .pipe(lintScripts()); gulp.watch('bower.json', ['bower']); }); -gulp.task('serve', (callback) => +gulp.task('serve', (callback) => { runSequence('clean:tmp', ['lint:scripts'], 'bower', ['start:server', 'start:client'], 'watch', callback); -); +}); gulp.task('test:server', () => { process.env.NODE_ENV = 'test'; @@ -181,7 +181,7 @@ gulp.task('test:server', () => { }); gulp.task('test:client', () => { - var testFiles = paths.client.testRequire.concat(paths.client.test) + var testFiles = _.union(paths.client.testRequire, paths.client.test) return gulp.src(testFiles) .pipe(plugins.karma({ configFile: paths.karma, @@ -190,23 +190,23 @@ gulp.task('test:client', () => { }); // inject bower components -gulp.task('bower', () => +gulp.task('bower', () => { gulp.src(paths.views.main) .pipe(wiredep({ exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] })) .pipe(gulp.dest('client/')); -); +}); /////////// // Build // /////////// -gulp.task('build', (callback) => +gulp.task('build', (callback) => { runSequence('clean:dist', ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], callback); -); +}); gulp.task('clean:dist', () => gulp.src('dist', {read: false}).pipe(plugins.clean())); @@ -233,12 +233,12 @@ gulp.task('client:build', ['html'], () => { .pipe(gulp.dest(paths.dist + '/public')); }); -gulp.task('html', () => +gulp.task('html', () => { gulp.src(yeoman.app + '/views/**/*') .pipe(gulp.dest(paths.dist + '/public/views')); -); +}); -gulp.task('images', () => +gulp.task('images', () => { gulp.src(yeoman.app + '/images/**/*') .pipe(plugins.cache(plugins.imagemin({ optimizationLevel: 5, @@ -246,23 +246,23 @@ gulp.task('images', () => interlaced: true }))) .pipe(gulp.dest(paths.dist + '/public/images')); -); +}); -gulp.task('copy:extras', () => +gulp.task('copy:extras', () => { gulp.src(yeoman.app + '/*.*', { dot: true }) .pipe(gulp.dest(paths.dist + '/public')); -); +}); -gulp.task('copy:fonts', () => +gulp.task('copy:fonts', () => { gulp.src(yeoman.app + '/fonts/**/*') .pipe(gulp.dest(paths.dist + '/fonts')); -); +}); -gulp.task('copy:server', () => +gulp.task('copy:server', () => { gulp.src([ 'package.json', 'server.js', 'lib/**/*' ], {cwdbase: true}) .pipe(gulp.dest(paths.dist)); -); +}); From 3d8ce97be6152f8a9a7024750b0f16b1e98f18fd Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sun, 21 Jun 2015 23:47:56 -0400 Subject: [PATCH 083/201] chore(npm): Update lodash from ~2.4.1 to ~3.9.3, and bump lazypipe --- app/templates/_package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index ad713fdc4..4b906315b 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -12,7 +12,7 @@ "express-session": "~1.0.2", "errorhandler": "~1.0.0", "compression": "~1.0.1", - "lodash": "~2.4.1",<% if(filters.jade) { %> + "lodash": "~3.9.3",<% if(filters.jade) { %> "jade": "~1.2.0",<% } %><% if(filters.html) { %> "ejs": "~0.8.4",<% } %><% if(filters.mongoose) { %> "mongoose": "~3.8.8",<% } %><% if(filters.auth) { %> @@ -53,7 +53,7 @@ "utile": "~0.3.0", "nodemon": "^1.3.7", "run-sequence": "^1.1.0", - "lazypipe": "^0.2.3", + "lazypipe": "^0.2.4", "wiredep": "^2.2.2",<% if(filters.jade) { %> "gulp-jade": "^1.0.1",<% } %><% if(filters.stylus) { %> "gulp-stylus": "^2.0.4", From 538f803d05d31e50d4200f52de83510a39951e0c Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 00:40:45 -0400 Subject: [PATCH 084/201] feat(npm): Add gulp-babel [ci skip] --- app/templates/_package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 4b906315b..67c548019 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -31,7 +31,8 @@ }, "devDependencies": {<% if(filters.gulp) { %> "gulp": "^3.9.0", - "gulp-autoprefixer": "2.3.1", + "gulp-autoprefixer": "2.3.1",<% if(filters.babel) { %> + "gulp-babel": "^5.1.0",<% } %> "gulp-cache": "^0.2.10", "gulp-clean": "^0.3.1", "gulp-filter": "^2.0.2", From eb1672558f5613a906111a532783a6b95255cf48 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 01:01:56 -0400 Subject: [PATCH 085/201] fix(app): Add relative path for bower sass assets --- app/templates/client/app/app(sass).scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/templates/client/app/app(sass).scss b/app/templates/client/app/app(sass).scss index 4b8ae7a04..3ef474843 100644 --- a/app/templates/client/app/app(sass).scss +++ b/app/templates/client/app/app(sass).scss @@ -1,8 +1,8 @@ <% if(filters.bootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> $fa-font-path: "/bower_components/font-awesome/fonts"; <% if(filters.bootstrap) { %> -@import 'bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> -@import 'font-awesome/scss/font-awesome'; +@import '../bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> +@import '../bower_components/font-awesome/scss/font-awesome'; /** * App-wide Styles @@ -27,4 +27,4 @@ $fa-font-path: "/bower_components/font-awesome/fonts"; @import 'account/login/login.scss'; @import 'admin/admin.scss'; @import 'main/main.scss'; -// endinjector \ No newline at end of file +// endinjector From 996919f0bc183b3a9c2708c1716fa98d6bc6a87d Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 01:02:39 -0400 Subject: [PATCH 086/201] feat(gulp): Rework to get styles working again --- app/templates/_package.json | 3 ++- app/templates/gulpfile.babel.js | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 67c548019..83bf1868d 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -46,6 +46,7 @@ "gulp-plumber": "^1.0.1", "gulp-rev": "^5.0.0", "gulp-rev-replace": "^0.4.2", + "gulp-sourcemaps": "^1.5.2", "gulp-svgmin": "^1.1.2", "gulp-uglify": "^1.2.0", "gulp-useref": "^0.4.2", @@ -59,7 +60,7 @@ "gulp-jade": "^1.0.1",<% } %><% if(filters.stylus) { %> "gulp-stylus": "^2.0.4", "nib": "^1.1.0",<% } %><% if(filters.sass) { %> - "gulp-ruby-sass": "^1.0.5",<% } %><% if(filters.coffee) { %> + "gulp-sass": "^2.0.1",<% } %><% if(filters.coffee) { %> "gulp-coffeelint": "^0.5.0", "gulp-coffee": "^2.3.1",<% } %><% } else { %> "grunt": "~0.4.4", diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index fdad78cb6..abdaeb1c6 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -26,7 +26,7 @@ var paths = { 'client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>', '!client/bower_components/**/*.js' ], - styles: ['client/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], + styles: ['client/{app, components}/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], testRequire: [ 'client/bower_components/angular/angular.js', @@ -99,20 +99,23 @@ var lintScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.jshint, '.jshintrc') .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> -var styles = lazypipe()<% if(filters.stylus) { %> +let styles = lazypipe() + .pipe(gulp.src, paths.client.styles) + .pipe(plugins.sourcemaps.init)<% if(filters.stylus) { %> .pipe(plugins.stylus, { use: [nib()], errors: true - })<% } %><% if(filters.sass) { %> - .pipe(plugins.rubySass, paths.client.styles)<% } %> - .pipe(plugins.autoprefixer, 'last 1 version') - .pipe(gulp.dest, '.tmp/styles'); + })<% } if(filters.sass) { %> + .pipe(plugins.sass)<% } %> + .pipe(plugins.sourcemaps.write, '.') + // .pipe(plugins.autoprefixer, {browsers: ['last 1 version']}) //seems to break this + .pipe(gulp.dest, '.tmp'); /////////// // Tasks // /////////// -gulp.task('styles', () => styles());<% if(filters.coffee) { %> +gulp.task('styles', styles);<% if(filters.coffee) { %> gulp.task('coffee', () => gulp.src(paths.client.scripts) From 9fd160d9d601ca49281c75533c567e834f5b86f9 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 01:59:57 -0400 Subject: [PATCH 087/201] feat(gulp): Add inject tasks for css and js into index.html, add them to serve task Tested to work with plain js, sass, other defaults... gulp serve works :] --- app/templates/_package.json | 1 + app/templates/gulpfile.babel.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/templates/_package.json b/app/templates/_package.json index 83bf1868d..a59e56538 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -37,6 +37,7 @@ "gulp-clean": "^0.3.1", "gulp-filter": "^2.0.2", "gulp-imagemin": "^2.2.1", + "gulp-inject": "^1.3.1", "gulp-jshint": "^1.11.0", "gulp-karma": "0.0.4", "gulp-livereload": "^3.8.0", diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index abdaeb1c6..8633e22f9 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -115,6 +115,32 @@ let styles = lazypipe() // Tasks // /////////// +gulp.task('inject', cb => { + runSequence(['inject:js', 'inject:css'], cb); +}); + +gulp.task('inject:js', () => { + return gulp.src(paths.views.main) + .pipe(plugins.inject(gulp.src(_.union( + paths.client.scripts + ), {read: false}), { + starttag: '', + endtag: '', + transform: (filepath) => '' + })) + .pipe(gulp.dest('client')); +}); + +gulp.task('inject:css', () => { + return gulp.src(paths.views.main) + .pipe(plugins.inject(gulp.src('/client/**/*.css', {read: false}), { + starttag: '', + endtag: '', + transform: (filepath) => '' + })) + .pipe(gulp.dest('client')); +}); + gulp.task('styles', styles);<% if(filters.coffee) { %> gulp.task('coffee', () => @@ -171,6 +197,8 @@ gulp.task('watch', () => { gulp.task('serve', (callback) => { runSequence('clean:tmp', ['lint:scripts'], + 'inject:js', + 'inject:css', 'bower', ['start:server', 'start:client'], 'watch', From df481888dd9300762c7a817ec29d47f24b924cdd Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 20 Jun 2015 01:53:27 -0400 Subject: [PATCH 088/201] test(model): refactor tests to expose model update bugs Both mongoose and sequelize user model implementations have undesired effects when performing an update. --- .../user.model.spec(mongooseModels).js | 60 +++++++++++++------ .../user.model.spec(sequelizeModels).js | 56 +++++++++++------ 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js b/app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js index 16de6e2de..1aad3b25e 100644 --- a/app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js +++ b/app/templates/server/api/user(auth)/user.model.spec(mongooseModels).js @@ -2,22 +2,29 @@ var app = require('../../app'); var User = require('./user.model'); - -var user = new User({ - provider: 'local', - name: 'Fake User', - email: 'test@test.com', - password: 'password' -}); +var user; +var genUser = function() { + user = new User({ + provider: 'local', + name: 'Fake User', + email: 'test@test.com', + password: 'password' + }); + return user; +}; describe('User Model', function() { before(function() { // Clear users before testing - return User.remove().exec(); + return User.removeAsync(); + }); + + beforeEach(function() { + genUser(); }); afterEach(function() { - return User.remove().exec(); + return User.removeAsync(); }); it('should begin with no users', function() { @@ -28,21 +35,38 @@ describe('User Model', function() { it('should fail when saving a duplicate user', function() { return user.saveAsync() .then(function() { - var userDup = new User(user); + var userDup = genUser(); return userDup.saveAsync(); }).should.be.rejected; }); - it('should fail when saving without an email', function() { - user.email = ''; - return user.saveAsync().should.be.rejected; + describe('#email', function() { + it('should fail when saving without an email', function() { + user.email = ''; + return user.saveAsync().should.be.rejected; + }); }); - it('should authenticate user if password is valid', function() { - user.authenticate('password').should.be.true; - }); + describe('#password', function() { + beforeEach(function() { + return user.saveAsync(); + }); + + it('should authenticate user if valid', function() { + user.authenticate('password').should.be.true; + }); - it('should not authenticate user if password is invalid', function() { - user.authenticate('blah').should.not.be.true; + it('should not authenticate user if invalid', function() { + user.authenticate('blah').should.not.be.true; + }); + + it('should remain the same hash unless the password is updated', function() { + user.name = 'Test User'; + return user.saveAsync() + .spread(function(u) { + return u.authenticate('password'); + }).should.eventually.be.true; + }); }); + }); diff --git a/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js index f499667cd..a7af1bd38 100644 --- a/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js +++ b/app/templates/server/api/user(auth)/user.model.spec(sequelizeModels).js @@ -2,16 +2,17 @@ var app = require('../../app'); var User = require('../../sqldb').User; - -var userTemplate = { - provider: 'local', - name: 'Fake User', - email: 'test@test.com', - password: 'password' +var user; +var genUser = function() { + user = User.build({ + provider: 'local', + name: 'Fake User', + email: 'test@test.com', + password: 'password' + }); + return user; }; -var user = User.build(userTemplate); - describe('User Model', function() { before(function() { // Sync and clear users before testing @@ -20,6 +21,10 @@ describe('User Model', function() { }); }); + beforeEach(function() { + genUser(); + }); + afterEach(function() { return User.destroy({ where: {} }); }); @@ -32,21 +37,38 @@ describe('User Model', function() { it('should fail when saving a duplicate user', function() { return user.save() .then(function() { - var userDup = User.build(userTemplate); + var userDup = genUser(); return userDup.save(); }).should.be.rejected; }); - it('should fail when saving without an email', function() { - user.email = ''; - return user.save().should.be.rejected; + describe('#email', function() { + it('should fail when saving without an email', function() { + user.email = ''; + return user.save().should.be.rejected; + }); }); - it('should authenticate user if password is valid', function() { - user.authenticate('password').should.be.true; - }); + describe('#password', function() { + beforeEach(function() { + return user.save(); + }); + + it('should authenticate user if valid', function() { + user.authenticate('password').should.be.true; + }); - it('should not authenticate user if password is invalid', function() { - user.authenticate('blah').should.not.be.true; + it('should not authenticate user if invalid', function() { + user.authenticate('blah').should.not.be.true; + }); + + it('should remain the same hash unless the password is updated', function() { + user.name = 'Test User'; + return user.save() + .then(function(u) { + return u.authenticate('password'); + }).should.eventually.be.true; + }); }); + }); From 1805975d3a7bdd1b9a409813d3fc0d2777f492bf Mon Sep 17 00:00:00 2001 From: kingcody Date: Mon, 22 Jun 2015 02:04:38 -0400 Subject: [PATCH 089/201] fix(model): fix update bugs with mongoose and sequelize --- .../server/api/user(auth)/user.model(mongooseModels).js | 2 +- .../server/api/user(auth)/user.model(sequelizeModels).js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/templates/server/api/user(auth)/user.model(mongooseModels).js b/app/templates/server/api/user(auth)/user.model(mongooseModels).js index 201afb4bc..008412eaf 100644 --- a/app/templates/server/api/user(auth)/user.model(mongooseModels).js +++ b/app/templates/server/api/user(auth)/user.model(mongooseModels).js @@ -102,7 +102,7 @@ var validatePresenceOf = function(value) { UserSchema .pre('save', function(next) { // Handle new/update passwords - if (this.password) { + if (this.isModified('password')) { if (!validatePresenceOf(this.password)<% if (filters.oauth) { %> && authTypes.indexOf(this.provider) === -1<% } %>) { next(new Error('Invalid password')); } diff --git a/app/templates/server/api/user(auth)/user.model(sequelizeModels).js b/app/templates/server/api/user(auth)/user.model(sequelizeModels).js index af593157a..776eafc3e 100644 --- a/app/templates/server/api/user(auth)/user.model(sequelizeModels).js +++ b/app/templates/server/api/user(auth)/user.model(sequelizeModels).js @@ -89,8 +89,9 @@ module.exports = function(sequelize, DataTypes) { }, beforeUpdate: function(user, fields, fn) { if (user.changed('password')) { - user.updatePassword(fn); + return user.updatePassword(fn); } + fn(); } }, From 349b6d3e5ca01e2d44342f0d952953f30dd322e9 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 13:43:15 -0400 Subject: [PATCH 090/201] fix(npm): Remove git diff comment Crap.... --- app/templates/_package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 870408f92..346ec2078 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -45,7 +45,6 @@ "grunt-contrib-imagemin": "~0.7.1", "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-uglify": "~0.4.0", -<<<<<<< HEAD "grunt-contrib-watch": "~0.6.1",<% if (filters.coffee) { %> "grunt-contrib-coffee": "^0.10.1",<% } %><% if (filters.jade) { %> "grunt-contrib-jade": "^0.11.0",<% } %><% if (filters.less) { %> From 1bcffd674c776453732a242e8106f51090a9447c Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Mon, 22 Jun 2015 14:14:40 -0400 Subject: [PATCH 091/201] fix(gen:endpoint): Fix JSCS stuff and use Express 4 syntax --- endpoint/templates/name.controller.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 6a63a7ba8..4b5d985e4 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -11,7 +11,7 @@ function responseWithResult(res, statusCode) { statusCode = statusCode || 200; return function(entity) { if (entity) { - return res.json(statusCode, entity); + return res.status(statusCode).json(entity); } }; } @@ -41,7 +41,7 @@ function removeEntity(res) { if (entity) { return entity.removeAsync() .then(function() { - return res.send(204); + return res.status(204); }); } }; @@ -50,8 +50,8 @@ function removeEntity(res) { // Get list of <%= name %>s exports.index = function(req, res) {<% if (!filters.mongoose) { %> res.json([]);<% } %><% if (filters.mongoose) { %> - <%= classedName %>.find(function (err, <%= name %>s) { - if(err) { return handleError(res, err); } + <%= classedName %>.find(function(err, <%= name %>s) { + if (err) { return handleError(res, err); } return res.status(200).json(<%= name %>s); });<% } %> };<% if (filters.mongoose) { %> From 0af7c3ebb95edb41b1b82014d5e1501d8f4164ce Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 23 Jun 2015 06:40:39 -0400 Subject: [PATCH 092/201] fix(endpoint): refactor handleError for promise use --- endpoint/templates/name.controller.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 4b5d985e4..7d03a42ee 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -3,8 +3,11 @@ var _ = require('lodash'); var <%= classedName %> = require('./<%= name %>.model'); -function handleError(res, err) { - return res.status(500).send(err); +function handleError(res, statusCode) { + statusCode = statusCode || 500; + return function(err) { + res.status(statusCode).send(err); + }; } function responseWithResult(res, statusCode) { @@ -19,7 +22,7 @@ function responseWithResult(res, statusCode) { function handleEntityNotFound(res) { return function(entity) { if (!entity) { - res.send(404); + res.status(404).end(); return null; } return entity; @@ -41,7 +44,7 @@ function removeEntity(res) { if (entity) { return entity.removeAsync() .then(function() { - return res.status(204); + res.status(204).end(); }); } }; @@ -50,10 +53,9 @@ function removeEntity(res) { // Get list of <%= name %>s exports.index = function(req, res) {<% if (!filters.mongoose) { %> res.json([]);<% } %><% if (filters.mongoose) { %> - <%= classedName %>.find(function(err, <%= name %>s) { - if (err) { return handleError(res, err); } - return res.status(200).json(<%= name %>s); - });<% } %> + <%= classedName %>.findAsync() + .then(responseWithResult(res)) + .catch(handleError(res));<% } %> };<% if (filters.mongoose) { %> // Gets a single <%= name %> from the DB. From 0ec2e1808ec15755786b7144b99fcdc5704738a6 Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 23 Jun 2015 06:47:24 -0400 Subject: [PATCH 093/201] fix(test): remove package.json and bower.json --- test/fixtures/bower.json | 24 --------- test/fixtures/package.json | 102 ------------------------------------- 2 files changed, 126 deletions(-) delete mode 100644 test/fixtures/bower.json delete mode 100644 test/fixtures/package.json diff --git a/test/fixtures/bower.json b/test/fixtures/bower.json deleted file mode 100644 index 10dff6513..000000000 --- a/test/fixtures/bower.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "tempApp", - "version": "0.0.0", - "dependencies": { - "angular": ">=1.2.*", - "json3": "~3.3.1", - "es5-shim": "~3.0.1", - "bootstrap-sass-official": "~3.1.1", - "bootstrap": "~3.1.1", - "angular-resource": ">=1.2.*", - "angular-cookies": ">=1.2.*", - "angular-sanitize": ">=1.2.*", - "angular-route": ">=1.2.*", - "angular-bootstrap": "~0.11.0", - "font-awesome": ">=4.1.0", - "lodash": "~2.4.1", - "angular-socket-io": "~0.6.0", - "angular-ui-router": "~0.2.10" - }, - "devDependencies": { - "angular-mocks": ">=1.2.*", - "angular-scenario": ">=1.2.*" - } -} diff --git a/test/fixtures/package.json b/test/fixtures/package.json deleted file mode 100644 index c110f7838..000000000 --- a/test/fixtures/package.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "tempApp", - "version": "0.0.0", - "main": "server/app.js", - "dependencies": { - "express": "~4.9.0", - "morgan": "~1.0.0", - "body-parser": "~1.5.0", - "method-override": "~1.0.0", - "serve-favicon": "~2.0.1", - "cookie-parser": "~1.0.1", - "express-session": "~1.0.2", - "errorhandler": "~1.0.0", - "compression": "~1.0.1", - "lodash": "~2.4.1", - "jade": "~1.2.0", - "ejs": "~0.8.4", - "mongoose": "~3.8.8", - "jsonwebtoken": "^0.3.0", - "express-jwt": "^0.1.3", - "passport": "~0.2.0", - "passport-local": "~0.1.6", - "passport-facebook": "latest", - "passport-twitter": "latest", - "passport-google-oauth": "latest", - "composable-middleware": "^0.3.0", - "connect-mongo": "^0.4.1", - "socket.io": "^1.0.6", - "socket.io-client": "^1.0.6", - "socketio-jwt": "^2.0.2" - }, - "devDependencies": { - "grunt": "~0.4.4", - "grunt-autoprefixer": "~0.7.2", - "grunt-wiredep": "~1.8.0", - "grunt-concurrent": "~0.5.0", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-concat": "~0.4.0", - "grunt-contrib-copy": "~0.5.0", - "grunt-contrib-cssmin": "~0.9.0", - "grunt-contrib-htmlmin": "~0.2.0", - "grunt-contrib-imagemin": "~0.7.1", - "grunt-contrib-jshint": "~0.10.0", - "grunt-contrib-uglify": "~0.4.0", - "grunt-contrib-watch": "~0.6.1", - "grunt-contrib-coffee": "^0.10.1", - "grunt-contrib-jade": "^0.11.0", - "grunt-contrib-less": "^0.11.0", - "karma-babel-preprocessor": "^5.2.1", - "grunt-babel": "~5.0.0", - "grunt-google-cdn": "~0.4.0", - "grunt-newer": "~0.7.0", - "grunt-ng-annotate": "^0.2.3", - "grunt-rev": "~0.1.0", - "grunt-svgmin": "~0.4.0", - "grunt-usemin": "~2.1.1", - "grunt-env": "~0.4.1", - "grunt-node-inspector": "~0.1.5", - "grunt-nodemon": "~0.2.0", - "grunt-angular-templates": "^0.5.4", - "grunt-dom-munger": "^3.4.0", - "grunt-protractor-runner": "^1.1.0", - "grunt-injector": "~0.5.4", - "grunt-karma": "~0.8.2", - "grunt-build-control": "DaftMonk/grunt-build-control", - "grunt-mocha-test": "~0.10.2", - "grunt-contrib-sass": "^0.7.3", - "grunt-contrib-stylus": "latest", - "jit-grunt": "^0.5.0", - "time-grunt": "~0.3.1", - "grunt-express-server": "~0.4.17", - "grunt-open": "~0.2.3", - "open": "~0.0.4", - "jshint-stylish": "~0.1.5", - "connect-livereload": "~0.4.0", - "karma-ng-scenario": "~0.1.0", - "karma-firefox-launcher": "~0.1.3", - "karma-script-launcher": "~0.1.0", - "karma-html2js-preprocessor": "~0.1.0", - "karma-ng-jade2js-preprocessor": "^0.1.2", - "karma-jasmine": "~0.1.5", - "karma-chrome-launcher": "~0.1.3", - "requirejs": "~2.1.11", - "karma-requirejs": "~0.2.1", - "karma-coffee-preprocessor": "~0.2.1", - "karma-jade-preprocessor": "0.0.11", - "karma-phantomjs-launcher": "~0.1.4", - "karma": "~0.12.9", - "karma-ng-html2js-preprocessor": "~0.1.0", - "supertest": "~0.11.0", - "should": "~3.3.1" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "start": "node server/app.js", - "test": "grunt test", - "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update" - }, - "private": true -} From 342606c4a3447e4c12561c4b2752a89d47c99527 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 23 Jun 2015 12:15:25 -0400 Subject: [PATCH 094/201] fix(gen): Check that answers.odms exists --- app/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/index.js b/app/index.js index 29289881e..15f8f3b95 100644 --- a/app/index.js +++ b/app/index.js @@ -224,7 +224,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }], function (answers) { if(answers.socketio) this.filters.socketio = true; if(answers.auth) this.filters.auth = true; - if(answers.odms.length > 0) { + if(answers.odms && answers.odms.length > 0) { var models; if(!answers.models) { models = answers.odms[0]; From dae69cff73b615b92839cc2c7014f1a96d334544 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 24 Jun 2015 06:58:52 -0400 Subject: [PATCH 095/201] fix(travis): remove node v0.11 from testing --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 36b85dcc5..cdaee3885 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - '0.10' - - '0.11' - '0.12' env: global: From c98cb5d3606ddd47d44cb8a5b366124bde04328c Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 27 Jun 2015 02:13:17 -0400 Subject: [PATCH 096/201] fix(endpoint:user): refactor validationError for promise use --- .../server/api/user(auth)/user.controller.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index 0286b5415..d074c666b 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -8,21 +8,24 @@ var passport = require('passport'); var config = require('../../config/environment'); var jwt = require('jsonwebtoken'); -var validationError = function(res, err) { - return res.status(422).json(err); -}; +function validationError(res, statusCode) { + statusCode = statusCode || 422; + return function(err) { + res.status(statusCode).json(err); + } +} function handleError(res, statusCode) { statusCode = statusCode || 500; return function(err) { - res.send(statusCode, err); + res.status(statusCode).send(err); }; } function respondWith(res, statusCode) { statusCode = statusCode || 200; return function() { - res.send(statusCode); + res.status(statusCode).end(); }; } From c7b48a5b6bb54968ed690d600f496ef032ee7869 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sat, 27 Jun 2015 02:25:22 -0400 Subject: [PATCH 097/201] fix(endpoint:thing): use Express 4 syntax --- .../server/api/thing/thing.controller(models).js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/templates/server/api/thing/thing.controller(models).js b/app/templates/server/api/thing/thing.controller(models).js index a14fbd4b3..c7874b515 100644 --- a/app/templates/server/api/thing/thing.controller(models).js +++ b/app/templates/server/api/thing/thing.controller(models).js @@ -17,7 +17,7 @@ var Thing = sqldb.Thing;<% } %> function handleError(res, statusCode) { statusCode = statusCode || 500; return function(err) { - res.send(statusCode, err); + res.status(statusCode).send(err); }; } @@ -25,7 +25,7 @@ function responseWithResult(res, statusCode) { statusCode = statusCode || 200; return function(entity) { if (entity) { - return res.json(statusCode, entity); + return res.status(statusCode).json(entity); } }; } @@ -33,7 +33,7 @@ function responseWithResult(res, statusCode) { function handleEntityNotFound(res) { return function(entity) { if (!entity) { - res.send(404); + res.status(404).end(); return null; } return entity; @@ -58,7 +58,7 @@ function removeEntity(res) { <% if (filters.mongooseModels) { %>return entity.removeAsync()<% } if (filters.sequelizeModels) { %>return entity.destroy()<% } %> .then(function() { - return res.send(204); + return res.status(204).end(); }); } }; From 60334a8d43c2d53a4e994dad5ba201590982ae91 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 24 Jun 2015 05:41:37 -0400 Subject: [PATCH 098/201] feat(server): implement server-side ES6 via babel --- app/templates/Gruntfile.js | 29 +++++++--------------- app/templates/_package.json | 5 ++-- app/templates/mocha.conf.js | 5 +++- app/templates/server/index.js | 7 ++++++ test/test-file-creation.js | 45 ++--------------------------------- 5 files changed, 25 insertions(+), 66 deletions(-) create mode 100644 app/templates/server/index.js diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 028300e68..8d2ef6c96 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -39,13 +39,13 @@ module.exports = function (grunt) { }, dev: { options: { - script: 'server/app.js', + script: 'server', debug: true } }, prod: { options: { - script: 'dist/server/app.js' + script: 'dist/server' } } }, @@ -61,7 +61,7 @@ module.exports = function (grunt) { '!<%%= yeoman.client %>/{app,components}/**/*.spec.js', '!<%%= yeoman.client %>/{app,components}/**/*.mock.js', '!<%%= yeoman.client %>/app/app.js'], - tasks: ['injector:scripts'] + tasks: [<% if(filters.babel) { %>'newer:babel:client', <% } %>'injector:scripts'] }, injectCss: { files: [ @@ -128,13 +128,6 @@ module.exports = function (grunt) { '<%%= yeoman.client %>/{app,components}/**/*.spec.{coffee,litcoffee,coffee.md}' ], tasks: ['karma'] - },<% } %><% if(filters.babel) { %> - babel: { - files: [ - '<%%= yeoman.client %>/{app,components}/**/*.js', - '!<%%= yeoman.client %>/{app,components}/**/*.spec.js' - ], - tasks: ['babel'] },<% } %> gruntfile: { files: ['Gruntfile.js'] @@ -143,11 +136,7 @@ module.exports = function (grunt) { files: [ '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.css', '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.html', - <% if(filters.babel) { %> - '.tmp/{app,components}/**/*.js', - <% } else { %> '{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.js', - <% } %> '!{.tmp,<%%= yeoman.client %>}{app,components}/**/*.spec.js', '!{.tmp,<%%= yeoman.client %>}/{app,components}/**/*.mock.js', '<%%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}' @@ -261,7 +250,7 @@ module.exports = function (grunt) { // Use nodemon to run server in debug mode with an initial breakpoint nodemon: { debug: { - script: 'server/app.js', + script: 'server', options: { nodeArgs: ['--debug-brk'], env: { @@ -470,7 +459,7 @@ module.exports = function (grunt) { concurrent: { server: [<% if(filters.coffee) { %> 'coffee',<% } %><% if(filters.babel) { %> - 'babel',<% } %><% if(filters.jade) { %> + 'newer:babel:client',<% } %><% if(filters.jade) { %> 'jade',<% } %><% if(filters.stylus) { %> 'stylus',<% } %><% if(filters.sass) { %> 'sass',<% } %><% if(filters.less) { %> @@ -478,7 +467,7 @@ module.exports = function (grunt) { ], test: [<% if(filters.coffee) { %> 'coffee',<% } %><% if(filters.babel) { %> - 'babel',<% } %><% if(filters.jade) { %> + 'newer:babel:client',<% } %><% if(filters.jade) { %> 'jade',<% } %><% if(filters.stylus) { %> 'stylus',<% } %><% if(filters.sass) { %> 'sass',<% } %><% if(filters.less) { %> @@ -495,7 +484,7 @@ module.exports = function (grunt) { }, dist: [<% if(filters.coffee) { %> 'coffee',<% } %><% if(filters.babel) { %> - 'babel',<% } %><% if(filters.jade) { %> + 'newer:babel:client',<% } %><% if(filters.jade) { %> 'jade',<% } %><% if(filters.stylus) { %> 'stylus',<% } %><% if(filters.sass) { %> 'sass',<% } %><% if(filters.less) { %> @@ -639,10 +628,10 @@ module.exports = function (grunt) { options: { sourceMap: true }, - server: { + client: { files: [{ expand: true, - cwd: 'client', + cwd: '<%%= yeoman.client %>', src: [ '{app,components}/**/*.js', '!{app,components}/**/*.spec.js' diff --git a/app/templates/_package.json b/app/templates/_package.json index 346ec2078..1356bab64 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -12,7 +12,8 @@ "express-session": "~1.0.2", "errorhandler": "~1.0.0", "compression": "~1.0.1", - "lodash": "~2.4.1",<% if (filters.jade) { %> + "lodash": "~2.4.1",<% if(filters.babel) { %> + "babel-core": "^5.6.4",<% } %><% if (filters.jade) { %> "jade": "~1.2.0",<% } %><% if (filters.html) { %> "ejs": "~0.8.4",<% } %><% if (filters.mongoose) { %> "mongoose": "~3.8.8", @@ -106,7 +107,7 @@ "node": ">=0.10.0" }, "scripts": { - "start": "node server/app.js", + "start": "node server", "test": "grunt test", "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update" }, diff --git a/app/templates/mocha.conf.js b/app/templates/mocha.conf.js index 54e33bb6f..6b1504e9c 100644 --- a/app/templates/mocha.conf.js +++ b/app/templates/mocha.conf.js @@ -1,4 +1,7 @@ -'use strict'; +'use strict';<% if(filters.babel) { %> + +// Register the Babel require hook +require('babel-core/register');<% } %> var chai = require('chai'); diff --git a/app/templates/server/index.js b/app/templates/server/index.js new file mode 100644 index 000000000..7722a0e6c --- /dev/null +++ b/app/templates/server/index.js @@ -0,0 +1,7 @@ +'use strict';<% if (filters.babel) { %> + +// Register the Babel require hook +require('babel-core/register');<% } %> + +// Export the application +exports = module.exports = require('./app'); diff --git a/test/test-file-creation.js b/test/test-file-creation.js index a863700be..ec794c7ab 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -11,6 +11,7 @@ var recursiveReadDir = require('recursive-readdir'); describe('angular-fullstack generator', function () { var gen, defaultOptions = { script: 'js', + babel: true, markup: 'html', stylesheet: 'sass', router: 'uirouter', @@ -176,6 +177,7 @@ describe('angular-fullstack generator', function () { 'server/.jshintrc', 'server/.jshintrc-spec', 'server/app.js', + 'server/index.js', 'server/routes.js', 'server/api/thing/index.js', 'server/api/thing/index.spec.js', @@ -476,49 +478,6 @@ describe('angular-fullstack generator', function () { } }); - describe('with Babel ES6 preprocessor', function() { - beforeEach(function() { - helpers.mockPrompt(gen, { - script: 'js', - babel: true, - markup: 'jade', - stylesheet: 'less', - router: 'uirouter' - }); - }); - - it('should run client tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:client', function (error, stdout, stderr) { - expect(stdout, 'Client tests failed \n' + stdout ).to.contain('Executed 1 of 1 SUCCESS'); - done(); - }); - }); - }); - - it('should pass jshint', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt jshint', function (error, stdout, stderr) { - expect(stdout).to.contain('Done, without errors.'); - done(); - }); - }); - }); - - it('should run server tests successfully', function(done) { - this.timeout(60000); - gen.run({}, function () { - exec('grunt test:server', function (error, stdout, stderr) { - expect(stdout, 'Server tests failed (do you have mongoDB running?) \n' + stdout).to.contain('Done, without errors.'); - done(); - }); - }); - }); - }); - - describe('with other preprocessors and oauth', function() { var testOptions = { script: 'coffee', From f87b34c005566026bfce07c9d283719706b675fc Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 28 Jun 2015 01:50:32 -0400 Subject: [PATCH 099/201] chore(dependencies): remove unused dependency wiredep --- app/index.js | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/app/index.js b/app/index.js index 15f8f3b95..b987d44ce 100644 --- a/app/index.js +++ b/app/index.js @@ -5,7 +5,6 @@ var util = require('util'); var genUtils = require('../util.js'); var yeoman = require('yeoman-generator'); var chalk = require('chalk'); -var wiredep = require('wiredep'); var AngularFullstackGenerator = yeoman.generators.Base.extend({ diff --git a/package.json b/package.json index c9e55b21b..0f35ef723 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "dependencies": { "yeoman-generator": "~0.17.0", "chalk": "~0.4.0", - "wiredep": "~0.4.2", "generator-ng-component": "~0.0.4" }, "peerDependencies": { From 443af83cbe1ef6f6eaa40c30df173f0a0bfe8965 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Thu, 2 Jul 2015 21:47:01 -0400 Subject: [PATCH 100/201] fix(gulp:jshint): split jshint into client and server tasks make original jshint task run both tasks for server & client --- app/templates/gulpfile.babel.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 8633e22f9..8bd47cd43 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -93,10 +93,16 @@ function whenServerReady(cb) { // Reusable pipelines // //////////////////////// -var lintScripts = lazypipe()<% if(filters.coffee) { %> +var lintClientScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) .pipe(plugins.coffeelint.reporter);<% } else { %> - .pipe(plugins.jshint, '.jshintrc') + .pipe(plugins.jshint, 'client/.jshintrc') + .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> + +var lintServerScripts = lazypipe()<% if(filters.coffee) { %> + .pipe(plugins.coffeelint) + .pipe(plugins.coffeelint.reporter);<% } else { %> + .pipe(plugins.jshint, 'server/.jshintrc') .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> let styles = lazypipe() @@ -150,7 +156,11 @@ gulp.task('coffee', () => .pipe(gulp.dest('.tmp/scripts')); );<% } %> -gulp.task('lint:scripts', () => gulp.src(_.union(paths.client.scripts, paths.server.scripts)).pipe(lintScripts())); +gulp.task('lint:scripts', cb => runSequence(['lint:scripts:client', 'lint:scripts:server'], cb)); + +gulp.task('lint:scripts:client', () => gulp.src(paths.client.scripts).pipe(lintClientScripts())); + +gulp.task('lint:scripts:server', () => gulp.src(paths.server.scripts).pipe(lintServerScripts())); gulp.task('clean:tmp', () => gulp.src('.tmp', {read: false}).pipe(plugins.clean())); From 79cf0ddabad58c4eca09ce7c7028663daa2c4314 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Thu, 2 Jul 2015 23:52:18 -0400 Subject: [PATCH 101/201] style(gulp): Reformat section comments --- app/templates/gulpfile.babel.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 8bd47cd43..153505a9f 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -56,9 +56,9 @@ var paths = { dist: 'dist' }; -////////////////////// -// Helper functions // -////////////////////// +/******************** + * Helper functions + ********************/ function onServerLog(log) { console.log(plugins.util.colors.white('[') + plugins.util.colors.yellow('nodemon') + plugins.util.colors.white('] ') + log.message); @@ -89,9 +89,9 @@ function whenServerReady(cb) { 100); } -//////////////////////// -// Reusable pipelines // -//////////////////////// +/******************** + * Reusable pipelines + ********************/ var lintClientScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) @@ -117,9 +117,9 @@ let styles = lazypipe() // .pipe(plugins.autoprefixer, {browsers: ['last 1 version']}) //seems to break this .pipe(gulp.dest, '.tmp'); -/////////// -// Tasks // -/////////// +/******************** + * Tasks + ********************/ gulp.task('inject', cb => { runSequence(['inject:js', 'inject:css'], cb); @@ -239,9 +239,9 @@ gulp.task('bower', () => { .pipe(gulp.dest('client/')); }); -/////////// -// Build // -/////////// +/******************** + * Build + ********************/ gulp.task('build', (callback) => { runSequence('clean:dist', From 7cb111d3aa76ba4dc6f83f6d20c101b624dd48f8 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 00:41:45 -0400 Subject: [PATCH 102/201] feat(gulp:injector): Add Sass injector --- app/templates/gulpfile.babel.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 153505a9f..03f98049b 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -27,6 +27,7 @@ var paths = { '!client/bower_components/**/*.js' ], styles: ['client/{app, components}/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], + mainStyle: 'client/app/app.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>', test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], testRequire: [ 'client/bower_components/angular/angular.js', @@ -147,6 +148,17 @@ gulp.task('inject:css', () => { .pipe(gulp.dest('client')); }); +// TODO: other styles +gulp.task('inject:sass', () => { + return gulp.src('client/app/app.scss') + .pipe(plugins.inject(gulp.src(_.union(paths.client.styles, ['!' + paths.client.mainStyle]), {read: false}), { + starttag: '/*injector:sass*/', + endtag: '/*endinjector*/', + transform: (filepath) => '@import \'' + filepath.replace('/client/app/', '').replace('/client/components/', '../components/') + '\';' + })) + .pipe(gulp.dest('client/app')); +}); + gulp.task('styles', styles);<% if(filters.coffee) { %> gulp.task('coffee', () => From 39cfe1f59566eea221e29a176c7724608ebd1fc7 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 15:38:42 -0400 Subject: [PATCH 103/201] refactor(gulp): refactor callbacks --- app/templates/gulpfile.babel.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 03f98049b..6519baa53 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -176,10 +176,10 @@ gulp.task('lint:scripts:server', () => gulp.src(paths.server.scripts).pipe(lintS gulp.task('clean:tmp', () => gulp.src('.tmp', {read: false}).pipe(plugins.clean())); -gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], (callback) => { +gulp.task('start:client', [<% if(filters.coffee) { %>'coffee', <% } %>'styles'], cb => { whenServerReady(() => { open('http://localhost:' + config.port); - callback(); + cb(); }); }); @@ -216,7 +216,7 @@ gulp.task('watch', () => { gulp.watch('bower.json', ['bower']); }); -gulp.task('serve', (callback) => { +gulp.task('serve', cb => { runSequence('clean:tmp', ['lint:scripts'], 'inject:js', @@ -224,7 +224,7 @@ gulp.task('serve', (callback) => { 'bower', ['start:server', 'start:client'], 'watch', - callback); + cb); }); gulp.task('test:server', () => { @@ -255,10 +255,10 @@ gulp.task('bower', () => { * Build ********************/ -gulp.task('build', (callback) => { +gulp.task('build', cb => { runSequence('clean:dist', ['images', 'copy:extras', 'copy:fonts', 'copy:server', 'client:build'], - callback); + cb); }); gulp.task('clean:dist', () => gulp.src('dist', {read: false}).pipe(plugins.clean())); From 1f03946f57df7fbb48486cce318ffab9635ede8e Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 15:39:25 -0400 Subject: [PATCH 104/201] refactor(gulp): use let --- app/templates/gulpfile.babel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 6519baa53..6b8fdcefa 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -94,13 +94,13 @@ function whenServerReady(cb) { * Reusable pipelines ********************/ -var lintClientScripts = lazypipe()<% if(filters.coffee) { %> +let lintClientScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) .pipe(plugins.coffeelint.reporter);<% } else { %> .pipe(plugins.jshint, 'client/.jshintrc') .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> -var lintServerScripts = lazypipe()<% if(filters.coffee) { %> +let lintServerScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) .pipe(plugins.coffeelint.reporter);<% } else { %> .pipe(plugins.jshint, 'server/.jshintrc') From b01cff38021c3df6839fd4fdcaf7863c6edfdcb2 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 17:35:06 -0400 Subject: [PATCH 105/201] refactor(gulp): use variables for file extensions instead of conditional blocks This makes templating a lot easier, since we can shorten a bunch of if blocks in our EJS code to inserting a single variable --- app/index.js | 7 +++++++ app/templates/gulpfile.babel.js | 29 ++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/index.js b/app/index.js index b0bf1e6cc..35fa17ef5 100644 --- a/app/index.js +++ b/app/index.js @@ -255,6 +255,13 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ uibootstrap: true }); + this.scriptExt = this.filters.coffee ? 'coffee' : 'js'; + this.styleExt = this.filters.less ? 'less' : + this.filters.sass ? 'scss' : + this.filters.stylus ? 'styl' : + 'css'; + this.templateExt = this.filters.jade ? 'jade' : 'html'; + var angModules = [ "'ngCookies'", "'ngResource'", diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 6b8fdcefa..10ac0c452 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -23,35 +23,30 @@ var yeoman = { var paths = { client: { scripts: [ - 'client/**/*.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>', + 'client/**/*.<%= scriptExt %>', '!client/bower_components/**/*.js' ], - styles: ['client/{app, components}/**/*.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>'], - mainStyle: 'client/app/app.<% if(filters.stylus) { %>styl<% } else if (filters.sass) { %>scss<% } else { %>css<% } %>', - test: ['client/**/*.spec.<% if(filters.coffee) { %>coffee<% } else { %>js<% } %>'], + styles: ['client/{app, components}/**/*.<%= styleExt %>'], + mainStyle: 'client/app/app.<%= styleExt %>', + test: ['client/**/*.spec.<%= scriptExt %>'], testRequire: [ 'client/bower_components/angular/angular.js', 'client/bower_components/angular-mocks/angular-mocks.js', 'client/bower_components/angular-resource/angular-resource.js', 'client/bower_components/angular-cookies/angular-cookies.js', 'client/bower_components/angular-sanitize/angular-sanitize.js', - 'client/bower_components/angular-route/angular-route.js',<% if(filters.coffee) { %> - 'client/**/*.spec.coffee'<% } else { %> - 'client/**/*.spec.js'<% } %> + 'client/bower_components/angular-route/angular-route.js', + 'client/**/*.spec.<%= scriptExt %>' ], bower: 'client/bower_components/' }, - server: {<% if(filters.coffee) { %> - scripts: ['server/**/*.coffee'], - test: ['server/**/*.spec.coffee'],<% } else { %> - scripts: ['server/**/*.js'], - test: ['server/**/*.spec.js'],<% } %> + server: { + scripts: ['server/**/*.<%= scriptExt %>'], + test: ['server/**/*.spec.<%= scriptExt %>'] }, - views: {<% if(filters.jade) { %> - main: 'client/index.jade', - files: ['client/app/**/*.jade']<% } else {%> - main: 'client/index.html', - files: ['client/app/**/*.html']<% } %> + views: { + main: 'client/index.<%= templateExt %>', + files: ['client/app/**/*.<%= templateExt %>'] }, karma: 'karma.conf.js', dist: 'dist' From 94b2aba98bc24fb87cd20330d7ed7710ed59b766 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 17:36:03 -0400 Subject: [PATCH 106/201] style(gulp): split onServerLog log into multiple lines --- app/templates/gulpfile.babel.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 10ac0c452..9b987c2ce 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -57,7 +57,10 @@ var paths = { ********************/ function onServerLog(log) { - console.log(plugins.util.colors.white('[') + plugins.util.colors.yellow('nodemon') + plugins.util.colors.white('] ') + log.message); + console.log(plugins.util.colors.white('[') + + plugins.util.colors.yellow('nodemon') + + plugins.util.colors.white('] ') + + log.message); } function checkAppReady(cb) { From 3bdda890f6bdebe45cb9a1b92ec81006767631d0 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 17:38:59 -0400 Subject: [PATCH 107/201] fix(gulp): fix remaining refactored linter function uses --- app/templates/gulpfile.babel.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index 9b987c2ce..b48dae040 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -161,7 +161,8 @@ gulp.task('styles', styles);<% if(filters.coffee) { %> gulp.task('coffee', () => gulp.src(paths.client.scripts) - .pipe(lintScripts()) + .pipe(lintClientScripts()) + .pipe(lintServerScripts()) .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts')); );<% } %> @@ -202,14 +203,14 @@ gulp.task('watch', () => { plugins.watch(paths.client.scripts) .pipe(plugins.plumber()) - .pipe(lintScripts())<% if(filters.coffee) { %> + .pipe(lintClientScripts())<% if(filters.coffee) { %> .pipe(plugins.coffee({bare: true}).on('error', plugins.util.log)) .pipe(gulp.dest('.tmp/scripts'))<% } %> .pipe(plugins.livereload()); plugins.watch(_.union(paths.server.scripts, testFiles)) .pipe(plugins.plumber()) - .pipe(lintScripts()); + .pipe(lintServerScripts()); gulp.watch('bower.json', ['bower']); }); From 43920ffa04b26d3d0e8ba177a5bb8cfd3fe63893 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 3 Jul 2015 17:39:42 -0400 Subject: [PATCH 108/201] fix(gulp): fix sass injector start/end tags --- app/templates/gulpfile.babel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel.js b/app/templates/gulpfile.babel.js index b48dae040..2a16eb808 100644 --- a/app/templates/gulpfile.babel.js +++ b/app/templates/gulpfile.babel.js @@ -150,8 +150,8 @@ gulp.task('inject:css', () => { gulp.task('inject:sass', () => { return gulp.src('client/app/app.scss') .pipe(plugins.inject(gulp.src(_.union(paths.client.styles, ['!' + paths.client.mainStyle]), {read: false}), { - starttag: '/*injector:sass*/', - endtag: '/*endinjector*/', + starttag: '// injector', + endtag: '// endinjector', transform: (filepath) => '@import \'' + filepath.replace('/client/app/', '').replace('/client/components/', '../components/') + '\';' })) .pipe(gulp.dest('client/app')); From df82d171488fcff5fdbc19ba255cc6f942b3e593 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 5 Jul 2015 07:49:10 -0400 Subject: [PATCH 109/201] fix(endpoint): fully support sequelize models --- endpoint/templates/index.js | 2 +- endpoint/templates/index.spec.js | 6 +- endpoint/templates/name.controller.js | 71 +++++++++++++------ endpoint/templates/name.integration.js | 6 +- ...oose).js => name.model(mongooseModels).js} | 0 ...ize).js => name.model(sequelizeModels).js} | 0 6 files changed, 58 insertions(+), 27 deletions(-) rename endpoint/templates/{name.model(mongoose).js => name.model(mongooseModels).js} (100%) rename endpoint/templates/{name.model(sequelize).js => name.model(sequelizeModels).js} (100%) diff --git a/endpoint/templates/index.js b/endpoint/templates/index.js index 3f8c592a6..60198d142 100644 --- a/endpoint/templates/index.js +++ b/endpoint/templates/index.js @@ -5,7 +5,7 @@ var controller = require('./<%= name %>.controller'); var router = express.Router(); -router.get('/', controller.index);<% if(filters.mongoose) { %> +router.get('/', controller.index);<% if (filters.models) { %> router.get('/:id', controller.show); router.post('/', controller.create); router.put('/:id', controller.update); diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index ccd15ec7e..291a04662 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -3,7 +3,7 @@ var proxyquire = require('proxyquire').noPreserveCache(); var <%= cameledName %>CtrlStub = { - index: '<%= name %>Ctrl.index'<% if(filters.mongoose) { %>, + index: '<%= name %>Ctrl.index'<% if(filters.models) { %>, show: '<%= name %>Ctrl.show', create: '<%= name %>Ctrl.create', update: '<%= name %>Ctrl.update', @@ -11,7 +11,7 @@ var <%= cameledName %>CtrlStub = { }; var routerStub = { - get: sinon.spy()<% if(filters.mongoose) { %>, + get: sinon.spy()<% if(filters.models) { %>, put: sinon.spy(), patch: sinon.spy(), post: sinon.spy(), @@ -42,7 +42,7 @@ describe('<%= classedName %> API Router:', function() { .should.have.been.calledOnce; }); - });<% if(filters.mongoose) { %> + });<% if(filters.models) { %> describe('GET <%= route %>/:id', function() { diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/name.controller.js index 7d03a42ee..abcc5f34b 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/name.controller.js @@ -1,7 +1,18 @@ -'use strict';<% if(filters.mongoose) { %> +/** + * Using Rails-like standard naming convention for endpoints. + * GET <%= route %> -> index<% if (filters.models) { %> + * POST <%= route %> -> create + * GET <%= route %>/:id -> show + * PUT <%= route %>/:id -> update + * DELETE <%= route %>/:id -> destroy<% } %> + */ -var _ = require('lodash'); -var <%= classedName %> = require('./<%= name %>.model'); +'use strict';<% if (filters.models) { %> + +var _ = require('lodash');<% if (filters.mongooseModels) { %> +var <%= classedName %> = require('./<%= name %>.model');<% } if (filters.sequelizeModels) { %> +var sqldb = require('../../sqldb'); +var <%= classedName %> = sqldb.<%= classedName %>;<% } %> function handleError(res, statusCode) { statusCode = statusCode || 500; @@ -14,7 +25,7 @@ function responseWithResult(res, statusCode) { statusCode = statusCode || 200; return function(entity) { if (entity) { - return res.status(statusCode).json(entity); + res.status(statusCode).json(entity); } }; } @@ -31,9 +42,11 @@ function handleEntityNotFound(res) { function saveUpdates(updates) { return function(entity) { - var updated = _.merge(entity, updates); + <% if (filters.mongooseModels) { %>var updated = _.merge(entity, updates); return updated.saveAsync() - .spread(function(updated) { + .spread(function(updated) {<% } + if (filters.sequelizeModels) { %>return entity.updateAttributes(updates) + .then(function(updated) {<% } %> return updated; }); }; @@ -42,7 +55,8 @@ function saveUpdates(updates) { function removeEntity(res) { return function(entity) { if (entity) { - return entity.removeAsync() + <% if (filters.mongooseModels) { %>return entity.removeAsync()<% } + if (filters.sequelizeModels) { %>return entity.destroy()<% } %> .then(function() { res.status(204).end(); }); @@ -50,44 +64,61 @@ function removeEntity(res) { }; }<% } %> -// Get list of <%= name %>s -exports.index = function(req, res) {<% if (!filters.mongoose) { %> - res.json([]);<% } %><% if (filters.mongoose) { %> - <%= classedName %>.findAsync() +// Gets a list of <%= name %>s +exports.index = function(req, res) {<% if (!filters.models) { %> + res.json([]);<% } else { %> + <% if (filters.mongooseModels) { %><%= classedName %>.findAsync()<% } + if (filters.sequelizeModels) { %><%= classedName %>.findAll()<% } %> .then(responseWithResult(res)) .catch(handleError(res));<% } %> -};<% if (filters.mongoose) { %> +};<% if (filters.models) { %> -// Gets a single <%= name %> from the DB. +// Gets a single <%= name %> from the DB exports.show = function(req, res) { - <%= classedName %>.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %><%= classedName %>.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %><%= classedName %>.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(responseWithResult(res)) .catch(handleError(res)); }; -// Creates a new <%= name %> in the DB. +// Creates a new <%= name %> in the DB exports.create = function(req, res) { - <%= classedName %>.createAsync(req.body) + <% if (filters.mongooseModels) { %><%= classedName %>.createAsync(req.body)<% } + if (filters.sequelizeModels) { %><%= classedName %>.create(req.body)<% } %> .then(responseWithResult(res, 201)) .catch(handleError(res)); }; -// Updates an existing <%= name %> in the DB. +// Updates an existing <%= name %> in the DB exports.update = function(req, res) { if (req.body._id) { delete req.body._id; } - <%= classedName %>.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %><%= classedName %>.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %><%= classedName %>.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(saveUpdates(req.body)) .then(responseWithResult(res)) .catch(handleError(res)); }; -// Deletes a <%= name %> from the DB. +// Deletes a <%= name %> from the DB exports.destroy = function(req, res) { - <%= classedName %>.findByIdAsync(req.params.id) + <% if (filters.mongooseModels) { %><%= classedName %>.findByIdAsync(req.params.id)<% } + if (filters.sequelizeModels) { %><%= classedName %>.find({ + where: { + _id: req.params.id + } + })<% } %> .then(handleEntityNotFound(res)) .then(removeEntity(res)) .catch(handleError(res)); diff --git a/endpoint/templates/name.integration.js b/endpoint/templates/name.integration.js index a377456a4..160cdedfa 100644 --- a/endpoint/templates/name.integration.js +++ b/endpoint/templates/name.integration.js @@ -1,7 +1,7 @@ 'use strict'; var app = require('../../app'); -var request = require('supertest');<% if(filters.mongoose) { %> +var request = require('supertest');<% if(filters.models) { %> var new<%= classedName %>;<% } %> @@ -28,7 +28,7 @@ describe('<%= classedName %> API:', function() { <%= cameledName %>s.should.be.instanceOf(Array); }); - });<% if(filters.mongoose) { %> + });<% if(filters.models) { %> describe('POST <%= route %>', function() { beforeEach(function(done) { @@ -130,7 +130,7 @@ describe('<%= classedName %> API:', function() { }); }); - it('should respond with 404 when <%= name %> does not exsist', function(done) { + it('should respond with 404 when <%= name %> does not exist', function(done) { request(app) .delete('<%= route %>/' + new<%= classedName %>._id) .expect(404) diff --git a/endpoint/templates/name.model(mongoose).js b/endpoint/templates/name.model(mongooseModels).js similarity index 100% rename from endpoint/templates/name.model(mongoose).js rename to endpoint/templates/name.model(mongooseModels).js diff --git a/endpoint/templates/name.model(sequelize).js b/endpoint/templates/name.model(sequelizeModels).js similarity index 100% rename from endpoint/templates/name.model(sequelize).js rename to endpoint/templates/name.model(sequelizeModels).js From 6dc81306fea1abcf57f293f91776e00e9d50ad26 Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 7 Jul 2015 19:36:50 -0400 Subject: [PATCH 110/201] feat(gen): use common endpoint templates for thing route --- app/index.js | 685 +++++++++--------- app/templates/server/api/thing/index.js | 15 - app/templates/server/api/thing/index.spec.js | 97 --- .../api/thing/thing.controller(models).js | 124 ---- .../api/thing/thing.controller(noModels).js | 38 - .../server/api/thing/thing.integration.js | 147 ---- .../api/thing/thing.model(mongooseModels).js | 12 - .../api/thing/thing.model(sequelizeModels).js | 15 - .../api/thing/thing.socket(socketio).js | 33 - 9 files changed, 359 insertions(+), 807 deletions(-) delete mode 100644 app/templates/server/api/thing/index.js delete mode 100644 app/templates/server/api/thing/index.spec.js delete mode 100644 app/templates/server/api/thing/thing.controller(models).js delete mode 100644 app/templates/server/api/thing/thing.controller(noModels).js delete mode 100644 app/templates/server/api/thing/thing.integration.js delete mode 100644 app/templates/server/api/thing/thing.model(mongooseModels).js delete mode 100644 app/templates/server/api/thing/thing.model(sequelizeModels).js delete mode 100644 app/templates/server/api/thing/thing.socket(socketio).js diff --git a/app/index.js b/app/index.js index b987d44ce..5c3ef0673 100644 --- a/app/index.js +++ b/app/index.js @@ -8,379 +8,412 @@ var chalk = require('chalk'); var AngularFullstackGenerator = yeoman.generators.Base.extend({ - init: function () { - this.argument('name', { type: String, required: false }); - this.appname = this.name || path.basename(process.cwd()); - this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname))); - - this.option('app-suffix', { - desc: 'Allow a custom suffix to be added to the module name', - type: String, - required: 'false' - }); - this.scriptAppName = this.appname + genUtils.appName(this); - this.appPath = this.env.options.appPath; - this.pkg = require('../package.json'); - - this.filters = {}; - - // dynamic assertion statement - this.does = this.is = function(foo) { - if (this.filters.should) { - return foo + '.should'; + initializing: { + + init: function () { + this.argument('name', { type: String, required: false }); + this.appname = this.name || path.basename(process.cwd()); + this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname))); + + this.option('app-suffix', { + desc: 'Allow a custom suffix to be added to the module name', + type: String, + required: 'false' + }); + this.scriptAppName = this.appname + genUtils.appName(this); + this.appPath = this.env.options.appPath; + this.pkg = require('../package.json'); + + this.filters = {}; + + // dynamic assertion statement + this.does = this.is = function(foo) { + if (this.filters.should) { + return foo + '.should'; + } else { + return 'expect(' + foo + ').to'; + } + }.bind(this); + }, + + info: function () { + this.log(this.yeoman); + this.log('Out of the box I create an AngularJS app with an Express server.\n'); + }, + + checkForConfig: function() { + var cb = this.async(); + + if(this.config.get('filters')) { + this.prompt([{ + type: 'confirm', + name: 'skipConfig', + message: 'Existing .yo-rc configuration found, would you like to use it?', + default: true, + }], function (answers) { + this.skipConfig = answers.skipConfig; + + this.filters = this._.defaults(this.config.get('filters'), { + bootstrap: true, + uibootstrap: true, + jasmine: true + }); + + // NOTE: temp(?) fix for #403 + if(typeof this.filters.oauth==='undefined') { + var strategies = Object.keys(this.filters).filter(function(key) { + return key.match(/Auth$/) && key; + }); + + if(strategies.length) this.filters.oauth = true; + } + + this.config.forceSave(); + + cb(); + }.bind(this)); } else { - return 'expect(' + foo + ').to'; + cb(); } - }.bind(this); - }, + } - info: function () { - this.log(this.yeoman); - this.log('Out of the box I create an AngularJS app with an Express server.\n'); }, - checkForConfig: function() { - var cb = this.async(); + prompting: { - if(this.config.get('filters')) { - this.prompt([{ - type: 'confirm', - name: 'skipConfig', - message: 'Existing .yo-rc configuration found, would you like to use it?', - default: true, - }], function (answers) { - this.skipConfig = answers.skipConfig; - - this.filters = this._.defaults(this.config.get('filters'), { - bootstrap: true, - uibootstrap: true, - jasmine: true - }); - - // NOTE: temp(?) fix for #403 - if(typeof this.filters.oauth==='undefined') { - var strategies = Object.keys(this.filters).filter(function(key) { - return key.match(/Auth$/) && key; - }); - - if(strategies.length) this.filters.oauth = true; - } + clientPrompts: function() { + if(this.skipConfig) return; + var cb = this.async(); - this.config.forceSave(); + this.log('# Client\n'); - cb(); - }.bind(this)); - } else { - cb(); - } - }, + this.prompt([{ + type: 'list', + name: 'script', + message: 'What would you like to write scripts with?', + choices: [ 'JavaScript', 'CoffeeScript'], + filter: function( val ) { + var filterMap = { + 'JavaScript': 'js', + 'CoffeeScript': 'coffee' + }; + + return filterMap[val]; + } + }, { + type: 'confirm', + name: 'babel', + message: 'Would you like to use Javascript ES6 in your client by preprocessing it with Babel?', + when: function (answers) { + return answers.script === 'js'; + } + }, { + type: 'list', + name: 'markup', + message: 'What would you like to write markup with?', + choices: ['HTML', 'Jade'], + filter: function( val ) { return val.toLowerCase(); } + }, { + type: 'list', + name: 'stylesheet', + default: 1, + message: 'What would you like to write stylesheets with?', + choices: [ 'CSS', 'Sass', 'Stylus', 'Less'], + filter: function( val ) { return val.toLowerCase(); } + }, { + type: 'list', + name: 'router', + default: 1, + message: 'What Angular router would you like to use?', + choices: [ 'ngRoute', 'uiRouter'], + filter: function( val ) { return val.toLowerCase(); } + }, { + type: 'confirm', + name: 'bootstrap', + message: 'Would you like to include Bootstrap?' + }, { + type: 'confirm', + name: 'uibootstrap', + message: 'Would you like to include UI Bootstrap?', + when: function (answers) { + return answers.bootstrap; + } + }], function (answers) { + + this.filters.babel = !!answers.babel; + if(this.filters.babel){ this.filters.js = true; } + this.filters[answers.script] = true; + this.filters[answers.markup] = true; + this.filters[answers.stylesheet] = true; + this.filters[answers.router] = true; + this.filters.bootstrap = !!answers.bootstrap; + this.filters.uibootstrap = !!answers.uibootstrap; + cb(); + }.bind(this)); + }, - clientPrompts: function() { - if(this.skipConfig) return; - var cb = this.async(); + serverPrompts: function() { + if(this.skipConfig) return; + var cb = this.async(); + var self = this; - this.log('# Client\n'); + this.log('\n# Server\n'); - this.prompt([{ + this.prompt([{ + type: 'checkbox', + name: 'odms', + message: 'What would you like to use for data modeling?', + choices: [ + { + value: 'mongoose', + name: 'Mongoose (MongoDB)', + checked: true + }, + { + value: 'sequelize', + name: 'Sequelize (MySQL, SQLite, MariaDB, PostgreSQL)', + checked: false + } + ] + }, { type: 'list', - name: 'script', - message: 'What would you like to write scripts with?', - choices: [ 'JavaScript', 'CoffeeScript'], + name: 'models', + message: 'What would you like to use for the default models?', + choices: [ 'Mongoose', 'Sequelize' ], filter: function( val ) { - var filterMap = { - 'JavaScript': 'js', - 'CoffeeScript': 'coffee' - }; - - return filterMap[val]; + return val.toLowerCase(); + }, + when: function(answers) { + return answers.odms && answers.odms.length > 1; } }, { type: 'confirm', - name: 'babel', - message: 'Would you like to use Javascript ES6 in your client by preprocessing it with Babel?', + name: 'auth', + message: 'Would you scaffold out an authentication boilerplate?', when: function (answers) { - return answers.script === 'js'; + return answers.odms && answers.odms.length !== 0; } }, { - type: 'list', - name: 'markup', - message: 'What would you like to write markup with?', - choices: ['HTML', 'Jade'], - filter: function( val ) { return val.toLowerCase(); } - }, { - type: 'list', - name: 'stylesheet', - default: 1, - message: 'What would you like to write stylesheets with?', - choices: [ 'CSS', 'Sass', 'Stylus', 'Less'], - filter: function( val ) { return val.toLowerCase(); } - }, { - type: 'list', - name: 'router', - default: 1, - message: 'What Angular router would you like to use?', - choices: [ 'ngRoute', 'uiRouter'], - filter: function( val ) { return val.toLowerCase(); } - }, { - type: 'confirm', - name: 'bootstrap', - message: 'Would you like to include Bootstrap?' + type: 'checkbox', + name: 'oauth', + message: 'Would you like to include additional oAuth strategies?', + when: function (answers) { + return answers.auth; + }, + choices: [ + { + value: 'googleAuth', + name: 'Google', + checked: false + }, + { + value: 'facebookAuth', + name: 'Facebook', + checked: false + }, + { + value: 'twitterAuth', + name: 'Twitter', + checked: false + } + ] }, { type: 'confirm', - name: 'uibootstrap', - message: 'Would you like to include UI Bootstrap?', + name: 'socketio', + message: 'Would you like to use socket.io?', + // to-do: should not be dependent on ODMs when: function (answers) { - return answers.bootstrap; - } + return answers.odms && answers.odms.length !== 0; + }, + default: true }], function (answers) { + if(answers.socketio) this.filters.socketio = true; + if(answers.auth) this.filters.auth = true; + if(answers.odms && answers.odms.length > 0) { + var models; + if(!answers.models) { + models = answers.odms[0]; + } else { + models = answers.models; + } + this.filters.models = true; + this.filters[models + 'Models'] = true; + answers.odms.forEach(function(odm) { + this.filters[odm] = true; + }.bind(this)); + } else { + this.filters.noModels = true; + } + if(answers.oauth) { + if(answers.oauth.length) this.filters.oauth = true; + answers.oauth.forEach(function(oauthStrategy) { + this.filters[oauthStrategy] = true; + }.bind(this)); + } - this.filters.babel = !!answers.babel; - if(this.filters.babel){ this.filters.js = true; } - this.filters[answers.script] = true; - this.filters[answers.markup] = true; - this.filters[answers.stylesheet] = true; - this.filters[answers.router] = true; - this.filters.bootstrap = !!answers.bootstrap; - this.filters.uibootstrap = !!answers.uibootstrap; cb(); }.bind(this)); - }, + }, - serverPrompts: function() { - if(this.skipConfig) return; - var cb = this.async(); - var self = this; - - this.log('\n# Server\n'); - - this.prompt([{ - type: 'checkbox', - name: 'odms', - message: 'What would you like to use for data modeling?', - choices: [ - { - value: 'mongoose', - name: 'Mongoose (MongoDB)', - checked: true - }, - { - value: 'sequelize', - name: 'Sequelize (MySQL, SQLite, MariaDB, PostgreSQL)', - checked: false + projectPrompts: function() { + if(this.skipConfig) return; + var cb = this.async(); + var self = this; + + this.log('\n# Project\n'); + + this.prompt([{ + type: 'list', + name: 'testing', + message: 'What would you like to write tests with?', + choices: [ 'Jasmine', 'Mocha + Chai + Sinon'], + filter: function( val ) { + var filterMap = { + 'Jasmine': 'jasmine', + 'Mocha + Chai + Sinon': 'mocha' + }; + + return filterMap[val]; } - ] - }, { - type: 'list', - name: 'models', - message: 'What would you like to use for the default models?', - choices: [ 'Mongoose', 'Sequelize' ], - filter: function( val ) { - return val.toLowerCase(); - }, - when: function(answers) { - return answers.odms && answers.odms.length > 1; - } - }, { - type: 'confirm', - name: 'auth', - message: 'Would you scaffold out an authentication boilerplate?', - when: function (answers) { - return answers.odms && answers.odms.length !== 0; - } - }, { - type: 'checkbox', - name: 'oauth', - message: 'Would you like to include additional oAuth strategies?', - when: function (answers) { - return answers.auth; - }, - choices: [ - { - value: 'googleAuth', - name: 'Google', - checked: false - }, - { - value: 'facebookAuth', - name: 'Facebook', - checked: false + }, { + type: 'list', + name: 'chai', + message: 'What would you like to write Chai assertions with?', + choices: ['Expect', 'Should'], + filter: function( val ) { + return val.toLowerCase(); }, - { - value: 'twitterAuth', - name: 'Twitter', - checked: false + when: function( answers ) { + return answers.testing === 'mocha'; } - ] - }, { - type: 'confirm', - name: 'socketio', - message: 'Would you like to use socket.io?', - // to-do: should not be dependent on ODMs - when: function (answers) { - return answers.odms && answers.odms.length !== 0; - }, - default: true - }], function (answers) { - if(answers.socketio) this.filters.socketio = true; - if(answers.auth) this.filters.auth = true; - if(answers.odms && answers.odms.length > 0) { - var models; - if(!answers.models) { - models = answers.odms[0]; - } else { - models = answers.models; + }], function (answers) { + this.filters[answers.testing] = true; + if (answers.testing === 'mocha') { + this.filters.jasmine = false; + this.filters.should = false; + this.filters.expect = false; + this.filters[answers.chai] = true; + } + if (answers.testing === 'jasmine') { + this.filters.mocha = false; + this.filters.should = false; + this.filters.expect = false; } - this.filters.models = true; - this.filters[models + 'Models'] = true; - answers.odms.forEach(function(odm) { - this.filters[odm] = true; - }.bind(this)); - } else { - this.filters.noModels = true; - } - if(answers.oauth) { - if(answers.oauth.length) this.filters.oauth = true; - answers.oauth.forEach(function(oauthStrategy) { - this.filters[oauthStrategy] = true; - }.bind(this)); - } - cb(); - }.bind(this)); + cb(); + }.bind(this)); + } + }, - projectPrompts: function() { - if(this.skipConfig) return; - var cb = this.async(); - var self = this; - - this.log('\n# Project\n'); - - this.prompt([{ - type: 'list', - name: 'testing', - message: 'What would you like to write tests with?', - choices: [ 'Jasmine', 'Mocha + Chai + Sinon'], - filter: function( val ) { - var filterMap = { - 'Jasmine': 'jasmine', - 'Mocha + Chai + Sinon': 'mocha' - }; - - return filterMap[val]; - } - }, { - type: 'list', - name: 'chai', - message: 'What would you like to write Chai assertions with?', - choices: ['Expect', 'Should'], - filter: function( val ) { - return val.toLowerCase(); - }, - when: function( answers ) { - return answers.testing === 'mocha'; - } - }], function (answers) { - this.filters[answers.testing] = true; - if (answers.testing === 'mocha') { - this.filters.jasmine = false; - this.filters.should = false; - this.filters.expect = false; - this.filters[answers.chai] = true; - } - if (answers.testing === 'jasmine') { - this.filters.mocha = false; - this.filters.should = false; - this.filters.expect = false; - } + configuring: { + + saveSettings: function() { + if(this.skipConfig) return; + this.config.set('insertRoutes', true); + this.config.set('registerRoutesFile', 'server/routes.js'); + this.config.set('routesNeedle', '// Insert routes below'); + + this.config.set('routesBase', '/api/'); + this.config.set('pluralizeRoutes', true); + + this.config.set('insertSockets', true); + this.config.set('registerSocketsFile', 'server/config/socketio.js'); + this.config.set('socketsNeedle', '// Insert sockets below'); + + this.config.set('insertModels', true); + this.config.set('registerModelsFile', 'server/sqldb/index.js'); + this.config.set('modelsNeedle', '// Insert models below'); + + this.config.set('filters', this.filters); + this.config.forceSave(); + }, + + ngComponent: function() { + if(this.skipConfig) return; + var appPath = 'client/app/'; + var extensions = []; + var filters = [ + 'ngroute', + 'uirouter', + 'jasmine', + 'mocha', + 'expect', + 'should' + ].filter(function(v) {return this.filters[v];}, this); + + if(this.filters.ngroute) filters.push('ngroute'); + if(this.filters.uirouter) filters.push('uirouter'); + if(this.filters.babel) extensions.push('babel'); + if(this.filters.coffee) extensions.push('coffee'); + if(this.filters.js) extensions.push('js'); + if(this.filters.html) extensions.push('html'); + if(this.filters.jade) extensions.push('jade'); + if(this.filters.css) extensions.push('css'); + if(this.filters.stylus) extensions.push('styl'); + if(this.filters.sass) extensions.push('scss'); + if(this.filters.less) extensions.push('less'); + + this.composeWith('ng-component', { + options: { + 'routeDirectory': appPath, + 'directiveDirectory': appPath, + 'filterDirectory': appPath, + 'serviceDirectory': appPath, + 'filters': filters, + 'extensions': extensions, + 'basePath': 'client' + } + }, { local: require.resolve('generator-ng-component/app/index.js') }); + }, + + ngModules: function() { + var angModules = [ + "'ngCookies'", + "'ngResource'", + "'ngSanitize'" + ]; + if(this.filters.ngroute) angModules.push("'ngRoute'"); + if(this.filters.socketio) angModules.push("'btford.socket-io'"); + if(this.filters.uirouter) angModules.push("'ui.router'"); + if(this.filters.uibootstrap) angModules.push("'ui.bootstrap'"); + + this.angularModules = '\n ' + angModules.join(',\n ') +'\n'; + } - cb(); - }.bind(this)); }, - saveSettings: function() { - if(this.skipConfig) return; - this.config.set('insertRoutes', true); - this.config.set('registerRoutesFile', 'server/routes.js'); - this.config.set('routesNeedle', '// Insert routes below'); + default: {}, - this.config.set('routesBase', '/api/'); - this.config.set('pluralizeRoutes', true); + writing: { - this.config.set('insertSockets', true); - this.config.set('registerSocketsFile', 'server/config/socketio.js'); - this.config.set('socketsNeedle', '// Insert sockets below'); + generateProject: function() { + this.sourceRoot(path.join(__dirname, './templates')); + genUtils.processDirectory(this, '.', '.'); + }, - this.config.set('insertModels', true); - this.config.set('registerModelsFile', 'server/sqldb/index.js'); - this.config.set('modelsNeedle', '// Insert models below'); + generateEndpoint: function() { + var name = this.name = this.cameledName = 'thing'; + this.classedName = name.charAt(0).toUpperCase() + name.slice(1); + this.route = '/api/' + name + 's'; + this.sourceRoot(path.join(__dirname, '..', 'endpoint', 'templates')); + genUtils.processDirectory(this, '.', 'server/api/' + name); + } - this.config.set('filters', this.filters); - this.config.forceSave(); }, - compose: function() { - if(this.skipConfig) return; - var appPath = 'client/app/'; - var extensions = []; - var filters = [ - 'ngroute', - 'uirouter', - 'jasmine', - 'mocha', - 'expect', - 'should' - ].filter(function(v) {return this.filters[v];}, this); - - if(this.filters.ngroute) filters.push('ngroute'); - if(this.filters.uirouter) filters.push('uirouter'); - if(this.filters.babel) extensions.push('babel'); - if(this.filters.coffee) extensions.push('coffee'); - if(this.filters.js) extensions.push('js'); - if(this.filters.html) extensions.push('html'); - if(this.filters.jade) extensions.push('jade'); - if(this.filters.css) extensions.push('css'); - if(this.filters.stylus) extensions.push('styl'); - if(this.filters.sass) extensions.push('scss'); - if(this.filters.less) extensions.push('less'); - - this.composeWith('ng-component', { - options: { - 'routeDirectory': appPath, - 'directiveDirectory': appPath, - 'filterDirectory': appPath, - 'serviceDirectory': appPath, - 'filters': filters, - 'extensions': extensions, - 'basePath': 'client' - } - }, { local: require.resolve('generator-ng-component/app/index.js') }); - }, + install: { - ngModules: function() { - var angModules = [ - "'ngCookies'", - "'ngResource'", - "'ngSanitize'" - ]; - if(this.filters.ngroute) angModules.push("'ngRoute'"); - if(this.filters.socketio) angModules.push("'btford.socket-io'"); - if(this.filters.uirouter) angModules.push("'ui.router'"); - if(this.filters.uibootstrap) angModules.push("'ui.bootstrap'"); - - this.angularModules = '\n ' + angModules.join(',\n ') +'\n'; - }, + installDeps: function() { + this.installDependencies({ + skipInstall: this.options['skip-install'] + }); + } - generate: function() { - this.sourceRoot(path.join(__dirname, './templates')); - genUtils.processDirectory(this, '.', '.'); }, - end: function() { - this.installDependencies({ - skipInstall: this.options['skip-install'] - }); - } + end: {} + }); module.exports = AngularFullstackGenerator; diff --git a/app/templates/server/api/thing/index.js b/app/templates/server/api/thing/index.js deleted file mode 100644 index fde8f3968..000000000 --- a/app/templates/server/api/thing/index.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var express = require('express'); -var controller = require('./thing.controller'); - -var router = express.Router(); - -router.get('/', controller.index);<% if (filters.models) { %> -router.get('/:id', controller.show); -router.post('/', controller.create); -router.put('/:id', controller.update); -router.patch('/:id', controller.update); -router.delete('/:id', controller.destroy);<% } %> - -module.exports = router; diff --git a/app/templates/server/api/thing/index.spec.js b/app/templates/server/api/thing/index.spec.js deleted file mode 100644 index 91f02f6df..000000000 --- a/app/templates/server/api/thing/index.spec.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -var proxyquire = require('proxyquire').noPreserveCache(); - -var thingCtrlStub = { - index: 'thingCtrl.index'<% if (filters.models) { %>, - show: 'thingCtrl.show', - create: 'thingCtrl.create', - update: 'thingCtrl.update', - destroy: 'thingCtrl.destroy'<% } %> -}; - -var routerStub = { - get: sinon.spy()<% if (filters.models) { %>, - put: sinon.spy(), - patch: sinon.spy(), - post: sinon.spy(), - delete: sinon.spy()<% } %> -}; - -// require the index with our stubbed out modules -var thingIndex = proxyquire('./index.js', { - 'express': { - Router: function() { - return routerStub; - } - }, - './thing.controller': thingCtrlStub -}); - -describe('Thing API Router:', function() { - - it('should return an express router instance', function() { - thingIndex.should.equal(routerStub); - }); - - describe('GET /api/things', function() { - - it('should route to thing.controller.index', function() { - routerStub.get - .withArgs('/', 'thingCtrl.index') - .should.have.been.calledOnce; - }); - - });<% if (filters.models) { %> - - describe('GET /api/things/:id', function() { - - it('should route to thing.controller.show', function() { - routerStub.get - .withArgs('/:id', 'thingCtrl.show') - .should.have.been.calledOnce; - }); - - }); - - describe('POST /api/things', function() { - - it('should route to thing.controller.create', function() { - routerStub.post - .withArgs('/', 'thingCtrl.create') - .should.have.been.calledOnce; - }); - - }); - - describe('PUT /api/things/:id', function() { - - it('should route to thing.controller.update', function() { - routerStub.put - .withArgs('/:id', 'thingCtrl.update') - .should.have.been.calledOnce; - }); - - }); - - describe('PATCH /api/things/:id', function() { - - it('should route to thing.controller.update', function() { - routerStub.patch - .withArgs('/:id', 'thingCtrl.update') - .should.have.been.calledOnce; - }); - - }); - - describe('DELETE /api/things/:id', function() { - - it('should route to thing.controller.destroy', function() { - routerStub.delete - .withArgs('/:id', 'thingCtrl.destroy') - .should.have.been.calledOnce; - }); - - });<% } %> - -}); diff --git a/app/templates/server/api/thing/thing.controller(models).js b/app/templates/server/api/thing/thing.controller(models).js deleted file mode 100644 index c7874b515..000000000 --- a/app/templates/server/api/thing/thing.controller(models).js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Using Rails-like standard naming convention for endpoints. - * GET /things -> index - * POST /things -> create - * GET /things/:id -> show - * PUT /things/:id -> update - * DELETE /things/:id -> destroy - */ - -'use strict'; - -var _ = require('lodash');<% if (filters.mongooseModels) { %> -var Thing = require('./thing.model');<% } %><% if (filters.sequelizeModels) { %> -var sqldb = require('../../sqldb') -var Thing = sqldb.Thing;<% } %> - -function handleError(res, statusCode) { - statusCode = statusCode || 500; - return function(err) { - res.status(statusCode).send(err); - }; -} - -function responseWithResult(res, statusCode) { - statusCode = statusCode || 200; - return function(entity) { - if (entity) { - return res.status(statusCode).json(entity); - } - }; -} - -function handleEntityNotFound(res) { - return function(entity) { - if (!entity) { - res.status(404).end(); - return null; - } - return entity; - }; -} - -function saveUpdates(updates) { - return function(entity) { - <% if (filters.mongooseModels) { %>var updated = _.merge(entity, updates); - return updated.saveAsync() - .spread(function(updated) {<% } - if (filters.sequelizeModels) { %>return entity.updateAttributes(updates) - .then(function(updated) {<% } %> - return updated; - }); - }; -} - -function removeEntity(res) { - return function(entity) { - if (entity) { - <% if (filters.mongooseModels) { %>return entity.removeAsync()<% } - if (filters.sequelizeModels) { %>return entity.destroy()<% } %> - .then(function() { - return res.status(204).end(); - }); - } - }; -} - -// Get list of things -exports.index = function(req, res) { - <% if (filters.mongooseModels) { %>Thing.findAsync()<% } - if (filters.sequelizeModels) { %>Thing.findAll()<% } %> - .then(responseWithResult(res)) - .catch(handleError(res)); -}; - -// Get a single thing -exports.show = function(req, res) { - <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } - if (filters.sequelizeModels) { %>Thing.find({ - where: { - _id: req.params.id - } - })<% } %> - .then(handleEntityNotFound(res)) - .then(responseWithResult(res)) - .catch(handleError(res)); -}; - -// Creates a new thing in the DB. -exports.create = function(req, res) { - <% if (filters.mongooseModels) { %>Thing.createAsync(req.body)<% } - if (filters.sequelizeModels) { %>Thing.create(req.body)<% } %> - .then(responseWithResult(res, 201)) - .catch(handleError(res)); -}; - -// Updates an existing thing in the DB. -exports.update = function(req, res) { - if (req.body._id) { - delete req.body._id; - } - <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } - if (filters.sequelizeModels) { %>Thing.find({ - where: { - _id: req.params.id - } - })<% } %> - .then(handleEntityNotFound(res)) - .then(saveUpdates(req.body)) - .then(responseWithResult(res)) - .catch(handleError(res)); -}; - -// Deletes a thing from the DB. -exports.destroy = function(req, res) { - <% if (filters.mongooseModels) { %>Thing.findByIdAsync(req.params.id)<% } - if (filters.sequelizeModels) { %>Thing.find({ - where: { - _id: req.params.id - } - })<% } %> - .then(handleEntityNotFound(res)) - .then(removeEntity(res)) - .catch(handleError(res)); -}; diff --git a/app/templates/server/api/thing/thing.controller(noModels).js b/app/templates/server/api/thing/thing.controller(noModels).js deleted file mode 100644 index a39041258..000000000 --- a/app/templates/server/api/thing/thing.controller(noModels).js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Using Rails-like standard naming convention for endpoints. - * GET /things -> index - * POST /things -> create - * GET /things/:id -> show - * PUT /things/:id -> update - * DELETE /things/:id -> destroy - */ - -'use strict'; - -// Get list of things -exports.index = function(req, res) { - res.json([{ - name: 'Development Tools', - info: 'Integration with popular tools such as Bower, Grunt, Karma, Mocha, JSHint, ' + - 'Node Inspector, Livereload, Protractor, Jade, Stylus, Sass, CoffeeScript, and Less.' - }, { - name: 'Server and Client integration', - info: 'Built with a powerful and fun stack: MongoDB, Express, AngularJS, and Node.' - }, { - name: 'Smart Build System', - info: 'Build system ignores `spec` files, allowing you to keep tests alongside code. ' + - 'Automatic injection of scripts and styles into your index.html' - }, { - name: 'Modular Structure', - info: 'Best practice client and server structures allow for more code reusability and ' + - 'maximum scalability' - }, { - name: 'Optimized Build', - info: 'Build process packs up your templates as a single JavaScript payload, minifies ' + - 'your scripts/css/images, and rewrites asset names for caching.' - }, { - name: 'Deployment Ready', - info: 'Easily deploy your app to Heroku or Openshift with the heroku and openshift ' + - 'sub-generators' - }]); -}; diff --git a/app/templates/server/api/thing/thing.integration.js b/app/templates/server/api/thing/thing.integration.js deleted file mode 100644 index 3eb5d05d8..000000000 --- a/app/templates/server/api/thing/thing.integration.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict'; - -var app = require('../../app'); -var request = require('supertest');<% if (filters.models) { %> - -var newThing;<% } %> - -describe('Thing API:', function() { - - describe('GET /api/things', function() { - var things; - - beforeEach(function(done) { - request(app) - .get('/api/things') - .expect(200) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) { - return done(err); - } - things = res.body; - done(); - }); - }); - - it('should respond with JSON array', function() { - things.should.be.instanceOf(Array); - }); - - });<% if (filters.models) { %> - - describe('POST /api/things', function() { - beforeEach(function(done) { - request(app) - .post('/api/things') - .send({ - name: 'New Thing', - info: 'This is the brand new thing!!!' - }) - .expect(201) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) { - return done(err); - } - newThing = res.body; - done(); - }); - }); - - it('should respond with the newly created thing', function() { - newThing.name.should.equal('New Thing'); - newThing.info.should.equal('This is the brand new thing!!!'); - }); - - }); - - describe('GET /api/things/:id', function() { - var thing; - - beforeEach(function(done) { - request(app) - .get('/api/things/' + newThing._id) - .expect(200) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) { - return done(err); - } - thing = res.body; - done(); - }); - }); - - afterEach(function() { - thing = {}; - }); - - it('should respond with the requested thing', function() { - thing.name.should.equal('New Thing'); - thing.info.should.equal('This is the brand new thing!!!'); - }); - - }); - - describe('PUT /api/things/:id', function() { - var updatedThing - - beforeEach(function(done) { - request(app) - .put('/api/things/' + newThing._id) - .send({ - name: 'Updated Thing', - info: 'This is the updated thing!!!' - }) - .expect(200) - .expect('Content-Type', /json/) - .end(function(err, res) { - if (err) { - return done(err); - } - updatedThing = res.body; - done(); - }); - }); - - afterEach(function() { - updatedThing = {}; - }); - - it('should respond with the updated thing', function() { - updatedThing.name.should.equal('Updated Thing'); - updatedThing.info.should.equal('This is the updated thing!!!'); - }); - - }); - - describe('DELETE /api/things/:id', function() { - - it('should respond with 204 on successful removal', function(done) { - request(app) - .delete('/api/things/' + newThing._id) - .expect(204) - .end(function(err, res) { - if (err) { - return done(err); - } - done(); - }); - }); - - it('should respond with 404 when thing does not exist', function(done) { - request(app) - .delete('/api/things/' + newThing._id) - .expect(404) - .end(function(err, res) { - if (err) { - return done(err); - } - done(); - }); - }); - - });<% } %> - -}); diff --git a/app/templates/server/api/thing/thing.model(mongooseModels).js b/app/templates/server/api/thing/thing.model(mongooseModels).js deleted file mode 100644 index d1e6e49ea..000000000 --- a/app/templates/server/api/thing/thing.model(mongooseModels).js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var mongoose = require('mongoose-bird')(); -var Schema = mongoose.Schema; - -var ThingSchema = new Schema({ - name: String, - info: String, - active: Boolean -}); - -module.exports = mongoose.model('Thing', ThingSchema); diff --git a/app/templates/server/api/thing/thing.model(sequelizeModels).js b/app/templates/server/api/thing/thing.model(sequelizeModels).js deleted file mode 100644 index 8e8072da4..000000000 --- a/app/templates/server/api/thing/thing.model(sequelizeModels).js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -module.exports = function(sequelize, DataTypes) { - return sequelize.define('Thing', { - _id: { - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true - }, - name: DataTypes.STRING, - info: DataTypes.STRING, - active: DataTypes.BOOLEAN - }); -}; diff --git a/app/templates/server/api/thing/thing.socket(socketio).js b/app/templates/server/api/thing/thing.socket(socketio).js deleted file mode 100644 index d0d98a6ca..000000000 --- a/app/templates/server/api/thing/thing.socket(socketio).js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Broadcast updates to client when the model changes - */ - -'use strict'; -<% if (filters.mongooseModels) { %> -var thing = require('./thing.model');<% } %><% if (filters.sequelizeModels) { %> -var thing = require('../../sqldb').Thing;<% } %> - -exports.register = function(socket) {<% if (filters.sequelizeModels) { %> - thing.hook('afterCreate', function(doc, fields, fn) { - onSave(socket, doc); - fn(null); - });<% } %> - <% if (filters.mongooseModels) { %>thing.schema.post('save', function(doc) {<% } - if (filters.sequelizeModels) { %>thing.hook('afterUpdate', function(doc, fields, fn) {<% } %> - onSave(socket, doc);<% if (filters.sequelizeModels) { %> - fn(null);<% } %> - }); - <% if (filters.mongooseModels) { %>thing.schema.post('remove', function(doc) {<% } - if (filters.sequelizeModels) { %>thing.hook('afterDestroy', function(doc, fields, fn) {<% } %> - onRemove(socket, doc);<% if (filters.sequelizeModels) { %> - fn(null);<% } %> - }); -}; - -function onSave(socket, doc, cb) { - socket.emit('thing:save', doc); -} - -function onRemove(socket, doc, cb) { - socket.emit('thing:remove', doc); -} From 24171aa4962b460770876bf6232f6b82a27e9925 Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 7 Jul 2015 18:30:59 -0400 Subject: [PATCH 111/201] feat(app): implement navbar as directive --- .../client/app/account(auth)/login/login(html).html | 2 +- .../client/app/account(auth)/login/login(jade).jade | 2 +- .../app/account(auth)/settings/settings(html).html | 2 +- .../app/account(auth)/settings/settings(jade).jade | 2 +- .../client/app/account(auth)/signup/signup(html).html | 2 +- .../client/app/account(auth)/signup/signup(jade).jade | 2 +- app/templates/client/app/admin(auth)/admin(html).html | 2 +- app/templates/client/app/admin(auth)/admin(jade).jade | 4 ++-- app/templates/client/app/main/main(html).html | 2 +- app/templates/client/app/main/main(jade).jade | 4 ++-- .../components/navbar/navbar.directive(coffee).coffee | 7 +++++++ .../client/components/navbar/navbar.directive(js).js | 10 ++++++++++ test/test-file-creation.js | 1 + 13 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 app/templates/client/components/navbar/navbar.directive(coffee).coffee create mode 100644 app/templates/client/components/navbar/navbar.directive(js).js diff --git a/app/templates/client/app/account(auth)/login/login(html).html b/app/templates/client/app/account(auth)/login/login(html).html index f02de2616..667ecdd0e 100644 --- a/app/templates/client/app/account(auth)/login/login(html).html +++ b/app/templates/client/app/account(auth)/login/login(html).html @@ -1,4 +1,4 @@ -
+
diff --git a/app/templates/client/app/account(auth)/login/login(jade).jade b/app/templates/client/app/account(auth)/login/login(jade).jade index fd95e6ff1..e7ce91916 100644 --- a/app/templates/client/app/account(auth)/login/login(jade).jade +++ b/app/templates/client/app/account(auth)/login/login(jade).jade @@ -1,4 +1,4 @@ -div(ng-include='"components/navbar/navbar.html"') +navbar .container .row .col-sm-12 diff --git a/app/templates/client/app/account(auth)/settings/settings(html).html b/app/templates/client/app/account(auth)/settings/settings(html).html index bb5d8ded0..fe5c7f0f7 100644 --- a/app/templates/client/app/account(auth)/settings/settings(html).html +++ b/app/templates/client/app/account(auth)/settings/settings(html).html @@ -1,4 +1,4 @@ -
+
diff --git a/app/templates/client/app/account(auth)/settings/settings(jade).jade b/app/templates/client/app/account(auth)/settings/settings(jade).jade index 2dc55d402..96340b522 100644 --- a/app/templates/client/app/account(auth)/settings/settings(jade).jade +++ b/app/templates/client/app/account(auth)/settings/settings(jade).jade @@ -1,4 +1,4 @@ -div(ng-include='"components/navbar/navbar.html"') +navbar .container .row .col-sm-12 diff --git a/app/templates/client/app/account(auth)/signup/signup(html).html b/app/templates/client/app/account(auth)/signup/signup(html).html index fc55d3790..5052a02ee 100644 --- a/app/templates/client/app/account(auth)/signup/signup(html).html +++ b/app/templates/client/app/account(auth)/signup/signup(html).html @@ -1,4 +1,4 @@ -
+
diff --git a/app/templates/client/app/account(auth)/signup/signup(jade).jade b/app/templates/client/app/account(auth)/signup/signup(jade).jade index 081657a6d..cca29a28e 100644 --- a/app/templates/client/app/account(auth)/signup/signup(jade).jade +++ b/app/templates/client/app/account(auth)/signup/signup(jade).jade @@ -1,4 +1,4 @@ -div(ng-include='"components/navbar/navbar.html"') +navbar .container .row .col-sm-12 diff --git a/app/templates/client/app/admin(auth)/admin(html).html b/app/templates/client/app/admin(auth)/admin(html).html index 5c27c7af2..e20129214 100644 --- a/app/templates/client/app/admin(auth)/admin(html).html +++ b/app/templates/client/app/admin(auth)/admin(html).html @@ -1,4 +1,4 @@ -
+

The delete user and user index api routes are restricted to users with the 'admin' role.

diff --git a/app/templates/client/app/admin(auth)/admin(jade).jade b/app/templates/client/app/admin(auth)/admin(jade).jade index fd80a0bb6..bcef64773 100644 --- a/app/templates/client/app/admin(auth)/admin(jade).jade +++ b/app/templates/client/app/admin(auth)/admin(jade).jade @@ -1,4 +1,4 @@ -div(ng-include='"components/navbar/navbar.html"') +navbar .container p | The delete user and user index api routes are restricted to users with the 'admin' role. @@ -8,4 +8,4 @@ div(ng-include='"components/navbar/navbar.html"') br span.text-muted {{user.email}} a.trash(ng-click='delete(user)') - span.glyphicon.glyphicon-trash.pull-right \ No newline at end of file + span.glyphicon.glyphicon-trash.pull-right diff --git a/app/templates/client/app/main/main(html).html b/app/templates/client/app/main/main(html).html index 7d0d5c44b..9416ef0db 100644 --- a/app/templates/client/app/main/main(html).html +++ b/app/templates/client/app/main/main(html).html @@ -1,4 +1,4 @@ -
+
-
\ No newline at end of file +
diff --git a/app/templates/client/app/admin(auth)/admin(coffee).coffee b/app/templates/client/app/admin(auth)/admin(coffee).coffee index 18bb9d4ad..99b49177f 100644 --- a/app/templates/client/app/admin(auth)/admin(coffee).coffee +++ b/app/templates/client/app/admin(auth)/admin(coffee).coffee @@ -12,4 +12,4 @@ angular.module '<%= scriptAppName %>' url: '/admin' templateUrl: 'app/admin/admin.html' controller: 'AdminCtrl' -<% } %> \ No newline at end of file +<% } %> diff --git a/app/templates/client/app/admin(auth)/admin(html).html b/app/templates/client/app/admin(auth)/admin(html).html index e20129214..7688c9b47 100644 --- a/app/templates/client/app/admin(auth)/admin(html).html +++ b/app/templates/client/app/admin(auth)/admin(html).html @@ -9,4 +9,4 @@ -
\ No newline at end of file +
diff --git a/app/templates/client/app/admin(auth)/admin(less).less b/app/templates/client/app/admin(auth)/admin(less).less index ad8202750..a6f536dc5 100644 --- a/app/templates/client/app/admin(auth)/admin(less).less +++ b/app/templates/client/app/admin(auth)/admin(less).less @@ -1 +1 @@ -.trash { color:rgb(209, 91, 71); } \ No newline at end of file +.trash { color:rgb(209, 91, 71); } diff --git a/app/templates/client/app/admin(auth)/admin(stylus).styl b/app/templates/client/app/admin(auth)/admin(stylus).styl index d57e50db5..d7d50a172 100644 --- a/app/templates/client/app/admin(auth)/admin(stylus).styl +++ b/app/templates/client/app/admin(auth)/admin(stylus).styl @@ -1,2 +1,2 @@ .trash - color rgb(209, 91, 71) \ No newline at end of file + color rgb(209, 91, 71) diff --git a/app/templates/client/app/main/main(coffee).coffee b/app/templates/client/app/main/main(coffee).coffee index 5d28335d1..04cd367bb 100644 --- a/app/templates/client/app/main/main(coffee).coffee +++ b/app/templates/client/app/main/main(coffee).coffee @@ -12,4 +12,4 @@ angular.module '<%= scriptAppName %>' url: '/' templateUrl: 'app/main/main.html' controller: 'MainCtrl' -<% } %> \ No newline at end of file +<% } %> diff --git a/app/templates/client/components/modal(uibootstrap)/modal(css).css b/app/templates/client/components/modal(uibootstrap)/modal(css).css index f5cc0d9e7..ae0406856 100644 --- a/app/templates/client/components/modal(uibootstrap)/modal(css).css +++ b/app/templates/client/components/modal(uibootstrap)/modal(css).css @@ -20,4 +20,4 @@ } .modal-danger .modal-header { background: #d9534f; -} \ No newline at end of file +} diff --git a/app/templates/client/components/modal(uibootstrap)/modal(html).html b/app/templates/client/components/modal(uibootstrap)/modal(html).html index 4580254ff..f04d0db03 100644 --- a/app/templates/client/components/modal(uibootstrap)/modal(html).html +++ b/app/templates/client/components/modal(uibootstrap)/modal(html).html @@ -8,4 +8,4 @@
\ No newline at end of file + diff --git a/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(coffee).coffee b/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(coffee).coffee index d255f614d..cf0e1ccf0 100644 --- a/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(coffee).coffee +++ b/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(coffee).coffee @@ -9,4 +9,4 @@ angular.module '<%= scriptAppName %>' require: 'ngModel' link: (scope, element, attrs, ngModel) -> element.on 'keydown', -> - ngModel.$setValidity 'mongoose', true \ No newline at end of file + ngModel.$setValidity 'mongoose', true diff --git a/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(js).js b/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(js).js index 8a331009b..a71cb03cf 100644 --- a/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(js).js +++ b/app/templates/client/components/mongoose-error(auth)/mongoose-error.directive(js).js @@ -14,4 +14,4 @@ angular.module('<%= scriptAppName %>') }); } }; - }); \ No newline at end of file + }); diff --git a/app/templates/client/components/navbar/navbar(jade).jade b/app/templates/client/components/navbar/navbar(jade).jade index 5d7cb2795..e20a8fffa 100644 --- a/app/templates/client/components/navbar/navbar(jade).jade +++ b/app/templates/client/components/navbar/navbar(jade).jade @@ -31,4 +31,4 @@ div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarCtrl') span.glyphicon.glyphicon-cog li(ng-show='isLoggedIn()') - a(<% if (filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %> \ No newline at end of file + a(<% if (filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %> diff --git a/app/templates/client/components/navbar/navbar.controller(coffee).coffee b/app/templates/client/components/navbar/navbar.controller(coffee).coffee index 9dda1ae4b..98eaf2213 100644 --- a/app/templates/client/components/navbar/navbar.controller(coffee).coffee +++ b/app/templates/client/components/navbar/navbar.controller(coffee).coffee @@ -12,4 +12,4 @@ angular.module '<%= scriptAppName %>' $scope.getCurrentUser = Auth.getCurrentUser<% } %><% if(!filters.uirouter) { %> $scope.isActive = (route) -> - route is $location.path()<% } %> \ No newline at end of file + route is $location.path()<% } %> diff --git a/app/templates/client/components/socket(socketio)/socket.mock(js).js b/app/templates/client/components/socket(socketio)/socket.mock(js).js index 84a2e0c36..ba09c1d35 100644 --- a/app/templates/client/components/socket(socketio)/socket.mock(js).js +++ b/app/templates/client/components/socket(socketio)/socket.mock(js).js @@ -13,4 +13,4 @@ angular.module('socketMock', []) syncUpdates: function() {}, unsyncUpdates: function() {} }; - }); \ No newline at end of file + }); diff --git a/controller/index.js b/controller/index.js index 29f65325b..6d8897d61 100644 --- a/controller/index.js +++ b/controller/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/decorator/index.js b/decorator/index.js index b28be5c88..ae8193eb7 100644 --- a/decorator/index.js +++ b/decorator/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/directive/index.js b/directive/index.js index 298f4240e..257a4b19a 100644 --- a/directive/index.js +++ b/directive/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/factory/index.js b/factory/index.js index 584079bad..c303eb9b8 100644 --- a/factory/index.js +++ b/factory/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/filter/index.js b/filter/index.js index 8aafad6f7..d1119b27d 100644 --- a/filter/index.js +++ b/filter/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/generators/constant/index.js b/generators/constant/index.js index fd7b5c574..4524a8eed 100644 --- a/generators/constant/index.js +++ b/generators/constant/index.js @@ -11,4 +11,4 @@ util.inherits(Generator, yeoman.generators.Base); Generator.prototype.deprecated = function deprecated() { this.log(chalk.yellow('This sub-generator is deprecated. \n')); -}; \ No newline at end of file +}; diff --git a/generators/deploy/index.js b/generators/deploy/index.js index 6a3d5ec9c..7fb3452fa 100644 --- a/generators/deploy/index.js +++ b/generators/deploy/index.js @@ -12,4 +12,4 @@ util.inherits(Generator, yeoman.generators.NamedBase); Generator.prototype.deprecated = function deprecated() { this.log(chalk.yellow(chalk.bold('yo angular-fullstack:deploy') + ' is deprecated, instead use: \n') + chalk.green('yo angular-fullstack:heroku') + ' or ' + chalk.green('yo angular-fullstack:openshift')); -}; \ No newline at end of file +}; diff --git a/generators/readme.md b/generators/readme.md index 670a62a57..d56c72138 100644 --- a/generators/readme.md +++ b/generators/readme.md @@ -1 +1 @@ -This folder is for deprecated generators only. \ No newline at end of file +This folder is for deprecated generators only. diff --git a/generators/value/index.js b/generators/value/index.js index fd7b5c574..4524a8eed 100644 --- a/generators/value/index.js +++ b/generators/value/index.js @@ -11,4 +11,4 @@ util.inherits(Generator, yeoman.generators.Base); Generator.prototype.deprecated = function deprecated() { this.log(chalk.yellow('This sub-generator is deprecated. \n')); -}; \ No newline at end of file +}; diff --git a/generators/view/index.js b/generators/view/index.js index fd7b5c574..4524a8eed 100644 --- a/generators/view/index.js +++ b/generators/view/index.js @@ -11,4 +11,4 @@ util.inherits(Generator, yeoman.generators.Base); Generator.prototype.deprecated = function deprecated() { this.log(chalk.yellow('This sub-generator is deprecated. \n')); -}; \ No newline at end of file +}; diff --git a/openshift/USAGE b/openshift/USAGE index b3dd18759..a57763b36 100644 --- a/openshift/USAGE +++ b/openshift/USAGE @@ -5,4 +5,4 @@ Example: yo angular-fullstack:openshift This will create: - a dist folder and initialize an openshift app \ No newline at end of file + a dist folder and initialize an openshift app diff --git a/provider/index.js b/provider/index.js index ed40ef29d..5e3ac882e 100644 --- a/provider/index.js +++ b/provider/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/route/index.js b/route/index.js index 2a69476c5..cc8569854 100644 --- a/route/index.js +++ b/route/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/scripts/sauce_connect_setup.sh b/scripts/sauce_connect_setup.sh index 06b6e2092..4348e3662 100755 --- a/scripts/sauce_connect_setup.sh +++ b/scripts/sauce_connect_setup.sh @@ -57,4 +57,4 @@ done unset SAUCE_CONNECT_PLATFORM SAUCE_TMP_DIR SC_DIR SC_DISTRIBUTION SC_READYFILE SC_LOGFILE SC_TUNNEL_ID -popd \ No newline at end of file +popd diff --git a/service/index.js b/service/index.js index d133abdbc..9aa5f48b0 100644 --- a/service/index.js +++ b/service/index.js @@ -7,4 +7,4 @@ var Generator = yeoman.generators.Base.extend({ } }); -module.exports = Generator; \ No newline at end of file +module.exports = Generator; diff --git a/test/fixtures/.yo-rc.json b/test/fixtures/.yo-rc.json index 9ab655e54..a26821115 100644 --- a/test/fixtures/.yo-rc.json +++ b/test/fixtures/.yo-rc.json @@ -17,4 +17,4 @@ "googleAuth": true } } -} \ No newline at end of file +} diff --git a/util.js b/util.js index 7544f8c8e..4bf2170c4 100644 --- a/util.js +++ b/util.js @@ -137,4 +137,4 @@ function processDirectory (self, source, destination) { } } }); -} \ No newline at end of file +} From e7a1a462cd825d03c3b9564c1114182fef416466 Mon Sep 17 00:00:00 2001 From: Tyson Quek Date: Wed, 22 Jul 2015 10:32:28 +0800 Subject: [PATCH 157/201] refactor(client:auth): use $cookies instead $cookieStore is deprecated. See https://docs.angularjs.org/api/ngCookies/service/$cookieStore --- app/templates/client/app/app(coffee).coffee | 6 +++--- app/templates/client/app/app(js).js | 8 ++++---- .../auth(auth)/auth.service(coffee).coffee | 12 ++++++------ .../client/components/auth(auth)/auth.service(js).js | 12 ++++++------ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/templates/client/app/app(coffee).coffee b/app/templates/client/app/app(coffee).coffee index 25b572a75..b070abd8b 100644 --- a/app/templates/client/app/app(coffee).coffee +++ b/app/templates/client/app/app(coffee).coffee @@ -15,12 +15,12 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] $locationProvider.html5Mode true<% if (filters.auth) { %> $httpProvider.interceptors.push 'authInterceptor'<% } %> <% } %><% if (filters.auth) { %> -.factory 'authInterceptor', ($rootScope, $q, $cookieStore<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) -> +.factory 'authInterceptor', ($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) -> <% if (filters.uirouter) { %>state = null <% } %># Add authorization token to headers request: (config) -> config.headers = config.headers or {} - config.headers.Authorization = 'Bearer ' + $cookieStore.get 'token' if $cookieStore.get 'token' + config.headers.Authorization = 'Bearer ' + $cookies.get 'token' if $cookies.get 'token' config # Intercept 401s and redirect you to login @@ -28,7 +28,7 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] if response.status is 401 <% if (filters.ngroute) { %>$location.path '/login'<% } if (filters.uirouter) { %>(state || state = $injector.get '$state').go 'login'<% } %> # remove any stale tokens - $cookieStore.remove 'token' + $cookies.remove 'token' $q.reject response diff --git a/app/templates/client/app/app(js).js b/app/templates/client/app/app(js).js index 2ee87aafe..0b636714d 100644 --- a/app/templates/client/app/app(js).js +++ b/app/templates/client/app/app(js).js @@ -17,14 +17,14 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) $httpProvider.interceptors.push('authInterceptor');<% } %> })<% } if (filters.auth) { %> - .factory('authInterceptor', function($rootScope, $q, $cookieStore<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) { + .factory('authInterceptor', function($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>) { <% if (filters.uirouter) { %>var state; <% } %>return { // Add authorization token to headers request: function(config) { config.headers = config.headers || {}; - if ($cookieStore.get('token')) { - config.headers.Authorization = 'Bearer ' + $cookieStore.get('token'); + if ($cookies.get('token')) { + config.headers.Authorization = 'Bearer ' + $cookies.get('token'); } return config; }, @@ -34,7 +34,7 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>]) if (response.status === 401) { <% if (filters.ngroute) { %>$location.path('/login');<% } if (filters.uirouter) { %>(state || (state = $injector.get('$state'))).go('login');<% } %> // remove any stale tokens - $cookieStore.remove('token'); + $cookies.remove('token'); return $q.reject(response); } else { diff --git a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee index 1d4b29544..778c4e547 100644 --- a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee +++ b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee @@ -1,8 +1,8 @@ 'use strict' angular.module '<%= scriptAppName %>' -.factory 'Auth', ($http, User, $cookieStore, $q) -> - currentUser = if $cookieStore.get 'token' then User.get() else {} +.factory 'Auth', ($http, User, $cookies, $q) -> + currentUser = if $cookies.get 'token' then User.get() else {} ### Authenticate user and save token @@ -17,7 +17,7 @@ angular.module '<%= scriptAppName %>' password: user.password .then (res) -> - $cookieStore.put 'token', res.data.token + $cookies.put 'token', res.data.token currentUser = User.get() callback?() res.data @@ -32,7 +32,7 @@ angular.module '<%= scriptAppName %>' Delete access token and user info ### logout: -> - $cookieStore.remove 'token' + $cookies.remove 'token' currentUser = {} return @@ -47,7 +47,7 @@ angular.module '<%= scriptAppName %>' createUser: (user, callback) -> User.save user, (data) -> - $cookieStore.put 'token', data.token + $cookies.put 'token', data.token currentUser = User.get() callback? null, user @@ -144,4 +144,4 @@ angular.module '<%= scriptAppName %>' Get auth token ### getToken: -> - $cookieStore.get 'token' + $cookies.get 'token' diff --git a/app/templates/client/components/auth(auth)/auth.service(js).js b/app/templates/client/components/auth(auth)/auth.service(js).js index 5baf0e0b4..6b0c80e08 100644 --- a/app/templates/client/components/auth(auth)/auth.service(js).js +++ b/app/templates/client/components/auth(auth)/auth.service(js).js @@ -1,7 +1,7 @@ 'use strict'; angular.module('<%= scriptAppName %>') - .factory('Auth', function Auth($http, User, $cookieStore, $q) { + .factory('Auth', function Auth($http, User, $cookies, $q) { /** * Return a callback or noop function * @@ -14,7 +14,7 @@ angular.module('<%= scriptAppName %>') currentUser = {}; - if ($cookieStore.get('token')) { + if ($cookies.get('token')) { currentUser = User.get(); } @@ -33,7 +33,7 @@ angular.module('<%= scriptAppName %>') password: user.password }) .then(function(res) { - $cookieStore.put('token', res.data.token); + $cookies.put('token', res.data.token); currentUser = User.get(); safeCb(callback)(); return res.data; @@ -48,7 +48,7 @@ angular.module('<%= scriptAppName %>') * Delete access token and user info */ logout: function() { - $cookieStore.remove('token'); + $cookies.remove('token'); currentUser = {}; }, @@ -62,7 +62,7 @@ angular.module('<%= scriptAppName %>') createUser: function(user, callback) { return User.save(user, function(data) { - $cookieStore.put('token', data.token); + $cookies.put('token', data.token); currentUser = User.get(); return safeCb(callback)(null, user); }, @@ -160,7 +160,7 @@ angular.module('<%= scriptAppName %>') * @return {String} - a token string used for authenticating */ getToken: function() { - return $cookieStore.get('token'); + return $cookies.get('token'); } }; }); From 90ff36e8d5eebd53b2a615c4803c412812a11673 Mon Sep 17 00:00:00 2001 From: kingcody Date: Fri, 31 Jul 2015 05:10:28 -0400 Subject: [PATCH 158/201] fix(gen): default grunt filter This takes care of the README.md template as well as allowing other template updates related to the grunt/gulp implementation --- app/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/index.js b/app/index.js index 5c3ef0673..6c0a7fe3f 100644 --- a/app/index.js +++ b/app/index.js @@ -287,6 +287,11 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ return answers.testing === 'mocha'; } }], function (answers) { + /** + * Default to grunt until gulp support is implemented + */ + this.filters.grunt = true; + this.filters[answers.testing] = true; if (answers.testing === 'mocha') { this.filters.jasmine = false; From 1bfcc1fc05202b2abd05915c52ec5010ad960b5e Mon Sep 17 00:00:00 2001 From: Denis Ciccale Date: Sun, 2 Aug 2015 16:28:22 +0200 Subject: [PATCH 159/201] fix(app.coffee): missing preventDefault() --- app/templates/client/app/app(coffee).coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/templates/client/app/app(coffee).coffee b/app/templates/client/app/app(coffee).coffee index b070abd8b..bf97363b1 100644 --- a/app/templates/client/app/app(coffee).coffee +++ b/app/templates/client/app/app(coffee).coffee @@ -36,5 +36,6 @@ angular.module '<%= scriptAppName %>', [<%= angularModules %>] # Redirect to login if route requires auth and you're not logged in $rootScope.$on <% if (filters.ngroute) { %>'$routeChangeStart'<% } %><% if (filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> Auth.isLoggedIn (loggedIn) -> + event.preventDefault() <% if (filters.ngroute) { %>$location.path '/login'<% } %><% if (filters.uirouter) { %>$state.go 'login'<% } %> if next.authenticate and not loggedIn <% } %> From 6bfc1da235d96a1d569c9ac7cba6d765a2a51c4b Mon Sep 17 00:00:00 2001 From: Denis Ciccale Date: Sun, 2 Aug 2015 16:29:30 +0200 Subject: [PATCH 160/201] chore(auth.service): changePassword does not receive success data --- .../client/components/auth(auth)/auth.service(coffee).coffee | 4 ++-- .../client/components/auth(auth)/auth.service(js).js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee index 778c4e547..d59b1040d 100644 --- a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee +++ b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee @@ -73,8 +73,8 @@ angular.module '<%= scriptAppName %>' oldPassword: oldPassword newPassword: newPassword - , (user) -> - callback? null, user + , () -> + callback? null , (err) -> callback? err diff --git a/app/templates/client/components/auth(auth)/auth.service(js).js b/app/templates/client/components/auth(auth)/auth.service(js).js index 6b0c80e08..d7f787a94 100644 --- a/app/templates/client/components/auth(auth)/auth.service(js).js +++ b/app/templates/client/components/auth(auth)/auth.service(js).js @@ -84,8 +84,8 @@ angular.module('<%= scriptAppName %>') return User.changePassword({ id: currentUser._id }, { oldPassword: oldPassword, newPassword: newPassword - }, function(user) { - return safeCb(callback)(null, user); + }, function() { + return safeCb(callback)(null); }, function(err) { return safeCb(callback)(err); }).$promise; From 7ecf75180fc89de2ad441adf651dcfcd95ad85ae Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 4 Aug 2015 00:05:49 -0400 Subject: [PATCH 161/201] chore(dependencies): update grunt-wiredep to `^2.0.0` --- app/templates/_package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 194af868e..31b5aa5d5 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -36,7 +36,7 @@ "devDependencies": { "autoprefixer-core": "^5.2.1", "grunt": "~0.4.4", - "grunt-wiredep": "~1.8.0", + "grunt-wiredep": "^2.0.0", "grunt-concurrent": "~0.5.0", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-concat": "~0.4.0", From f31e9968dc1aca0b0254d411b19fdc5bd19a6b7f Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 4 Aug 2015 00:07:14 -0400 Subject: [PATCH 162/201] feat(app): use wiredep to inject bower deps into karma.conf.js --- app/templates/Gruntfile.js | 31 +++++++++++++++++++++++-------- app/templates/karma.conf.js | 14 +++----------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index ce5275629..e635727f9 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -72,7 +72,7 @@ module.exports = function (grunt) { }, jsTest: { files: ['<%%= yeoman.client %>/{app,components}/**/*.{spec,mock}.js'], - tasks: ['newer:jshint:all', 'karma'] + tasks: ['newer:jshint:all', 'wiredep:test', 'karma'] },<% if (filters.stylus) { %> injectStylus: { files: ['<%%= yeoman.client %>/{app,components}/**/*.styl'], @@ -240,12 +240,26 @@ module.exports = function (grunt) { } }, - // Automatically inject Bower components into the app + // Automatically inject Bower components into the app and karma.conf.js wiredep: { - target: { + options: { + exclude: [ + /angular-scenario/, + /bootstrap-sass-official/, + /bootstrap.js/, + '/json3/', + '/es5-shim/'<% if(!filters.css) { %>, + /bootstrap.css/, + /font-awesome.css/<% } %> + ] + }, + client: { src: '<%%= yeoman.client %>/index.html', ignorePath: '<%%= yeoman.client %>/', - exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/'<% if(!filters.css) { %>, /bootstrap.css/, /font-awesome.css/ <% } %>] + }, + test: { + src: './karma.conf.js', + devDependencies: true } }, @@ -773,7 +787,7 @@ module.exports = function (grunt) { 'injector:sass',<% } %> 'concurrent:server', 'injector', - 'wiredep', + 'wiredep:client', 'postcss', 'concurrent:debug' ]); @@ -787,7 +801,7 @@ module.exports = function (grunt) { 'injector:sass',<% } %> 'concurrent:server', 'injector', - 'wiredep', + 'wiredep:client', 'postcss', 'express:dev', 'wait', @@ -821,6 +835,7 @@ module.exports = function (grunt) { 'concurrent:test', 'injector', 'postcss', + 'wiredep:test', 'karma' ]); } @@ -847,7 +862,7 @@ module.exports = function (grunt) { 'injector:sass',<% } %> 'concurrent:test', 'injector', - 'wiredep', + 'wiredep:client', 'postcss', 'express:dev', 'protractor' @@ -903,7 +918,7 @@ module.exports = function (grunt) { 'injector:sass',<% } %> 'concurrent:dist', 'injector', - 'wiredep', + 'wiredep:client', 'useminPrepare', 'postcss', 'ngtemplates', diff --git a/app/templates/karma.conf.js b/app/templates/karma.conf.js index b18bc8da3..5b45e4f86 100644 --- a/app/templates/karma.conf.js +++ b/app/templates/karma.conf.js @@ -12,17 +12,9 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ - 'client/bower_components/jquery/dist/jquery.js', - 'client/bower_components/angular/angular.js', - 'client/bower_components/angular-mocks/angular-mocks.js', - 'client/bower_components/angular-resource/angular-resource.js', - 'client/bower_components/angular-cookies/angular-cookies.js', - 'client/bower_components/angular-sanitize/angular-sanitize.js', - 'client/bower_components/angular-route/angular-route.js',<% if (filters.uibootstrap) { %> - 'client/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',<% } %> - 'client/bower_components/lodash/dist/lodash.compat.js',<% if (filters.socketio) { %> - 'client/bower_components/angular-socket-io/socket.js',<% } %><% if (filters.uirouter) { %> - 'client/bower_components/angular-ui-router/release/angular-ui-router.js',<% } %> + // bower:js + // endbower<% if (filters.socketio) { %> + 'node_modules/socket.io-client/socket.io.js',<% } %> 'client/app/app.js', 'client/app/app.coffee', 'client/app/**/*.js', From e04185a7227ad018f620aa1e32d813b555d1dc76 Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 4 Aug 2015 03:45:09 -0400 Subject: [PATCH 163/201] fix(app): auth.login waits for user resource to resolve --- .../auth(auth)/auth.service(coffee).coffee | 11 +++++++---- .../client/components/auth(auth)/auth.service(js).js | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee index 778c4e547..3b1ab4d0c 100644 --- a/app/templates/client/components/auth(auth)/auth.service(coffee).coffee +++ b/app/templates/client/components/auth(auth)/auth.service(coffee).coffee @@ -8,7 +8,7 @@ angular.module '<%= scriptAppName %>' Authenticate user and save token @param {Object} user - login info - @param {Function} callback - optional, function(error) + @param {Function} callback - optional, function(error, user) @return {Promise} ### login: (user, callback) -> @@ -19,10 +19,13 @@ angular.module '<%= scriptAppName %>' .then (res) -> $cookies.put 'token', res.data.token currentUser = User.get() - callback?() - res.data + currentUser.$promise + + .then (user) -> + callback? null, user + user - , (err) => + .catch (err) => @logout() callback? err.data $q.reject err.data diff --git a/app/templates/client/components/auth(auth)/auth.service(js).js b/app/templates/client/components/auth(auth)/auth.service(js).js index 6b0c80e08..32a4eabf3 100644 --- a/app/templates/client/components/auth(auth)/auth.service(js).js +++ b/app/templates/client/components/auth(auth)/auth.service(js).js @@ -24,7 +24,7 @@ angular.module('<%= scriptAppName %>') * Authenticate user and save token * * @param {Object} user - login info - * @param {Function} callback - optional, function(error) + * @param {Function} callback - optional, function(error, user) * @return {Promise} */ login: function(user, callback) { @@ -35,9 +35,13 @@ angular.module('<%= scriptAppName %>') .then(function(res) { $cookies.put('token', res.data.token); currentUser = User.get(); - safeCb(callback)(); - return res.data; - }, function(err) { + return currentUser.$promise; + }) + .then(function(user) { + safeCb(callback)(null, user); + return user; + }) + .catch(function(err) { this.logout(); safeCb(callback)(err.data); return $q.reject(err.data); From 8247085844f3b73feb7db3cc785a4bc48b3b2e6c Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 5 Aug 2015 00:57:24 -0400 Subject: [PATCH 164/201] feat(grunt): add watch to bower.json --- app/templates/Gruntfile.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index e635727f9..361c49f1a 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -133,7 +133,11 @@ module.exports = function (grunt) { livereload: true, nospawn: true //Without this option specified express won't be reloaded } - } + }, + bower: { + files: ['bower.json'], + tasks: ['wiredep'] + }, }, // Make sure code styles are up to par and there are no obvious mistakes From 2526ca5c90edced22eac4980bef5b9b6a5f1b156 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 5 Aug 2015 13:28:26 -0400 Subject: [PATCH 165/201] feat(server:auth): add role to signToken add role as second parameter, and attach to jwt closes #382 --- app/templates/server/auth(auth)/auth.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/server/auth(auth)/auth.service.js b/app/templates/server/auth(auth)/auth.service.js index 86f781f84..faa2684cf 100644 --- a/app/templates/server/auth(auth)/auth.service.js +++ b/app/templates/server/auth(auth)/auth.service.js @@ -71,8 +71,8 @@ function hasRole(roleRequired) { /** * Returns a jwt token signed by the app secret */ -function signToken(id) { - return jwt.sign({ _id: id }, config.secrets.session, { +function signToken(id, role) { + return jwt.sign({ _id: id, role: role }, config.secrets.session, { expiresInMinutes: 60 * 5 }); } From 76325bdc24b6c0a613981a4f95830341c09bf490 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Fri, 17 Jul 2015 18:51:33 -0400 Subject: [PATCH 166/201] fix(gen:css): ensure scss/less/stylus files have proper relative paths --- app/templates/Gruntfile.js | 6 +++--- app/templates/client/app/app(less).less | 8 ++++---- app/templates/client/app/app(sass).scss | 8 ++++---- app/templates/client/app/app(stylus).styl | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 361c49f1a..fde0acb0a 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -689,7 +689,7 @@ module.exports = function (grunt) { options: { transform: function(filePath) { filePath = filePath.replace('/client/app/', ''); - filePath = filePath.replace('/client/components/', ''); + filePath = filePath.replace('/client/components/', '../components/'); return '@import \'' + filePath + '\';'; }, starttag: '// injector', @@ -708,7 +708,7 @@ module.exports = function (grunt) { options: { transform: function(filePath) { filePath = filePath.replace('/client/app/', ''); - filePath = filePath.replace('/client/components/', ''); + filePath = filePath.replace('/client/components/', '../components/'); return '@import \'' + filePath + '\';'; }, starttag: '// injector', @@ -727,7 +727,7 @@ module.exports = function (grunt) { options: { transform: function(filePath) { filePath = filePath.replace('/client/app/', ''); - filePath = filePath.replace('/client/components/', ''); + filePath = filePath.replace('/client/components/', '../components/'); return '@import \'' + filePath + '\';'; }, starttag: '// injector', diff --git a/app/templates/client/app/app(less).less b/app/templates/client/app/app(less).less index 460b56bdb..cbfffbe88 100644 --- a/app/templates/client/app/app(less).less +++ b/app/templates/client/app/app(less).less @@ -1,8 +1,8 @@ -<% if (filters.bootstrap) { %>@import 'bootstrap/less/bootstrap.less';<% } %> -@import 'font-awesome/less/font-awesome.less'; +<% if (filters.bootstrap) { %>@import '../bower_components/bootstrap/less/bootstrap.less';<% } %> +@import '../bower_components/font-awesome/less/font-awesome.less'; -<% if (filters.bootstrap) { %>@icon-font-path: '/bower_components/bootstrap/fonts/';<% } %> -@fa-font-path: '/bower_components/font-awesome/fonts'; +<% if (filters.bootstrap) { %>@icon-font-path: '../bower_components/bootstrap/fonts/';<% } %> +@fa-font-path: '../bower_components/font-awesome/fonts'; /** * App-wide Styles diff --git a/app/templates/client/app/app(sass).scss b/app/templates/client/app/app(sass).scss index 30befa636..889878aee 100644 --- a/app/templates/client/app/app(sass).scss +++ b/app/templates/client/app/app(sass).scss @@ -1,8 +1,8 @@ -<% if (filters.bootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> -$fa-font-path: "/bower_components/font-awesome/fonts"; +<% if (filters.bootstrap) { %>$icon-font-path: "../bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> +$fa-font-path: "../bower_components/font-awesome/fonts"; <% if (filters.bootstrap) { %> -@import 'bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> -@import 'font-awesome/scss/font-awesome'; +@import '../bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> +@import '../bower_components/font-awesome/scss/font-awesome'; /** * App-wide Styles diff --git a/app/templates/client/app/app(stylus).styl b/app/templates/client/app/app(stylus).styl index 9eab53889..d25cdfc59 100644 --- a/app/templates/client/app/app(stylus).styl +++ b/app/templates/client/app/app(stylus).styl @@ -1,5 +1,5 @@ -@import "font-awesome/css/font-awesome.css" -<% if (filters.bootstrap) { %>@import "bootstrap/dist/css/bootstrap.css" +@import "../bower_components/font-awesome/css/font-awesome.css" +<% if (filters.bootstrap) { %>@import "../bower_components/bootstrap/dist/css/bootstrap.css" // // Bootstrap Fonts From 799e94b9a12e119cc29bc68a864aab833f4e28ba Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 5 Aug 2015 12:59:29 -0400 Subject: [PATCH 167/201] refactor(grunt): remove no longer needed paths remove Sass/Stylus/Less include paths --- app/templates/Gruntfile.js | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index fde0acb0a..d562f6b3b 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -612,11 +612,6 @@ module.exports = function (grunt) { stylus: { server: { options: { - paths: [ - '<%%= yeoman.client %>/bower_components', - '<%%= yeoman.client %>/app', - '<%%= yeoman.client %>/components' - ], "include css": true }, files: { @@ -629,11 +624,6 @@ module.exports = function (grunt) { sass: { server: { options: { - loadPath: [ - '<%%= yeoman.client %>/bower_components', - '<%%= yeoman.client %>/app', - '<%%= yeoman.client %>/components' - ], compass: false }, files: { @@ -644,18 +634,11 @@ module.exports = function (grunt) { // Compiles Less to CSS less: { - options: { - paths: [ - '<%%= yeoman.client %>/bower_components', - '<%%= yeoman.client %>/app', - '<%%= yeoman.client %>/components' - ] - }, server: { files: { '.tmp/app/app.css' : '<%%= yeoman.client %>/app/app.less' } - }, + } },<% } %> injector: { From 9c3e7eed5d66d5d3a136d7d72dd7f0f8a32b65d6 Mon Sep 17 00:00:00 2001 From: kingcody Date: Thu, 6 Aug 2015 02:42:18 -0400 Subject: [PATCH 168/201] fix(grunt): `watch.jade` only watches jade files --- app/templates/Gruntfile.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 361c49f1a..420f6dd21 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -99,10 +99,7 @@ module.exports = function (grunt) { tasks: ['less', 'postcss'] },<% } if (filters.jade) { %> jade: { - files: [ - '<%%= yeoman.client %>/{app,components}/*', - '<%%= yeoman.client %>/{app,components}/**/*.jade' - ], + files: ['<%%= yeoman.client %>/{app,components}/**/*.jade'], tasks: ['jade'] },<% } if (filters.coffee) { %> coffee: { From 1dfc856d21f94808954c0dd5cae97741a216e62f Mon Sep 17 00:00:00 2001 From: kingcody Date: Fri, 24 Jul 2015 03:17:00 -0400 Subject: [PATCH 169/201] chore(dependencies): update yeoman-generator to ~0.8.10 --- app/index.js | 9 +++++---- endpoint/index.js | 16 ++++++++-------- package.json | 4 ++-- test/test-file-creation.js | 30 +++++++++++++++--------------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/app/index.js b/app/index.js index 6c0a7fe3f..4ae1ad871 100644 --- a/app/index.js +++ b/app/index.js @@ -37,7 +37,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, info: function () { - this.log(this.yeoman); + this.log(this.welcome); this.log('Out of the box I create an AngularJS app with an Express server.\n'); }, @@ -60,14 +60,15 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }); // NOTE: temp(?) fix for #403 - if(typeof this.filters.oauth==='undefined') { + if(typeof this.filters.oauth === 'undefined') { var strategies = Object.keys(this.filters).filter(function(key) { - return key.match(/Auth$/) && key; - }); + return key.match(/Auth$/) && this.filters[key]; + }.bind(this)); if(strategies.length) this.filters.oauth = true; } + this.config.set('filters', this.filters); this.config.forceSave(); cb(); diff --git a/endpoint/index.js b/endpoint/index.js index 8fa1f498d..22e8e8950 100644 --- a/endpoint/index.js +++ b/endpoint/index.js @@ -11,7 +11,7 @@ var Generator = module.exports = function Generator() { util.inherits(Generator, ScriptBase); -Generator.prototype.askFor = function askFor() { +Generator.prototype.prompting = function askFor() { var done = this.async(); var name = this.name; @@ -66,7 +66,13 @@ Generator.prototype.askFor = function askFor() { }.bind(this)); }; -Generator.prototype.registerEndpoint = function registerEndpoint() { +Generator.prototype.writing = function createFiles() { + var dest = this.config.get('endpointDirectory') || 'server/api/' + this.name; + this.sourceRoot(path.join(__dirname, './templates')); + ngUtil.processDirectory(this, '.', dest); +}; + +Generator.prototype.end = function registerEndpoint() { if(this.config.get('insertRoutes')) { var routeConfig = { file: this.config.get('registerRoutesFile'), @@ -110,9 +116,3 @@ Generator.prototype.registerEndpoint = function registerEndpoint() { } } }; - -Generator.prototype.createFiles = function createFiles() { - var dest = this.config.get('endpointDirectory') || 'server/api/' + this.name; - this.sourceRoot(path.join(__dirname, './templates')); - ngUtil.processDirectory(this, '.', dest); -}; diff --git a/package.json b/package.json index f66b72cb0..c1a50c792 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ "test": "grunt test" }, "dependencies": { - "yeoman-generator": "~0.17.0", "chalk": "~0.4.0", - "generator-ng-component": "~0.0.4" + "generator-ng-component": "~0.0.4", + "yeoman-generator": "~0.18.10" }, "devDependencies": { "chai": "^1.9.1", diff --git a/test/test-file-creation.js b/test/test-file-creation.js index bec4ab17d..ce8635c0b 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -26,13 +26,13 @@ describe('angular-fullstack generator', function () { }, dependenciesInstalled = false; function generatorTest(generatorType, name, mockPrompt, callback) { - gen.run({}, function () { + gen.run(function () { var afGenerator; var deps = [path.join('../..', generatorType)]; afGenerator = helpers.createGenerator('angular-fullstack:' + generatorType, deps, [name]); helpers.mockPrompt(afGenerator, mockPrompt); - afGenerator.run([], function () { + afGenerator.run(function () { callback(); }); }); @@ -107,7 +107,7 @@ describe('angular-fullstack generator', function () { if (endpoint) { generatorTest('endpoint', endpoint, {}, execFn); } else { - gen.run({}, execFn); + gen.run(execFn); } } @@ -430,7 +430,7 @@ describe('angular-fullstack generator', function () { helpers.mockPrompt(gen, { skipConfig: true }); - gen.run({}, function () { + gen.run(function () { helpers.assertFile([ 'client/app/main/main.less', 'client/app/main/main.coffee', @@ -454,7 +454,7 @@ describe('angular-fullstack generator', function () { helpers.mockPrompt(gen, { skipConfig: true }); - gen.run({}, function () { + gen.run(function () { var yoConfig = require(__dirname + '/temp/.yo-rc.json'); expect(yoConfig['generator-angular-fullstack'].filters.oauth).to.be.true; done(); @@ -462,14 +462,14 @@ describe('angular-fullstack generator', function () { }); it('should generate expected files', function (done) { - gen.run({}, function () { + gen.run(function () { helpers.assertFile(genFiles(defaultOptions)); done(); }); }); it('should not generate unexpected files', function (done) { - gen.run({}, function () { + gen.run(function () { assertOnlyFiles(genFiles(defaultOptions), done); }); }); @@ -533,14 +533,14 @@ describe('angular-fullstack generator', function () { }); it('should generate expected files', function (done) { - gen.run({}, function () { + gen.run(function () { helpers.assertFile(genFiles(testOptions)); done(); }); }); it('should not generate unexpected files', function (done) { - gen.run({}, function () { + gen.run(function () { assertOnlyFiles(genFiles(testOptions), done); }); }); @@ -605,14 +605,14 @@ describe('angular-fullstack generator', function () { }); it('should generate expected files', function (done) { - gen.run({}, function () { + gen.run(function () { helpers.assertFile(genFiles(testOptions)); done(); }); }); it('should not generate unexpected files', function (done) { - gen.run({}, function () { + gen.run(function () { assertOnlyFiles(genFiles(testOptions), done); }); }); @@ -679,14 +679,14 @@ describe('angular-fullstack generator', function () { }); it('should generate expected files', function (done) { - gen.run({}, function () { + gen.run(function () { helpers.assertFile(genFiles(testOptions)); done(); }); }); it('should not generate unexpected files', function (done) { - gen.run({}, function () { + gen.run(function () { assertOnlyFiles(genFiles(testOptions), done); }); }); @@ -740,14 +740,14 @@ describe('angular-fullstack generator', function () { }); it('should generate expected files', function (done) { - gen.run({}, function () { + gen.run(function () { helpers.assertFile(genFiles(testOptions)); done(); }); }); it('should not generate unexpected files', function (done) { - gen.run({}, function () { + gen.run(function () { assertOnlyFiles(genFiles(testOptions), done); }); }); From 533bbd7991e4066e724f7c4807020eeef2739384 Mon Sep 17 00:00:00 2001 From: kingcody Date: Thu, 6 Aug 2015 02:58:35 -0400 Subject: [PATCH 170/201] chore(dependencies): update generator-ng-component to ~0.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c1a50c792..a062a68a9 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "dependencies": { "chalk": "~0.4.0", - "generator-ng-component": "~0.0.4", + "generator-ng-component": "~0.1.0", "yeoman-generator": "~0.18.10" }, "devDependencies": { From d7fc0a80abda86c0cdca0de9e7748bb81e1b92ff Mon Sep 17 00:00:00 2001 From: Denis Ciccale Date: Fri, 7 Aug 2015 10:16:42 +0200 Subject: [PATCH 171/201] chore(user): change status code 204 for empty response body --- app/templates/server/api/user(auth)/user.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/server/api/user(auth)/user.controller.js b/app/templates/server/api/user(auth)/user.controller.js index d074c666b..f1c2498fb 100644 --- a/app/templates/server/api/user(auth)/user.controller.js +++ b/app/templates/server/api/user(auth)/user.controller.js @@ -128,7 +128,7 @@ exports.changePassword = function(req, res, next) { <% if (filters.mongooseModels) { %>return user.saveAsync()<% } if (filters.sequelizeModels) { %>return user.save()<% } %> .then(function() { - res.status(200).end(); + res.status(204).end(); }) .catch(validationError(res)); } else { From 63782b360e3c7f12bce073de0a4bfe8817e03dbb Mon Sep 17 00:00:00 2001 From: Dan Rocha Date: Sat, 8 Aug 2015 00:52:31 -0500 Subject: [PATCH 172/201] feat(package): upgrade jshint packages --- app/templates/_package.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 31b5aa5d5..c9b1533be 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -44,7 +44,7 @@ "grunt-contrib-cssmin": "~0.9.0", "grunt-contrib-htmlmin": "~0.2.0", "grunt-contrib-imagemin": "~0.7.1", - "grunt-contrib-jshint": "~0.10.0", + "grunt-contrib-jshint": "~0.11.2", "grunt-contrib-uglify": "~0.4.0", "grunt-contrib-watch": "~0.6.1",<% if (filters.coffee) { %> "grunt-contrib-coffee": "^0.10.1",<% } %><% if (filters.jade) { %> @@ -76,7 +76,7 @@ "grunt-postcss": "^0.5.5", "grunt-open": "~0.2.3", "open": "~0.0.4", - "jshint-stylish": "~0.1.5", + "jshint-stylish": "~2.0.1", "connect-livereload": "^0.5.3", "mocha": "^2.2.5", "grunt-mocha-test": "~0.12.7", diff --git a/package.json b/package.json index f66b72cb0..e576c2ca9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "grunt": "~0.4.1", "grunt-build-control": "DaftMonk/grunt-build-control", "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-jshint": "^0.10.0", + "grunt-contrib-jshint": "^0.11.2", "grunt-conventional-changelog": "~1.0.0", "grunt-env": "^0.4.1", "grunt-mocha-test": "^0.11.0", From ea2a7331cfdb3fd7d0c0ee0f8f6a7ba021dd7647 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 11 Aug 2015 10:56:00 -0400 Subject: [PATCH 173/201] fix(server:errors): fix res.render syntax --- app/templates/server/components/errors/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/server/components/errors/index.js b/app/templates/server/components/errors/index.js index 52dba3749..ba71c73ba 100644 --- a/app/templates/server/components/errors/index.js +++ b/app/templates/server/components/errors/index.js @@ -12,11 +12,11 @@ module.exports[404] = function pageNotFound(req, res) { }; res.status(result.status); - res.render(viewFilePath, function(err) { + res.render(viewFilePath, {}, function(err, html) { if (err) { return res.json(result, result.status); } - res.render(viewFilePath); + res.send(html); }); }; From 2617ab28a772af21cbb21597cb36bb47a7ea6a00 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 11 Aug 2015 11:08:32 -0400 Subject: [PATCH 174/201] feat(client:main): use times symbol instead of 'x' in jade template --- app/templates/client/app/main/main(jade).jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/client/app/main/main(jade).jade b/app/templates/client/app/main/main(jade).jade index e791e96ab..3277e7b05 100644 --- a/app/templates/client/app/main/main(jade).jade +++ b/app/templates/client/app/main/main(jade).jade @@ -14,7 +14,7 @@ header#banner.hero-unit li a(href='#', tooltip='{{thing.info}}') | {{thing.name}}<% if (filters.socketio) { %> - button.close(type='button', ng-click='deleteThing(thing)') ×<% } %><% if (filters.socketio) { %> + button.close(type='button', ng-click='deleteThing(thing)') ×<% } %><% if (filters.socketio) { %> form.thing-form label Syncs in realtime across clients From 6f598c95843616009c48aabb7c8198977b403369 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 11 Aug 2015 15:50:10 -0400 Subject: [PATCH 175/201] fix(): fix missed merge conflicts --- app/index.js | 55 +++++++++++++--------------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/app/index.js b/app/index.js index cc355b3bd..f34880dbd 100644 --- a/app/index.js +++ b/app/index.js @@ -152,7 +152,8 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ return answers.bootstrap; } }], function (answers) { - + this.filters.grunt = answers.buildtool === 'grunt' || answers.buildtool === 'grunt_and_gulp'; + this.filters.gulp = answers.buildtool === 'gulp' || answers.buildtool === 'grunt_and_gulp'; this.filters.babel = !!answers.babel; if(this.filters.babel){ this.filters.js = true; } this.filters[answers.script] = true; @@ -240,18 +241,6 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, default: true }], function (answers) { -<<<<<<< HEAD - this.filters.grunt = answers.buildtool === 'grunt' || answers.buildtool === 'grunt_and_gulp'; - this.filters.gulp = answers.buildtool === 'gulp' || answers.buildtool === 'grunt_and_gulp'; - this.filters.babel = !!answers.babel; - if(this.filters.babel){ this.filters.js = false; } - this.filters[answers.script] = true; - this.filters[answers.markup] = true; - this.filters[answers.stylesheet] = true; - this.filters[answers.router] = true; - this.filters.bootstrap = !!answers.bootstrap; - this.filters.uibootstrap = !!answers.uibootstrap; -======= if(answers.socketio) this.filters.socketio = true; if(answers.auth) this.filters.auth = true; if(answers.odms && answers.odms.length > 0) { @@ -276,7 +265,6 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }.bind(this)); } ->>>>>>> e6a3fe91009d434d0fe1946f0e4f66d2ea5612eb cb(); }.bind(this)); }, @@ -399,6 +387,18 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, ngModules: function() { + this.filters = this._.defaults(this.config.get('filters'), { + bootstrap: true, + uibootstrap: true + }); + + this.scriptExt = this.filters.coffee ? 'coffee' : 'js'; + this.styleExt = this.filters.less ? 'less' : + this.filters.sass ? 'scss' : + this.filters.stylus ? 'styl' : + 'css'; + this.templateExt = this.filters.jade ? 'jade' : 'html'; + var angModules = [ "'ngCookies'", "'ngResource'", @@ -414,32 +414,6 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, -<<<<<<< HEAD - ngModules: function() { - this.filters = this._.defaults(this.config.get('filters'), { - bootstrap: true, - uibootstrap: true - }); - - this.scriptExt = this.filters.coffee ? 'coffee' : 'js'; - this.styleExt = this.filters.less ? 'less' : - this.filters.sass ? 'scss' : - this.filters.stylus ? 'styl' : - 'css'; - this.templateExt = this.filters.jade ? 'jade' : 'html'; - - var angModules = [ - "'ngCookies'", - "'ngResource'", - "'ngSanitize'" - ]; - if(this.filters.ngroute) angModules.push("'ngRoute'"); - if(this.filters.socketio) angModules.push("'btford.socket-io'"); - if(this.filters.uirouter) angModules.push("'ui.router'"); - if(this.filters.uibootstrap) angModules.push("'ui.bootstrap'"); - - this.angularModules = "\n " + angModules.join(",\n ") +"\n"; -======= default: {}, writing: { @@ -457,7 +431,6 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ genUtils.processDirectory(this, '.', 'server/api/' + name); } ->>>>>>> e6a3fe91009d434d0fe1946f0e4f66d2ea5612eb }, install: { From bb394eeff9deb119b40b1c75cabd4c15d8931506 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 11 Aug 2015 16:12:29 -0400 Subject: [PATCH 176/201] feat(gen): move babel choice to script list --- app/index.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/app/index.js b/app/index.js index 4ae1ad871..e25388d7b 100644 --- a/app/index.js +++ b/app/index.js @@ -92,21 +92,13 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ type: 'list', name: 'script', message: 'What would you like to write scripts with?', - choices: [ 'JavaScript', 'CoffeeScript'], + choices: [ 'JavaScript', 'JavaScript + Babel', 'CoffeeScript'], filter: function( val ) { - var filterMap = { + return { 'JavaScript': 'js', + 'JavaScript + Babel': 'babel', 'CoffeeScript': 'coffee' - }; - - return filterMap[val]; - } - }, { - type: 'confirm', - name: 'babel', - message: 'Would you like to use Javascript ES6 in your client by preprocessing it with Babel?', - when: function (answers) { - return answers.script === 'js'; + }[val]; } }, { type: 'list', @@ -141,8 +133,8 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ } }], function (answers) { - this.filters.babel = !!answers.babel; - if(this.filters.babel){ this.filters.js = true; } + // also set 'js' to true if using babel + if(answers.script === 'babel') { this.filters.js = true; } this.filters[answers.script] = true; this.filters[answers.markup] = true; this.filters[answers.stylesheet] = true; From fb915b29d07044b09f5014b317b2303b94f47252 Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 28 Jul 2015 17:59:38 -0400 Subject: [PATCH 177/201] fix(gen): `endpointDirectory` is now a full option/config --- app/index.js | 1 + endpoint/index.js | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/index.js b/app/index.js index 4ae1ad871..f31a71fa7 100644 --- a/app/index.js +++ b/app/index.js @@ -316,6 +316,7 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ saveSettings: function() { if(this.skipConfig) return; + this.config.set('endpointDirectory', 'server/api/'); this.config.set('insertRoutes', true); this.config.set('registerRoutesFile', 'server/routes.js'); this.config.set('routesNeedle', '// Insert routes below'); diff --git a/endpoint/index.js b/endpoint/index.js index 22e8e8950..01d4486df 100644 --- a/endpoint/index.js +++ b/endpoint/index.js @@ -7,6 +7,11 @@ var ScriptBase = require('../script-base.js'); var Generator = module.exports = function Generator() { ScriptBase.apply(this, arguments); + + this.option('endpointDirectory', { + desc: 'Parent directory for enpoints', + type: String + }); }; util.inherits(Generator, ScriptBase); @@ -66,10 +71,14 @@ Generator.prototype.prompting = function askFor() { }.bind(this)); }; +Generator.prototype.configuring = function config() { + this.routeDest = path.join(this.options.endpointDirectory || + this.config.get('endpointDirectory') || 'server/api/', this.name); +}; + Generator.prototype.writing = function createFiles() { - var dest = this.config.get('endpointDirectory') || 'server/api/' + this.name; this.sourceRoot(path.join(__dirname, './templates')); - ngUtil.processDirectory(this, '.', dest); + ngUtil.processDirectory(this, '.', this.routeDest); }; Generator.prototype.end = function registerEndpoint() { From 3fcd8e909c29ee4903a083ef6bce83b9fa1b93dc Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 28 Jul 2015 18:03:53 -0400 Subject: [PATCH 178/201] feat(gen): add `relativeRequire` and other template helpers --- script-base.js | 15 +++++++++++++-- util.js | 25 ++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/script-base.js b/script-base.js index 5d6c7dd2e..d88cd988c 100644 --- a/script-base.js +++ b/script-base.js @@ -15,8 +15,13 @@ var Generator = module.exports = function Generator() { this.appname = this._.slugify(this._.humanize(this.appname)); this.scriptAppName = this._.camelize(this.appname) + angularUtils.appName(this); - this.cameledName = this._.camelize(this.name); - this.classedName = this._.classify(this.name); + var name = this.name.replace(/\//g, '-'); + + this.cameledName = this._.camelize(name); + this.classedName = this._.classify(name); + + this.basename = path.basename(this.name); + this.dirname = (this.name.indexOf('/') >= 0) ? path.dirname(this.name) : this.name; // dynamic assertion statement this.does = this.is = function(foo) { @@ -27,6 +32,12 @@ var Generator = module.exports = function Generator() { } }.bind(this); + // dynamic relative require path + this.relativeRequire = function(to, fr) { + fr = fr || this.filePath; + return angularUtils.relativeRequire(this, to, fr); + }.bind(this); + this.filters = this.config.get('filters'); this.sourceRoot(path.join(__dirname, '/templates')); }; diff --git a/util.js b/util.js index 4bf2170c4..6657cfc9f 100644 --- a/util.js +++ b/util.js @@ -6,7 +6,8 @@ module.exports = { rewrite: rewrite, rewriteFile: rewriteFile, appName: appName, - processDirectory: processDirectory + processDirectory: processDirectory, + relativeRequire: relativeRequire }; function rewriteFile (args) { @@ -74,6 +75,23 @@ function appName (self) { return suffix ? self._.classify(suffix) : ''; } +function destinationPath (self, filepath) { + filepath = path.normalize(filepath); + if (!path.isAbsolute(filepath)) { + filepath = path.join(self.destinationRoot(), filepath); + } + + return filepath; +} + +function relativeRequire (self, to, fr) { + fr = destinationPath(self, fr); + to = destinationPath(self, to); + return path.relative(path.dirname(fr), to) + .replace(/^(?!\.\.)(.*)/, './$1') + .replace(/[\/\\]index\.js$/, ''); +} + function filterFile (template) { // Find matches for parans var filterMatches = template.match(/\(([^)]+)\)/g); @@ -109,6 +127,9 @@ function processDirectory (self, source, destination) { files.forEach(function(f) { var filteredFile = filterFile(f); + if(self.basename) { + filteredFile.name = filteredFile.name.replace('basename', self.basename); + } if(self.name) { filteredFile.name = filteredFile.name.replace('name', self.name); } @@ -133,7 +154,9 @@ function processDirectory (self, source, destination) { if(copy) { self.copy(src, dest); } else { + self.filePath = dest; self.template(src, dest); + delete self.filePath; } } }); From 5227ef033fa80f51c7a764c99d99780d4bad958a Mon Sep 17 00:00:00 2001 From: kingcody Date: Tue, 28 Jul 2015 18:16:15 -0400 Subject: [PATCH 179/201] fix(gen): endpoint accepts path as name --- app/index.js | 18 ++- endpoint/index.js | 119 +++++++++++------- ...e.controller.js => basename.controller.js} | 14 +-- ...(models).js => basename.events(models).js} | 4 +- ...integration.js => basename.integration.js} | 20 +-- ...).js => basename.model(mongooseModels).js} | 0 ....js => basename.model(sequelizeModels).js} | 0 ...ketio).js => basename.socket(socketio).js} | 4 +- endpoint/templates/index.js | 2 +- endpoint/templates/index.spec.js | 36 +++--- 10 files changed, 124 insertions(+), 93 deletions(-) rename endpoint/templates/{name.controller.js => basename.controller.js} (89%) rename endpoint/templates/{name.events(models).js => basename.events(models).js} (84%) rename endpoint/templates/{name.integration.js => basename.integration.js} (84%) rename endpoint/templates/{name.model(mongooseModels).js => basename.model(mongooseModels).js} (100%) rename endpoint/templates/{name.model(sequelizeModels).js => basename.model(sequelizeModels).js} (100%) rename endpoint/templates/{name.socket(socketio).js => basename.socket(socketio).js} (82%) diff --git a/app/index.js b/app/index.js index f31a71fa7..99f1e3995 100644 --- a/app/index.js +++ b/app/index.js @@ -400,11 +400,19 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ }, generateEndpoint: function() { - var name = this.name = this.cameledName = 'thing'; - this.classedName = name.charAt(0).toUpperCase() + name.slice(1); - this.route = '/api/' + name + 's'; - this.sourceRoot(path.join(__dirname, '..', 'endpoint', 'templates')); - genUtils.processDirectory(this, '.', 'server/api/' + name); + var models; + if (this.filters.mongooseModels) { + models = 'mongoose'; + } else if (this.filters.sequelizeModels) { + models = 'sequelize'; + } + this.composeWith('angular-fullstack:endpoint', { + options: { + route: '/api/things', + models: models + }, + args: ['thing'] + }); } }, diff --git a/endpoint/index.js b/endpoint/index.js index 01d4486df..cbb8d5aeb 100644 --- a/endpoint/index.js +++ b/endpoint/index.js @@ -8,6 +8,16 @@ var ScriptBase = require('../script-base.js'); var Generator = module.exports = function Generator() { ScriptBase.apply(this, arguments); + this.option('route', { + desc: 'URL for the endpoint', + type: String + }); + + this.option('models', { + desc: 'Specify which model(s) to use', + type: String + }); + this.option('endpointDirectory', { desc: 'Parent directory for enpoints', type: String @@ -18,6 +28,38 @@ util.inherits(Generator, ScriptBase); Generator.prototype.prompting = function askFor() { var done = this.async(); + var promptCb = function (props) { + if(props.route.charAt(0) !== '/') { + props.route = '/' + props.route; + } + + this.route = props.route; + + if (props.models) { + delete this.filters.mongoose; + delete this.filters.mongooseModels; + delete this.filters.sequelize; + delete this.filters.sequelizeModels; + + this.filters[props.models] = true; + this.filters[props.models + 'Models'] = true; + } + done(); + }.bind(this); + + if (this.options.route) { + if (this.filters.mongoose && this.filters.sequelize) { + if (this.options.models) { + return promptCb(this.options); + } + } else { + if (this.filters.mongooseModels) { this.options.models = 'mongoose'; } + else if (this.filters.sequelizeModels) { this.options.models = 'sequelize'; } + else { delete this.options.models; } + return promptCb(this.options); + } + } + var name = this.name; var base = this.config.get('routesBase') || '/api/'; @@ -51,24 +93,7 @@ Generator.prototype.prompting = function askFor() { } ]; - this.prompt(prompts, function (props) { - if(props.route.charAt(0) !== '/') { - props.route = '/' + props.route; - } - - this.route = props.route; - - if (props.models) { - delete this.filters.mongoose; - delete this.filters.mongooseModels; - delete this.filters.sequelize; - delete this.filters.sequelizeModels; - - this.filters[props.models] = true; - this.filters[props.models + 'Models'] = true; - } - done(); - }.bind(this)); + this.prompt(prompts, promptCb); }; Generator.prototype.configuring = function config() { @@ -83,45 +108,43 @@ Generator.prototype.writing = function createFiles() { Generator.prototype.end = function registerEndpoint() { if(this.config.get('insertRoutes')) { + var routesFile = this.config.get('registerRoutesFile'); + var reqPath = this.relativeRequire(this.routeDest, routesFile); var routeConfig = { - file: this.config.get('registerRoutesFile'), + file: routesFile, needle: this.config.get('routesNeedle'), splicable: [ - "app.use(\'" + this.route +"\', require(\'./api/" + this.name + "\'));" + "app.use(\'" + this.route +"\', require(\'" + reqPath + "\'));" ] }; ngUtil.rewriteFile(routeConfig); } - if (this.filters.socketio) { - if(this.config.get('insertSockets')) { - var socketConfig = { - file: this.config.get('registerSocketsFile'), - needle: this.config.get('socketsNeedle'), - splicable: [ - "require(\'../api/" + this.name + '/' + this.name + ".socket\').register(socket);" - ] - }; - ngUtil.rewriteFile(socketConfig); - } + if (this.filters.socketio && this.config.get('insertSockets')) { + var socketsFile = this.config.get('registerSocketsFile'); + var reqPath = this.relativeRequire(this.routeDest + '/' + this.basename + + '.socket', socketsFile); + var socketConfig = { + file: socketsFile, + needle: this.config.get('socketsNeedle'), + splicable: [ + "require(\'" + reqPath + "\').register(socket);" + ] + }; + ngUtil.rewriteFile(socketConfig); } - if (this.filters.sequelize) { - if (this.config.get('insertModels')) { - var modelConfig = { - file: this.config.get('registerModelsFile'), - needle: this.config.get('modelsNeedle'), - splicable: [ - "db." + this.classedName + " = db.sequelize.import(path.join(\n" + - " config.root,\n" + - " 'server',\n" + - " 'api',\n" + - " '" + this.name + "',\n" + - " '" + this.name + ".model'\n" + - "));" - ] - }; - ngUtil.rewriteFile(modelConfig); - } + if (this.filters.sequelize && this.config.get('insertModels')) { + var modelsFile = this.config.get('registerModelsFile'); + var reqPath = this.relativeRequire(this.routeDest + '/' + this.basename + + '.model', modelsFile); + var modelConfig = { + file: modelsFile, + needle: this.config.get('modelsNeedle'), + splicable: [ + "db." + this.classedName + " = db.sequelize.import(\'" + reqPath +"\');" + ] + }; + ngUtil.rewriteFile(modelConfig); } }; diff --git a/endpoint/templates/name.controller.js b/endpoint/templates/basename.controller.js similarity index 89% rename from endpoint/templates/name.controller.js rename to endpoint/templates/basename.controller.js index abcc5f34b..cd151b13a 100644 --- a/endpoint/templates/name.controller.js +++ b/endpoint/templates/basename.controller.js @@ -10,8 +10,8 @@ 'use strict';<% if (filters.models) { %> var _ = require('lodash');<% if (filters.mongooseModels) { %> -var <%= classedName %> = require('./<%= name %>.model');<% } if (filters.sequelizeModels) { %> -var sqldb = require('../../sqldb'); +var <%= classedName %> = require('./<%= basename %>.model');<% } if (filters.sequelizeModels) { %> +var sqldb = require('<%= relativeRequire(config.get('registerModelsFile')) %>'); var <%= classedName %> = sqldb.<%= classedName %>;<% } %> function handleError(res, statusCode) { @@ -64,7 +64,7 @@ function removeEntity(res) { }; }<% } %> -// Gets a list of <%= name %>s +// Gets a list of <%= classedName %>s exports.index = function(req, res) {<% if (!filters.models) { %> res.json([]);<% } else { %> <% if (filters.mongooseModels) { %><%= classedName %>.findAsync()<% } @@ -73,7 +73,7 @@ exports.index = function(req, res) {<% if (!filters.models) { %> .catch(handleError(res));<% } %> };<% if (filters.models) { %> -// Gets a single <%= name %> from the DB +// Gets a single <%= classedName %> from the DB exports.show = function(req, res) { <% if (filters.mongooseModels) { %><%= classedName %>.findByIdAsync(req.params.id)<% } if (filters.sequelizeModels) { %><%= classedName %>.find({ @@ -86,7 +86,7 @@ exports.show = function(req, res) { .catch(handleError(res)); }; -// Creates a new <%= name %> in the DB +// Creates a new <%= classedName %> in the DB exports.create = function(req, res) { <% if (filters.mongooseModels) { %><%= classedName %>.createAsync(req.body)<% } if (filters.sequelizeModels) { %><%= classedName %>.create(req.body)<% } %> @@ -94,7 +94,7 @@ exports.create = function(req, res) { .catch(handleError(res)); }; -// Updates an existing <%= name %> in the DB +// Updates an existing <%= classedName %> in the DB exports.update = function(req, res) { if (req.body._id) { delete req.body._id; @@ -111,7 +111,7 @@ exports.update = function(req, res) { .catch(handleError(res)); }; -// Deletes a <%= name %> from the DB +// Deletes a <%= classedName %> from the DB exports.destroy = function(req, res) { <% if (filters.mongooseModels) { %><%= classedName %>.findByIdAsync(req.params.id)<% } if (filters.sequelizeModels) { %><%= classedName %>.find({ diff --git a/endpoint/templates/name.events(models).js b/endpoint/templates/basename.events(models).js similarity index 84% rename from endpoint/templates/name.events(models).js rename to endpoint/templates/basename.events(models).js index 8bda5cf9a..f39b5b0be 100644 --- a/endpoint/templates/name.events(models).js +++ b/endpoint/templates/basename.events(models).js @@ -5,8 +5,8 @@ 'use strict'; var EventEmitter = require('events').EventEmitter;<% if (filters.mongooseModels) { %> -var <%= classedName %> = require('./<%= name %>.model');<% } if (filters.sequelizeModels) { %> -var <%= classedName %> = require('../../sqldb').<%= classedName %>;<% } %> +var <%= classedName %> = require('./<%= basename %>.model');<% } if (filters.sequelizeModels) { %> +var <%= classedName %> = require('<%= relativeRequire(config.get('registerModelsFile')) %>').<%= classedName %>;<% } %> var <%= classedName %>Events = new EventEmitter(); // Set max event listeners (0 == unlimited) diff --git a/endpoint/templates/name.integration.js b/endpoint/templates/basename.integration.js similarity index 84% rename from endpoint/templates/name.integration.js rename to endpoint/templates/basename.integration.js index 160cdedfa..bcd3fd407 100644 --- a/endpoint/templates/name.integration.js +++ b/endpoint/templates/basename.integration.js @@ -1,6 +1,6 @@ 'use strict'; -var app = require('../../app'); +var app = require('<%= relativeRequire('server/app') %>'); var request = require('supertest');<% if(filters.models) { %> var new<%= classedName %>;<% } %> @@ -36,7 +36,7 @@ describe('<%= classedName %> API:', function() { .post('<%= route %>') .send({ name: 'New <%= classedName %>', - info: 'This is the brand new <%= name %>!!!' + info: 'This is the brand new <%= cameledName %>!!!' }) .expect(201) .expect('Content-Type', /json/) @@ -49,9 +49,9 @@ describe('<%= classedName %> API:', function() { }); }); - it('should respond with the newly created <%= name %>', function() { + it('should respond with the newly created <%= cameledName %>', function() { new<%= classedName %>.name.should.equal('New <%= classedName %>'); - new<%= classedName %>.info.should.equal('This is the brand new <%= name %>!!!'); + new<%= classedName %>.info.should.equal('This is the brand new <%= cameledName %>!!!'); }); }); @@ -77,9 +77,9 @@ describe('<%= classedName %> API:', function() { <%= cameledName %> = {}; }); - it('should respond with the requested <%= name %>', function() { + it('should respond with the requested <%= cameledName %>', function() { <%= cameledName %>.name.should.equal('New <%= classedName %>'); - <%= cameledName %>.info.should.equal('This is the brand new <%= name %>!!!'); + <%= cameledName %>.info.should.equal('This is the brand new <%= cameledName %>!!!'); }); }); @@ -92,7 +92,7 @@ describe('<%= classedName %> API:', function() { .put('<%= route %>/' + new<%= classedName %>._id) .send({ name: 'Updated <%= classedName %>', - info: 'This is the updated <%= name %>!!!' + info: 'This is the updated <%= cameledName %>!!!' }) .expect(200) .expect('Content-Type', /json/) @@ -109,9 +109,9 @@ describe('<%= classedName %> API:', function() { updated<%= classedName %> = {}; }); - it('should respond with the updated <%= name %>', function() { + it('should respond with the updated <%= cameledName %>', function() { updated<%= classedName %>.name.should.equal('Updated <%= classedName %>'); - updated<%= classedName %>.info.should.equal('This is the updated <%= name %>!!!'); + updated<%= classedName %>.info.should.equal('This is the updated <%= cameledName %>!!!'); }); }); @@ -130,7 +130,7 @@ describe('<%= classedName %> API:', function() { }); }); - it('should respond with 404 when <%= name %> does not exist', function(done) { + it('should respond with 404 when <%= cameledName %> does not exist', function(done) { request(app) .delete('<%= route %>/' + new<%= classedName %>._id) .expect(404) diff --git a/endpoint/templates/name.model(mongooseModels).js b/endpoint/templates/basename.model(mongooseModels).js similarity index 100% rename from endpoint/templates/name.model(mongooseModels).js rename to endpoint/templates/basename.model(mongooseModels).js diff --git a/endpoint/templates/name.model(sequelizeModels).js b/endpoint/templates/basename.model(sequelizeModels).js similarity index 100% rename from endpoint/templates/name.model(sequelizeModels).js rename to endpoint/templates/basename.model(sequelizeModels).js diff --git a/endpoint/templates/name.socket(socketio).js b/endpoint/templates/basename.socket(socketio).js similarity index 82% rename from endpoint/templates/name.socket(socketio).js rename to endpoint/templates/basename.socket(socketio).js index 24d744d13..037f6113a 100644 --- a/endpoint/templates/name.socket(socketio).js +++ b/endpoint/templates/basename.socket(socketio).js @@ -4,7 +4,7 @@ 'use strict'; -var <%= classedName %>Events = require('./<%= name %>.events'); +var <%= classedName %>Events = require('./<%= basename %>.events'); // Model events to emit var events = ['save', 'remove']; @@ -13,7 +13,7 @@ exports.register = function(socket) { // Bind model events to socket events for (var i = 0, eventsLength = events.length; i < eventsLength; i++) { var event = events[i]; - var listener = createListener('<%= name %>:' + event, socket); + var listener = createListener('<%= cameledName %>:' + event, socket); <%= classedName %>Events.on(event, listener); socket.on('disconnect', removeListener(event, listener)); diff --git a/endpoint/templates/index.js b/endpoint/templates/index.js index 60198d142..26dc430dd 100644 --- a/endpoint/templates/index.js +++ b/endpoint/templates/index.js @@ -1,7 +1,7 @@ 'use strict'; var express = require('express'); -var controller = require('./<%= name %>.controller'); +var controller = require('./<%= basename %>.controller'); var router = express.Router(); diff --git a/endpoint/templates/index.spec.js b/endpoint/templates/index.spec.js index 291a04662..4bd178948 100644 --- a/endpoint/templates/index.spec.js +++ b/endpoint/templates/index.spec.js @@ -3,11 +3,11 @@ var proxyquire = require('proxyquire').noPreserveCache(); var <%= cameledName %>CtrlStub = { - index: '<%= name %>Ctrl.index'<% if(filters.models) { %>, - show: '<%= name %>Ctrl.show', - create: '<%= name %>Ctrl.create', - update: '<%= name %>Ctrl.update', - destroy: '<%= name %>Ctrl.destroy'<% } %> + index: '<%= cameledName %>Ctrl.index'<% if(filters.models) { %>, + show: '<%= cameledName %>Ctrl.show', + create: '<%= cameledName %>Ctrl.create', + update: '<%= cameledName %>Ctrl.update', + destroy: '<%= cameledName %>Ctrl.destroy'<% } %> }; var routerStub = { @@ -25,7 +25,7 @@ var <%= cameledName %>Index = proxyquire('./index.js', { return routerStub; } }, - './<%= name %>.controller': <%= cameledName %>CtrlStub + './<%= basename %>.controller': <%= cameledName %>CtrlStub }); describe('<%= classedName %> API Router:', function() { @@ -36,9 +36,9 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>', function() { - it('should route to <%= name %>.controller.index', function() { + it('should route to <%= cameledName %>.controller.index', function() { routerStub.get - .withArgs('/', '<%= name %>Ctrl.index') + .withArgs('/', '<%= cameledName %>Ctrl.index') .should.have.been.calledOnce; }); @@ -46,9 +46,9 @@ describe('<%= classedName %> API Router:', function() { describe('GET <%= route %>/:id', function() { - it('should route to <%= name %>.controller.show', function() { + it('should route to <%= cameledName %>.controller.show', function() { routerStub.get - .withArgs('/:id', '<%= name %>Ctrl.show') + .withArgs('/:id', '<%= cameledName %>Ctrl.show') .should.have.been.calledOnce; }); @@ -56,9 +56,9 @@ describe('<%= classedName %> API Router:', function() { describe('POST <%= route %>', function() { - it('should route to <%= name %>.controller.create', function() { + it('should route to <%= cameledName %>.controller.create', function() { routerStub.post - .withArgs('/', '<%= name %>Ctrl.create') + .withArgs('/', '<%= cameledName %>Ctrl.create') .should.have.been.calledOnce; }); @@ -66,9 +66,9 @@ describe('<%= classedName %> API Router:', function() { describe('PUT <%= route %>/:id', function() { - it('should route to <%= name %>.controller.update', function() { + it('should route to <%= cameledName %>.controller.update', function() { routerStub.put - .withArgs('/:id', '<%= name %>Ctrl.update') + .withArgs('/:id', '<%= cameledName %>Ctrl.update') .should.have.been.calledOnce; }); @@ -76,9 +76,9 @@ describe('<%= classedName %> API Router:', function() { describe('PATCH <%= route %>/:id', function() { - it('should route to <%= name %>.controller.update', function() { + it('should route to <%= cameledName %>.controller.update', function() { routerStub.patch - .withArgs('/:id', '<%= name %>Ctrl.update') + .withArgs('/:id', '<%= cameledName %>Ctrl.update') .should.have.been.calledOnce; }); @@ -86,9 +86,9 @@ describe('<%= classedName %> API Router:', function() { describe('DELETE <%= route %>/:id', function() { - it('should route to <%= name %>.controller.destroy', function() { + it('should route to <%= cameledName %>.controller.destroy', function() { routerStub.delete - .withArgs('/:id', '<%= name %>Ctrl.destroy') + .withArgs('/:id', '<%= cameledName %>Ctrl.destroy') .should.have.been.calledOnce; }); From 40277fdb35478df8c4860ed2bed2997bb2b4edb4 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 29 Jul 2015 07:08:59 -0400 Subject: [PATCH 180/201] chore(dependencies): update sequelize --- app/templates/_package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index c9b1533be..f72c18ca5 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -19,7 +19,7 @@ "mongoose": "~4.0.3", "mongoose-bird": "~0.0.1", "connect-mongo": "^0.8.1",<% } %><% if (filters.sequelize) { %> - "sequelize": "^2.0.0-rc2", + "sequelize": "^3.5.1", "sqlite3": "~3.0.2",<% } %><% if (filters.auth) { %> "jsonwebtoken": "^5.0.0", "express-jwt": "^3.0.0", From 63fae5cb2c8e0b21e5140ebd522a8b8d768c075b Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 29 Jul 2015 07:09:40 -0400 Subject: [PATCH 181/201] fix(gen): remove thing import from sequelize template --- .../server/sqldb(sequelize)/index.js | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/app/templates/server/sqldb(sequelize)/index.js b/app/templates/server/sqldb(sequelize)/index.js index 231db9823..2500a2213 100644 --- a/app/templates/server/sqldb(sequelize)/index.js +++ b/app/templates/server/sqldb(sequelize)/index.js @@ -13,23 +13,8 @@ var db = { Sequelize: Sequelize, sequelize: new Sequelize(config.sequelize.uri, config.sequelize.options) }; -<% if (filters.sequelizeModels) { %> -db.Thing = db.sequelize.import(path.join( - config.root, - 'server', - 'api', - 'thing', - 'thing.model' -)); -<% if (filters.auth) { %> -db.User = db.sequelize.import(path.join( - config.root, - 'server', - 'api', - 'user', - 'user.model' -)); -<% } %><% } %> -// Insert models below + +// Insert models below<% if (filters.sequelizeModels && filters.auth) { %> +db.User = db.sequelize.import('../api/user/user.model');<% } %> module.exports = db; From 06eeab4312bde750819366b40ab062fd5c8b7465 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 2 Aug 2015 05:23:26 -0400 Subject: [PATCH 182/201] fix(test): add endpoint sub-gen as test dependency --- test/test-file-creation.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index ce8635c0b..21b4c69fa 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -314,6 +314,7 @@ describe('angular-fullstack generator', function () { this.timeout(10000); var deps = [ '../../app', + '../../endpoint', [ helpers.createDummyGenerator(), 'ng-component:app' @@ -421,6 +422,7 @@ describe('angular-fullstack generator', function () { fs.copySync(__dirname + '/fixtures/.yo-rc.json', __dirname + '/temp/.yo-rc.json'); var gen = helpers.createGenerator('angular-fullstack:app', [ '../../app', + '../../endpoint', [ helpers.createDummyGenerator(), 'ng-component:app' @@ -445,6 +447,7 @@ describe('angular-fullstack generator', function () { fs.copySync(__dirname + '/fixtures/.yo-rc.json', __dirname + '/temp/.yo-rc.json'); var gen = helpers.createGenerator('angular-fullstack:app', [ '../../app', + '../../endpoint', [ helpers.createDummyGenerator(), 'ng-component:app' From c18824a8bbdeedf84807fc04d08eaa3ff7246772 Mon Sep 17 00:00:00 2001 From: kingcody Date: Sun, 2 Aug 2015 06:36:29 -0400 Subject: [PATCH 183/201] test(endpoint): test against a path name endpoint --- test/test-file-creation.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test-file-creation.js b/test/test-file-creation.js index 21b4c69fa..fb0fb2b91 100644 --- a/test/test-file-creation.js +++ b/test/test-file-creation.js @@ -417,6 +417,29 @@ describe('angular-fullstack generator', function () { runTest('grunt test:server', this, done, 'Foo'); }); + it('should pass lint with generated path name endpoint', function(done) { + runTest('grunt jshint', this, done, 'foo/bar'); + }); + + it('should run server tests successfully with generated path name endpoint', function(done) { + runTest('grunt test:server', this, done, 'foo/bar'); + }); + + it('should generate expected files with path name endpoint', function(done) { + runTest('(exit 0)', this, function() { + helpers.assertFile([ + 'server/api/foo/bar/index.js', + 'server/api/foo/bar/index.spec.js', + 'server/api/foo/bar/bar.controller.js', + 'server/api/foo/bar/bar.events.js', + 'server/api/foo/bar/bar.integration.js', + 'server/api/foo/bar/bar.model.js', + 'server/api/foo/bar/bar.socket.js' + ]); + done(); + }, 'foo/bar'); + }); + it('should use existing config if available', function(done) { this.timeout(60000); fs.copySync(__dirname + '/fixtures/.yo-rc.json', __dirname + '/temp/.yo-rc.json'); From 3b6650710ff7b212e4fc9e74b98c7bac719c397f Mon Sep 17 00:00:00 2001 From: kingcody Date: Mon, 10 Aug 2015 00:25:45 -0400 Subject: [PATCH 184/201] feat(gen): add david grunt task --- Gruntfile.js | 15 +++++++++++++++ package.json | 1 + 2 files changed, 16 insertions(+) diff --git a/Gruntfile.js b/Gruntfile.js index c81bffa5c..befea75e5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -87,6 +87,16 @@ module.exports = function (grunt) { ] }] } + }, + david: { + gen: { + options: {} + }, + app: { + options: { + package: 'test/fixtures/package.json' + } + } } }); @@ -271,6 +281,11 @@ module.exports = function (grunt) { ]) }); + grunt.registerTask('deps', function(target) { + if (!target || target === 'app') grunt.task.run(['updateFixtures']); + grunt.task.run(['david:' + (target || '')]); + }); + grunt.registerTask('demo', [ 'clean:demo', 'generateDemo' diff --git a/package.json b/package.json index f20b54725..7dfa26f05 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "grunt-contrib-clean": "^0.6.0", "grunt-contrib-jshint": "^0.11.2", "grunt-conventional-changelog": "~1.0.0", + "grunt-david": "~0.5.0", "grunt-env": "^0.4.1", "grunt-mocha-test": "^0.11.0", "grunt-release": "~0.6.0", From 1d5ab7db3b71110b30aa9fc0a3a3601c47e6e72f Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 12 Aug 2015 06:01:22 -0400 Subject: [PATCH 185/201] feat(app): server ships with babel --- app/templates/README.md | 3 +-- app/templates/_package.json | 4 ++-- app/templates/server/index.js | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/templates/README.md b/app/templates/README.md index bb4def0ce..e49273a90 100644 --- a/app/templates/README.md +++ b/app/templates/README.md @@ -11,8 +11,7 @@ This project was generated with the [Angular Full-Stack Generator](https://githu - [Bower](bower.io) (`npm install --global bower`)<% if(filters.sass) { %> - [Ruby](https://www.ruby-lang.org) and then `gem install sass`<% } if(filters.grunt) { %> - [Grunt](http://gruntjs.com/) (`npm install --global grunt-cli`)<% } if(filters.gulp) { %> -- [Gulp](http://gulpjs.com/) (`npm install --global gulp`)<% } if(filters.babel) { %> -- [Babel](https://babeljs.io) (`npm install --global babel`)<% } if(filters.mongoose) { %> +- [Gulp](http://gulpjs.com/) (`npm install --global gulp`)<% } if(filters.mongoose) { %> - [MongoDB](https://www.mongodb.org/) - Keep a running daemon with `mongod`<% } if(filters.sequelize) { %> - [SQLite](https://www.sqlite.org/quickstart.html)<% } %> diff --git a/app/templates/_package.json b/app/templates/_package.json index f72c18ca5..7ea2eda4b 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -12,8 +12,8 @@ "errorhandler": "~1.0.0", "compression": "~1.0.1", "composable-middleware": "^0.3.0", - "lodash": "~2.4.1",<% if(filters.babel) { %> - "babel-core": "^5.6.4",<% } %><% if (filters.jade) { %> + "lodash": "~2.4.1", + "babel-core": "^5.6.4",<% if (filters.jade) { %> "jade": "~1.2.0",<% } %><% if (filters.html) { %> "ejs": "~0.8.4",<% } %><% if (filters.mongoose) { %> "mongoose": "~4.0.3", diff --git a/app/templates/server/index.js b/app/templates/server/index.js index 7722a0e6c..fc65cd5f4 100644 --- a/app/templates/server/index.js +++ b/app/templates/server/index.js @@ -1,7 +1,7 @@ -'use strict';<% if (filters.babel) { %> +'use strict'; // Register the Babel require hook -require('babel-core/register');<% } %> +require('babel-core/register'); // Export the application exports = module.exports = require('./app'); From 733843e68348a96a5444fd37640d1726dc517701 Mon Sep 17 00:00:00 2001 From: Jinyoung Kim Date: Wed, 12 Aug 2015 22:32:37 +0900 Subject: [PATCH 186/201] chore(dependencies): remove angular-scenario --- app/templates/Gruntfile.js | 1 - app/templates/_bower.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index bd4559db6..8788038b1 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -245,7 +245,6 @@ module.exports = function (grunt) { wiredep: { options: { exclude: [ - /angular-scenario/, /bootstrap-sass-official/, /bootstrap.js/, '/json3/', diff --git a/app/templates/_bower.json b/app/templates/_bower.json index 5798b8a73..1d41b39d1 100644 --- a/app/templates/_bower.json +++ b/app/templates/_bower.json @@ -18,7 +18,6 @@ "angular-ui-router": "~0.2.15"<% } %> }, "devDependencies": { - "angular-mocks": "~1.4.0", - "angular-scenario": "~1.4.0" + "angular-mocks": "~1.4.0" } } From a849395d67290dd68721eb4f9871db2f1d3c6b66 Mon Sep 17 00:00:00 2001 From: Jinyoung Kim Date: Wed, 12 Aug 2015 22:35:49 +0900 Subject: [PATCH 187/201] docs(readme): remove angular-senario in bower list --- readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.md b/readme.md index af727cdb8..f5f37e9e1 100644 --- a/readme.md +++ b/readme.md @@ -302,7 +302,6 @@ The following packages are always installed by the [app](#app) generator: * angular-mocks * angular-resource * angular-sanitize -* angular-scenario * es5-shim * font-awesome * json3 From c8e2f0f36e373bb22596c36fcb74cc3695f02e9a Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 12 Aug 2015 23:05:29 -0400 Subject: [PATCH 188/201] feat(gen): test helper `does` accepts escaped template strings --- app/index.js | 2 ++ script-base.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/index.js b/app/index.js index c161fd381..50ec1deed 100644 --- a/app/index.js +++ b/app/index.js @@ -28,6 +28,8 @@ var AngularFullstackGenerator = yeoman.generators.Base.extend({ // dynamic assertion statement this.does = this.is = function(foo) { + foo = this.engine(foo.replace(/\(;>%%<;\)/g, '<%') + .replace(/\(;>%<;\)/g, '%>'), this); if (this.filters.should) { return foo + '.should'; } else { diff --git a/script-base.js b/script-base.js index d88cd988c..f24b61f85 100644 --- a/script-base.js +++ b/script-base.js @@ -25,6 +25,8 @@ var Generator = module.exports = function Generator() { // dynamic assertion statement this.does = this.is = function(foo) { + foo = this.engine(foo.replace(/\(;>%%<;\)/g, '<%') + .replace(/\(;>%<;\)/g, '%>'), this); if (this.filters.should) { return foo + '.should'; } else { From 6fa4b4e56c6f6e56d103fba8dab7ba75cabbe142 Mon Sep 17 00:00:00 2001 From: kingcody Date: Wed, 12 Aug 2015 23:28:56 -0400 Subject: [PATCH 189/201] fix(app): only generate excludes for included deps --- app/templates/Gruntfile.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/templates/Gruntfile.js b/app/templates/Gruntfile.js index 8788038b1..c9d5568aa 100644 --- a/app/templates/Gruntfile.js +++ b/app/templates/Gruntfile.js @@ -245,12 +245,12 @@ module.exports = function (grunt) { wiredep: { options: { exclude: [ - /bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/'<% if(!filters.css) { %>, - /bootstrap.css/, - /font-awesome.css/<% } %> + /font-awesome\.css/<% if(filters.bootstrap) { %>, + /bootstrap\.css/<% if(filters.sass) { %>, + /bootstrap-sass-official/<% }}} %> ] }, client: { From ee9f4f08a4d6557ff9be446a1622de3e01082b8e Mon Sep 17 00:00:00 2001 From: kingcody Date: Thu, 13 Aug 2015 08:15:20 -0400 Subject: [PATCH 190/201] fix(app): karma requires `babel` always --- app/templates/mocha.conf.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/mocha.conf.js b/app/templates/mocha.conf.js index 6b1504e9c..76f56625e 100644 --- a/app/templates/mocha.conf.js +++ b/app/templates/mocha.conf.js @@ -1,7 +1,7 @@ -'use strict';<% if(filters.babel) { %> +'use strict'; // Register the Babel require hook -require('babel-core/register');<% } %> +require('babel-core/register'); var chai = require('chai'); From a734289d33dff0142ccce352750272691cc62517 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Thu, 13 Aug 2015 16:23:29 -0400 Subject: [PATCH 191/201] feat(gulp): add LESS --- app/templates/_package.json | 3 ++- app/templates/gulpfile.babel(gulp).js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index c1e7d43b3..13ffbe6df 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -47,7 +47,8 @@ "gulp-imagemin": "^2.2.1", "gulp-inject": "^1.3.1", "gulp-jshint": "^1.11.0", - "gulp-karma": "0.0.4", + "gulp-karma": "0.0.4",<% if(filters.less) { %> + "gulp-less": "3.0.3",<% } %> "gulp-livereload": "^3.8.0", "gulp-load-plugins": "^1.0.0-rc.1", "gulp-minify-css": "^1.1.6", diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index bc8a09fb7..3277a20d7 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -115,7 +115,8 @@ let styles = lazypipe() use: [nib()], errors: true })<% } if(filters.sass) { %> - .pipe(plugins.sass)<% } %> + .pipe(plugins.sass)<% } if(filters.less) { %> + .pipe(plugins.less)<% } %> .pipe(plugins.autoprefixer, {browsers: ['last 1 version']}) .pipe(plugins.sourcemaps.write, '.') .pipe(gulp.dest, '.tmp/app');<% if(filters.babel || filters.coffee) { %> From ba855d8fda35c4f62bce925c50ce6b4afb3b69fe Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sat, 15 Aug 2015 15:37:10 -0400 Subject: [PATCH 192/201] fix(gulp:watch): fix gulp watch for styles --- app/templates/gulpfile.babel(gulp).js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 3277a20d7..f48a0dfc4 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -109,7 +109,6 @@ let lintServerScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> let styles = lazypipe() - .pipe(gulp.src, paths.client.mainStyle) .pipe(plugins.sourcemaps.init)<% if(filters.stylus) { %> .pipe(plugins.stylus, { use: [nib()], @@ -169,7 +168,10 @@ gulp.task('inject:<%= styleExt %>', () => { .pipe(gulp.dest('client/app')); }); -gulp.task('styles', styles);<% if(filters.babel || filters.coffee) { %> +gulp.task('styles', () => { + return gulp.src(paths.client.mainStyle) + .pipe(styles()); +}));<% if(filters.babel || filters.coffee) { %> gulp.task('transpile', () => { return gulp.src(paths.client.scripts) From 306896e79a9fa3b90cbac23b747034f3a63dc545 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sat, 15 Aug 2015 15:37:39 -0400 Subject: [PATCH 193/201] fix(gulp): return stream --- app/templates/gulpfile.babel(gulp).js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index f48a0dfc4..976d1548f 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -182,12 +182,12 @@ gulp.task('transpile', () => { gulp.task('lint:scripts', cb => runSequence(['lint:scripts:client', 'lint:scripts:server'], cb)); gulp.task('lint:scripts:client', () => { - gulp.src(_.union(paths.client.scripts, _.map(paths.client.test, blob => '!' + blob))) + return gulp.src(_.union(paths.client.scripts, _.map(paths.client.test, blob => '!' + blob))) .pipe(lintClientScripts()); }); gulp.task('lint:scripts:server', () => { - gulp.src(_.union(paths.server.scripts, _.map(paths.server.test, blob => '!' + blob))) + return gulp.src(_.union(paths.server.scripts, _.map(paths.server.test, blob => '!' + blob))) .pipe(lintServerScripts()); }); From e6af7e1ef0df453ee9d7b6262e858d426a1d334e Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sat, 15 Aug 2015 15:37:52 -0400 Subject: [PATCH 194/201] docs(gulp): remove old comment --- app/templates/gulpfile.babel(gulp).js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 976d1548f..aede44cfa 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -157,7 +157,6 @@ gulp.task('inject:css', () => { .pipe(gulp.dest('client')); }); -// TODO: other styles gulp.task('inject:<%= styleExt %>', () => { return gulp.src('client/app/app.<%= styleExt %>') .pipe(plugins.inject(gulp.src(_.union(paths.client.styles, ['!' + paths.client.mainStyle]), {read: false}), { From e6e5512f99f08a9adf68cc4235fc9fae65db5875 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sat, 15 Aug 2015 15:38:23 -0400 Subject: [PATCH 195/201] feat(gulp): run injector on script & style watches --- app/templates/gulpfile.babel(gulp).js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index aede44cfa..8aeece76a 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -211,7 +211,7 @@ gulp.task('watch', () => { plugins.livereload.listen(); - plugins.watch(paths.client.styles) + plugins.watch(paths.client.styles, ['inject:<%= styleExt %>']) .pipe(plugins.plumber()) .pipe(styles()) .pipe(plugins.livereload()); @@ -220,7 +220,7 @@ gulp.task('watch', () => { .pipe(plugins.plumber()) .pipe(plugins.livereload()); - plugins.watch(paths.client.scripts) + plugins.watch(paths.client.scripts, ['inject:js']) .pipe(plugins.plumber())<% if(filters.babel || filters.coffee) { %> .pipe(transpile()) .pipe(gulp.dest('.tmp/scripts'))<% } %> From fb42a6f3b3cc7896a5c2aa1504b05e4cc8e02c7e Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Sat, 15 Aug 2015 17:05:59 -0400 Subject: [PATCH 196/201] fix(gulp): include components in views.main paths --- app/templates/gulpfile.babel(gulp).js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 8aeece76a..84066e36c 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -50,7 +50,7 @@ var paths = { }, views: { main: 'client/index.<%= templateExt %>', - files: ['client/app/**/*.<%= templateExt %>'] + files: ['client/{app,components}/**/*.<%= templateExt %>'] }, karma: 'karma.conf.js', dist: 'dist' From e8e9ad856c2c0e346da9fb0306da5ab1c316fc31 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 18 Aug 2015 12:13:24 -0400 Subject: [PATCH 197/201] fix(gulp): fix styles watcher --- app/templates/gulpfile.babel(gulp).js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 84066e36c..483b31d70 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -117,8 +117,7 @@ let styles = lazypipe() .pipe(plugins.sass)<% } if(filters.less) { %> .pipe(plugins.less)<% } %> .pipe(plugins.autoprefixer, {browsers: ['last 1 version']}) - .pipe(plugins.sourcemaps.write, '.') - .pipe(gulp.dest, '.tmp/app');<% if(filters.babel || filters.coffee) { %> + .pipe(plugins.sourcemaps.write, '.');<% if(filters.babel || filters.coffee) { %> let transpile = lazypipe() .pipe(plugins.sourcemaps.init)<% if(filters.babel) { %> @@ -169,7 +168,8 @@ gulp.task('inject:<%= styleExt %>', () => { gulp.task('styles', () => { return gulp.src(paths.client.mainStyle) - .pipe(styles()); + .pipe(styles()) + .pipe(gulp.dest('.tmp/app')); }));<% if(filters.babel || filters.coffee) { %> gulp.task('transpile', () => { @@ -214,6 +214,7 @@ gulp.task('watch', () => { plugins.watch(paths.client.styles, ['inject:<%= styleExt %>']) .pipe(plugins.plumber()) .pipe(styles()) + .pipe(gulp.dest('.tmp')) .pipe(plugins.livereload()); plugins.watch(paths.views.files) From 5431375e800f0dfe99565a63a6198f888a98603d Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 18 Aug 2015 13:13:04 -0400 Subject: [PATCH 198/201] refactor(gulp): make sure to return gulp streams from tasks --- app/templates/gulpfile.babel(gulp).js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 483b31d70..fdb59cdd8 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -262,7 +262,7 @@ gulp.task('test:client', () => { // inject bower components gulp.task('bower', () => { - gulp.src(paths.views.main) + return gulp.src(paths.views.main) .pipe(wiredep({ exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ] })) @@ -331,7 +331,7 @@ gulp.task('html', function () { }); gulp.task('build:images', () => { - gulp.src('client/assets/images/**/*') + return gulp.src('client/assets/images/**/*') .pipe(plugins.cache(plugins.imagemin({ optimizationLevel: 5, progressive: true, @@ -341,7 +341,7 @@ gulp.task('build:images', () => { }); gulp.task('copy:extras', () => { - gulp.src([ + return gulp.src([ 'client/favicon.ico', 'client/robots.txt' ], { dot: true }) @@ -349,12 +349,12 @@ gulp.task('copy:extras', () => { }); gulp.task('copy:fonts', () => { - gulp.src(yeoman.app + '/fonts/**/*') + return gulp.src(yeoman.app + '/fonts/**/*') .pipe(gulp.dest(paths.dist + '/fonts')); }); gulp.task('copy:server', () => { - gulp.src([ + return gulp.src([ 'package.json', 'bower.json', '.bowerrc', From 8f4aba35883ae18469ce4518a674c80e4e2b72f9 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Tue, 18 Aug 2015 13:13:39 -0400 Subject: [PATCH 199/201] fix(gulp): use let, add missing semicolon --- app/templates/gulpfile.babel(gulp).js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index fdb59cdd8..8763818c8 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -252,7 +252,7 @@ gulp.task('test:server', () => { }); gulp.task('test:client', () => { - var testFiles = _.union(paths.client.testRequire, paths.client.test) + let testFiles = _.union(paths.client.testRequire, paths.client.test); return gulp.src(testFiles) .pipe(plugins.karma({ configFile: paths.karma, From 4b5caf285117020fae94bcf134ff9dc3e2a9d2cc Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 19 Aug 2015 00:45:20 -0400 Subject: [PATCH 200/201] fix(gulp:watch): fix styles and script watchers --- app/templates/gulpfile.babel(gulp).js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 8763818c8..cb62a4a63 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -211,20 +211,22 @@ gulp.task('watch', () => { plugins.livereload.listen(); - plugins.watch(paths.client.styles, ['inject:<%= styleExt %>']) - .pipe(plugins.plumber()) - .pipe(styles()) - .pipe(gulp.dest('.tmp')) - .pipe(plugins.livereload()); + plugins.watch(paths.client.styles, () => { //['inject:<%= styleExt %>'] + gulp.src(paths.client.mainStyle) + .pipe(plugins.plumber()) + .pipe(styles()) + .pipe(gulp.dest('.tmp/app')) + .pipe(plugins.livereload()); + }); plugins.watch(paths.views.files) .pipe(plugins.plumber()) .pipe(plugins.livereload()); - plugins.watch(paths.client.scripts, ['inject:js']) + plugins.watch(paths.client.scripts) //['inject:js'] .pipe(plugins.plumber())<% if(filters.babel || filters.coffee) { %> .pipe(transpile()) - .pipe(gulp.dest('.tmp/scripts'))<% } %> + .pipe(gulp.dest('.tmp'))<% } %> .pipe(plugins.livereload()); plugins.watch(_.union(paths.server.scripts, testFiles)) From a7f29679230f5f21b4f48511af710787c4954853 Mon Sep 17 00:00:00 2001 From: Andrew Koroluk Date: Wed, 19 Aug 2015 00:47:43 -0400 Subject: [PATCH 201/201] fix(gulp:serve): add transpile and styles tasks --- app/templates/gulpfile.babel(gulp).js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index cb62a4a63..643a9ec60 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -241,7 +241,9 @@ gulp.task('serve', cb => { ['lint:scripts'], 'inject:js', 'inject:css', - 'bower', + 'bower',<% if(filters.babel || filters.coffee) { %> + ['transpile', 'styles'],<% } else { %> + 'styles',<% } %> ['start:server', 'start:client'], 'watch', cb);