From dddb12c4ebc655b8f2784cc82383e22d078366b4 Mon Sep 17 00:00:00 2001 From: Talysson Date: Fri, 15 Sep 2017 08:50:49 -0300 Subject: [PATCH 1/3] Update Chai to accept async functions as expect parameter --- package.json | 4 ++-- yarn.lock | 49 ++++++++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 94cfb01..6540a5d 100644 --- a/package.json +++ b/package.json @@ -44,10 +44,10 @@ "structure": "^1.2.0" }, "devDependencies": { - "chai": "^3.5.0", + "chai": "^4.1.2", "chai-change": "^2.1.2", "chance": "^1.0.6", - "dirty-chai": "^1.2.2", + "dirty-chai": "^2.0.1", "eslint": "^3.17.1", "factory-girl": "^4.0.0", "istanbul": "^0.4.5", diff --git a/yarn.lock b/yarn.lock index 3f70c82..1196e22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -382,13 +382,16 @@ chai-change@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/chai-change/-/chai-change-2.1.2.tgz#1231cdf8bf5930eea1fab72b5cc4864e5bcae7f6" -chai@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" +chai@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" dependencies: assertion-error "^1.0.1" - deep-eql "^0.1.3" - type-detect "^1.0.0" + check-error "^1.0.1" + deep-eql "^3.0.0" + get-func-name "^2.0.0" + pathval "^1.0.0" + type-detect "^4.0.0" chalk@^1.0.0, chalk@^1.1, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" @@ -408,6 +411,10 @@ charm@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296" +check-error@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + chokidar@^1.4.3, chokidar@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" @@ -702,11 +709,11 @@ decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -deep-eql@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" +deep-eql@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" dependencies: - type-detect "0.1.1" + type-detect "^4.0.0" deep-extend@~0.4.0: version "0.4.1" @@ -764,9 +771,9 @@ diff@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" -dirty-chai@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-1.2.2.tgz#78495e619635f7fe44219aa4c837849bf183142e" +dirty-chai@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-2.0.1.tgz#6b2162ef17f7943589da840abc96e75bda01aff3" doctrine@^1.2.2: version "1.5.0" @@ -1419,6 +1426,10 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + getpass@^0.1.1: version "0.1.6" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" @@ -2953,6 +2964,10 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +pathval@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + pause-stream@0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" @@ -3969,13 +3984,9 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" - -type-detect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" +type-detect@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea" type-is@~1.6.14: version "1.6.14" From 42955f58506de051fb97a2bc3bb5dc349c52f0e0 Mon Sep 17 00:00:00 2001 From: Talysson Date: Fri, 15 Sep 2017 08:51:16 -0300 Subject: [PATCH 2/3] Use async/await instead of then/catch along the app --- src/app/Application.js | 10 +++--- src/app/user/CreateUser.js | 25 +++++++-------- src/app/user/GetAllUsers.js | 17 +++++----- src/infra/user/SequelizeUsersRepository.js | 21 ++++++------ test/api/users/createUser.spec.js | 30 ++++++++--------- test/api/users/listUsers.spec.js | 32 +++++++++---------- .../user/SequelizeUsersRepository.spec.js | 28 ++++++++-------- 7 files changed, 79 insertions(+), 84 deletions(-) diff --git a/src/app/Application.js b/src/app/Application.js index 149e72c..932a7e1 100644 --- a/src/app/Application.js +++ b/src/app/Application.js @@ -9,10 +9,12 @@ class Application { } } - start() { - return Promise.resolve() - .then(() => this.database && this.database.authenticate()) - .then(() => this.server.start()); + async start() { + if(this.database) { + await this.database.authenticate(); + } + + await this.server.start(); } } diff --git a/src/app/user/CreateUser.js b/src/app/user/CreateUser.js index 8398a98..5dff6e7 100644 --- a/src/app/user/CreateUser.js +++ b/src/app/user/CreateUser.js @@ -7,23 +7,22 @@ class CreateUser extends Operation { this.usersRepository = usersRepository; } - execute(userData) { + async execute(userData) { const { SUCCESS, ERROR, VALIDATION_ERROR } = this.outputs; const user = new User(userData); - this.usersRepository - .add(user) - .then((newUser) => { - this.emit(SUCCESS, newUser); - }) - .catch((error) => { - if(error.message === 'ValidationError') { - return this.emit(VALIDATION_ERROR, error); - } - - this.emit(ERROR, error); - }); + try { + const newUser = await this.usersRepository.add(user); + + this.emit(SUCCESS, newUser); + } catch(error) { + if(error.message === 'ValidationError') { + return this.emit(VALIDATION_ERROR, error); + } + + this.emit(ERROR, error); + } } } diff --git a/src/app/user/GetAllUsers.js b/src/app/user/GetAllUsers.js index ec3b273..e6c7f91 100644 --- a/src/app/user/GetAllUsers.js +++ b/src/app/user/GetAllUsers.js @@ -6,19 +6,18 @@ class GetAllUsers extends Operation { this.usersRepository = usersRepository; } - execute() { + async execute() { const { SUCCESS, ERROR } = this.outputs; - this.usersRepository - .getAll({ + try { + const users = await this.usersRepository.getAll({ attributes: ['id', 'name'] - }) - .then((users) => { - this.emit(SUCCESS, users); - }) - .catch((error) => { - this.emit(ERROR, error); }); + + this.emit(SUCCESS, users); + } catch(error) { + this.emit(ERROR, error); + } } } diff --git a/src/infra/user/SequelizeUsersRepository.js b/src/infra/user/SequelizeUsersRepository.js index a38de69..9bbef8c 100644 --- a/src/infra/user/SequelizeUsersRepository.js +++ b/src/infra/user/SequelizeUsersRepository.js @@ -5,29 +5,28 @@ class SequelizeUsersRepository { this.UserModel = UserModel; } - getAll(...args) { - return this.UserModel - .findAll(...args) - .then((users) => users.map(UserMapper.toEntity)); + async getAll(...args) { + const users = await this.UserModel.findAll(...args); + + return users.map(UserMapper.toEntity); } - add(user) { + async add(user) { const { valid, errors } = user.validate(); if(!valid) { const error = new Error('ValidationError'); error.details = errors; - return Promise.reject(error); + throw error; } - return this.UserModel - .create(UserMapper.toDatabase(user)) - .then(UserMapper.toEntity); + const newUser = await this.UserModel.create(UserMapper.toDatabase(user)); + return UserMapper.toEntity(newUser); } - count() { - return this.UserModel.count(); + async count() { + return await this.UserModel.count(); } } diff --git a/test/api/users/createUser.spec.js b/test/api/users/createUser.spec.js index 3679088..563d3cd 100644 --- a/test/api/users/createUser.spec.js +++ b/test/api/users/createUser.spec.js @@ -3,31 +3,29 @@ const { expect } = require('chai'); describe('API :: POST /api/users', () => { context('when sent data is ok', () => { - it('creates and returns 200 and the new user', () => { - return request() + it('creates and returns 200 and the new user', async () => { + const { body } = await request() .post('/api/users') .send({ name: 'New User' }) - .expect(201) - .then(({ body }) => { - expect(body.id).to.exist; - expect(body.name).to.equal('New User'); - expect(body).to.have.all.keys('id', 'name'); - }); + .expect(201); + + expect(body.id).to.exist; + expect(body.name).to.equal('New User'); + expect(body).to.have.all.keys('id', 'name'); }); }); context('when name is missing', () => { - it('does not create and returns 400 with the validation error', () => { - return request() + it('does not create and returns 400 with the validation error', async () => { + const { body } = await request() .post('/api/users') - .expect(400) - .then(({ body }) => { - expect(body.type).to.equal('ValidationError'); - expect(body.details).to.have.lengthOf(1); - expect(body.details[0].message).to.equal('"name" is required'); - }); + .expect(400); + + expect(body.type).to.equal('ValidationError'); + expect(body.details).to.have.lengthOf(1); + expect(body.details[0].message).to.equal('"name" is required'); }); }); }); diff --git a/test/api/users/listUsers.spec.js b/test/api/users/listUsers.spec.js index 88273b3..cb2e3c9 100644 --- a/test/api/users/listUsers.spec.js +++ b/test/api/users/listUsers.spec.js @@ -11,28 +11,28 @@ describe('API :: GET /api/users', () => { ]); }); - it('return success with array of users', () => { - return request().get('/api/users') - .expect(200) - .then(({ body }) => { - expect(body).to.have.lengthOf(2); + it('return success with array of users', async () => { + const { body } = await request() + .get('/api/users') + .expect(200); - expect(body[0].name).to.equal('First'); - expect(body[0]).to.have.all.keys('id', 'name'); + expect(body).to.have.lengthOf(2); - expect(body[1].name).to.equal('Second'); - expect(body[1]).to.have.all.keys('id', 'name'); - }); + expect(body[0].name).to.equal('First'); + expect(body[0]).to.have.all.keys('id', 'name'); + + expect(body[1].name).to.equal('Second'); + expect(body[1]).to.have.all.keys('id', 'name'); }); }); context('when there are no users', () => { - it('return success with empty array', () => { - return request().get('/api/users') - .expect(200) - .then(({ body }) => { - expect(body).to.have.lengthOf(0); - }); + it('return success with empty array', async () => { + const { body } = await request() + .get('/api/users') + .expect(200); + + expect(body).to.have.lengthOf(0); }); }); }); diff --git a/test/infra/user/SequelizeUsersRepository.spec.js b/test/infra/user/SequelizeUsersRepository.spec.js index f919ffd..79ee7af 100644 --- a/test/infra/user/SequelizeUsersRepository.spec.js +++ b/test/infra/user/SequelizeUsersRepository.spec.js @@ -13,19 +13,18 @@ describe('Infra :: User :: SequelizeUsersRepository', () => { ]); }); - it('returns all users from the database', () => { + it('returns all users from the database', async () => { const repository = new SequelizeUsersRepository({ UserModel }); - return repository.getAll() - .then((users) => { - expect(users).to.have.lengthOf(2); + const users = await repository.getAll(); - expect(users[0]).to.be.instanceOf(User); - expect(users[0].name).to.equal('User 1'); + expect(users).to.have.lengthOf(2); - expect(users[1]).to.be.instanceOf(User); - expect(users[1].name).to.equal('User 2'); - }); + expect(users[0]).to.be.instanceOf(User); + expect(users[0].name).to.equal('User 1'); + + expect(users[1]).to.be.instanceOf(User); + expect(users[1].name).to.equal('User 2'); }); }); @@ -40,12 +39,11 @@ describe('Infra :: User :: SequelizeUsersRepository', () => { expect(user.validate().valid).to.be.ok(); - return expect(() => { - return repo.add(user) - .then((persistedUser) => { - expect(persistedUser.id).to.exist; - expect(persistedUser.name).to.equal('The User'); - }); + return expect(async () => { + const persistedUser = await repo.add(user); + + expect(persistedUser.id).to.exist; + expect(persistedUser.name).to.equal('The User'); }).to.alter(() => repo.count(), { by: 1 }); }); }); From f05157f68b75c203974c41d909e2fc0bc3e01f46 Mon Sep 17 00:00:00 2001 From: Talysson Date: Thu, 21 Sep 2017 00:07:23 -0300 Subject: [PATCH 3/3] Set Node version to allow async/await --- .nvmrc | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.nvmrc b/.nvmrc index 09b254e..66ce77b 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6.0.0 +7.0.0 diff --git a/package.json b/package.json index 6540a5d..d999a38 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "private": true, "engines": { - "node": ">=6.0.0" + "node": ">=7.0.0" }, "scripts": { "start": "node cluster.js",