From 43505906978e14a93adc0827aba3343185f6cdd7 Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sat, 9 Mar 2019 13:36:27 +0300 Subject: [PATCH 01/13] add changePasssword mutation --- src/middleware/permissionsMiddleware.js | 3 +- src/resolvers/user_management.js | 69 ++++++++++++++++++++++--- src/schema.graphql | 1 + 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index c40803e00..15c4d1a9b 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -55,7 +55,8 @@ const permissions = shield({ report: isAuthenticated, CreateBadge: isAdmin, UpdateBadge: isAdmin, - DeleteBadge: isAdmin + DeleteBadge: isAdmin, + changePassword: isAuthenticated // addFruitToBasket: isAuthenticated // CreateUser: allow, }, diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index ec4ae7ce2..3a7698e24 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -30,22 +30,75 @@ export default { // throw new Error('Already logged in.') // } const session = driver.session() - return session.run( - 'MATCH (user:User {email: $userEmail}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', { - userEmail: email - }) - .then(async (result) => { + return session + .run( + 'MATCH (user:User {email: $userEmail}) ' + + 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', + { + userEmail: email + } + ) + .then(async result => { session.close() const [currentUser] = await result.records.map(function (record) { return record.get('user') }) - if (currentUser && await bcrypt.compareSync(password, currentUser.password)) { + if ( + currentUser && + (await bcrypt.compareSync(password, currentUser.password)) + ) { delete currentUser.password return encode(currentUser) - } else throw new AuthenticationError('Incorrect email address or password.') + } else { + throw new AuthenticationError( + 'Incorrect email address or password.' + ) + } }) + }, + changePassword: async ( + _, + { oldPassword, newPassword }, + { driver, user } + ) => { + const session = driver.session() + let result = await session.run( + `MATCH (user:User {email: $userEmail}) + RETURN user {.id, .email, .password}`, + { + userEmail: user.email + } + ) + + const [currentUser] = result.records.map(function (record) { + return record.get('user') + }) + + if (!(await bcrypt.compareSync(oldPassword, currentUser.password))) { + throw new AuthenticationError('Old password isn\'t valid') + } + + if (await bcrypt.compareSync(newPassword, currentUser.password)) { + throw new AuthenticationError( + 'Old password and New password should not be same' + ) + } else { + const newHashedPassword = await bcrypt.hashSync(newPassword, 10) + session.run( + `MATCH (user:User {email: $userEmail}) + SET user.password = $newHashedPassword + RETURN user + `, + { + userEmail: user.email, + newHashedPassword + } + ) + session.close() + + return encode(currentUser) + } } } } diff --git a/src/schema.graphql b/src/schema.graphql index 1f9bcb477..127b9ced2 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -6,6 +6,7 @@ type Query { type Mutation { login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! + changePassword(oldPassword:String!, newPassword: String!): String! report(resource: Resource!, description: String): Report } From 8fcefc63bc37d190b404ce93e3b6ffa615b4c43a Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sat, 9 Mar 2019 14:47:12 +0300 Subject: [PATCH 02/13] add changePassword mutation test --- src/resolvers/user_management.spec.js | 314 ++++++++++++++++---------- 1 file changed, 197 insertions(+), 117 deletions(-) diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index a3bf6fdd0..98574f0ac 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -1,9 +1,9 @@ -import Factory from '../seed/factories' -import { GraphQLClient, request } from 'graphql-request' -import jwt from 'jsonwebtoken' -import { host, login } from '../jest/helpers' +import Factory from "../seed/factories"; +import { GraphQLClient, request } from "graphql-request"; +import jwt from "jsonwebtoken"; +import { host, login } from "../jest/helpers"; -const factory = Factory() +const factory = Factory(); // here is the decoded JWT token: // { @@ -21,59 +21,71 @@ const factory = Factory() // iss: 'http://localhost:4000', // sub: 'u3' // } -const jennyRostocksHeaders = { authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' } +const jennyRostocksHeaders = { + authorization: + "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc" +}; beforeEach(async () => { - await factory.create('User', { - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', - id: 'acb2d923-f3af-479e-9f00-61b12e864666', - name: 'Matilde Hermiston', - slug: 'matilde-hermiston', - role: 'user', - email: 'test@example.org', - password: '1234' - }) -}) + await factory.create("User", { + avatar: + "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", + id: "acb2d923-f3af-479e-9f00-61b12e864666", + name: "Matilde Hermiston", + slug: "matilde-hermiston", + role: "user", + email: "test@example.org", + password: "1234" + }); +}); afterEach(async () => { - await factory.cleanDatabase() -}) + await factory.cleanDatabase(); +}); -describe('isLoggedIn', () => { - const query = '{ isLoggedIn }' - describe('unauthenticated', () => { - it('returns false', async () => { - await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false }) - }) - }) +describe("isLoggedIn", () => { + const query = "{ isLoggedIn }"; + describe("unauthenticated", () => { + it("returns false", async () => { + await expect(request(host, query)).resolves.toEqual({ + isLoggedIn: false + }); + }); + }); - describe('with malformed JWT Bearer token', () => { - const headers = { authorization: 'blah' } - const client = new GraphQLClient(host, { headers }) + describe("with malformed JWT Bearer token", () => { + const headers = { authorization: "blah" }; + const client = new GraphQLClient(host, { headers }); - it('returns false', async () => { - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) - }) - }) + it("returns false", async () => { + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: false + }); + }); + }); - describe('with valid JWT Bearer token', () => { - const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) + describe("with valid JWT Bearer token", () => { + const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); - it('returns false', async () => { - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) - }) + it("returns false", async () => { + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: false + }); + }); - describe('and a corresponding user in the database', () => { - it('returns true', async () => { + describe("and a corresponding user in the database", () => { + it("returns true", async () => { // see the decoded token above - await factory.create('User', { id: 'u3' }) - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: true }) - }) - }) - }) -}) + await factory.create("User", { id: "u3" }); + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: true + }); + }); + }); + }); +}); -describe('currentUser', () => { +describe("currentUser", () => { const query = `{ currentUser { id @@ -83,97 +95,165 @@ describe('currentUser', () => { email role } - }` + }`; - describe('unauthenticated', () => { - it('returns null', async () => { - const expected = { currentUser: null } - await expect(request(host, query)).resolves.toEqual(expected) - }) - }) + describe("unauthenticated", () => { + it("returns null", async () => { + const expected = { currentUser: null }; + await expect(request(host, query)).resolves.toEqual(expected); + }); + }); - describe('with valid JWT Bearer Token', () => { - let client - let headers + describe("with valid JWT Bearer Token", () => { + let client; + let headers; - describe('but no corresponding user in the database', () => { + describe("but no corresponding user in the database", () => { beforeEach(async () => { - client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) - }) + client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); + }); - it('returns null', async () => { - const expected = { currentUser: null } - await expect(client.request(query)).resolves.toEqual(expected) - }) - }) + it("returns null", async () => { + const expected = { currentUser: null }; + await expect(client.request(query)).resolves.toEqual(expected); + }); + }); - describe('and corresponding user in the database', () => { + describe("and corresponding user in the database", () => { beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) - }) + headers = await login({ email: "test@example.org", password: "1234" }); + client = new GraphQLClient(host, { headers }); + }); - it('returns the whole user object', async () => { + it("returns the whole user object", async () => { const expected = { currentUser: { - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', - email: 'test@example.org', - id: 'acb2d923-f3af-479e-9f00-61b12e864666', - name: 'Matilde Hermiston', - slug: 'matilde-hermiston', - role: 'user' + avatar: + "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", + email: "test@example.org", + id: "acb2d923-f3af-479e-9f00-61b12e864666", + name: "Matilde Hermiston", + slug: "matilde-hermiston", + role: "user" } - } - await expect(client.request(query)).resolves.toEqual(expected) - }) - }) - }) -}) + }; + await expect(client.request(query)).resolves.toEqual(expected); + }); + }); + }); +}); -describe('login', () => { - const mutation = (params) => { - const { email, password } = params +describe("login", () => { + const mutation = params => { + const { email, password } = params; return ` mutation { login(email:"${email}", password:"${password}") - }` - } + }`; + }; - describe('ask for a `token`', () => { - describe('with valid email/password combination', () => { - it('responds with a JWT token', async () => { - const data = await request(host, mutation({ - email: 'test@example.org', - password: '1234' - })) - const token = data.login + describe("ask for a `token`", () => { + describe("with valid email/password combination", () => { + it("responds with a JWT token", async () => { + const data = await request( + host, + mutation({ + email: "test@example.org", + password: "1234" + }) + ); + const token = data.login; jwt.verify(token, process.env.JWT_SECRET, (err, data) => { - expect(data.email).toEqual('test@example.org') - expect(err).toBeNull() - }) - }) - }) + expect(data.email).toEqual("test@example.org"); + expect(err).toBeNull(); + }); + }); + }); - describe('with a valid email but incorrect password', () => { + describe("with a valid email but incorrect password", () => { it('responds with "Incorrect email address or password."', async () => { await expect( - request(host, mutation({ - email: 'test@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) + request( + host, + mutation({ + email: "test@example.org", + password: "wrong" + }) + ) + ).rejects.toThrow("Incorrect email address or password."); + }); + }); - describe('with a non-existing email', () => { + describe("with a non-existing email", () => { it('responds with "Incorrect email address or password."', async () => { await expect( - request(host, mutation({ - email: 'non-existent@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) - }) -}) + request( + host, + mutation({ + email: "non-existent@example.org", + password: "wrong" + }) + ) + ).rejects.toThrow("Incorrect email address or password."); + }); + }); + }); +}); + +describe("change password", () => { + let headers; + let client; + + beforeEach(async () => { + headers = await login({ email: "test@example.org", password: "1234" }); + client = new GraphQLClient(host, { headers }); + }); + + const mutation = params => { + const { oldPassword, newPassword } = params; + return ` + mutation { + changePassword(oldPassword:"${oldPassword}", newPassword:"${newPassword}") + }`; + }; + + describe("should be authenticated before changing password", () => { + it('should throw not "Not Authorised!', async () => { + await expect( + request( + host, + mutation({ + oldPassword: "1234", + newPassword: "1234" + }) + ) + ).rejects.toThrow("Not Authorised!"); + }); + }); + + describe("old and new password should not match", () => { + it('responds with "Old password and New password should not be same"', async () => { + await expect( + client.request( + mutation({ + oldPassword: "1234", + newPassword: "1234" + }) + ) + ).rejects.toThrow("Old password and New password should not be same"); + }); + }); + + describe("incorrect old password", () => { + it('responds with "Old password isn\'t valid"', async () => { + await expect( + client.request( + mutation({ + oldPassword: "notOldPassword", + newPassword: "12345" + }) + ) + ).rejects.toThrow("Old password isn't valid"); + }); + }); +}); From 82ae81d8fe24f3c88c238d7f9a458145e9fe0ec6 Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sat, 9 Mar 2019 13:36:27 +0300 Subject: [PATCH 03/13] add changePasssword mutation --- src/middleware/permissionsMiddleware.js | 4 +- src/resolvers/user_management.js | 69 ++++++++++++++++++++++--- src/schema.graphql | 1 + 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index 7fb6e75b8..434b97200 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -56,9 +56,9 @@ const permissions = shield({ CreateBadge: isAdmin, UpdateBadge: isAdmin, DeleteBadge: isAdmin, - enable: isModerator, - disable: isModerator + disable: isModerator, + changePassword: isAuthenticated // addFruitToBasket: isAuthenticated // CreateUser: allow, }, diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index ec4ae7ce2..3a7698e24 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -30,22 +30,75 @@ export default { // throw new Error('Already logged in.') // } const session = driver.session() - return session.run( - 'MATCH (user:User {email: $userEmail}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', { - userEmail: email - }) - .then(async (result) => { + return session + .run( + 'MATCH (user:User {email: $userEmail}) ' + + 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', + { + userEmail: email + } + ) + .then(async result => { session.close() const [currentUser] = await result.records.map(function (record) { return record.get('user') }) - if (currentUser && await bcrypt.compareSync(password, currentUser.password)) { + if ( + currentUser && + (await bcrypt.compareSync(password, currentUser.password)) + ) { delete currentUser.password return encode(currentUser) - } else throw new AuthenticationError('Incorrect email address or password.') + } else { + throw new AuthenticationError( + 'Incorrect email address or password.' + ) + } }) + }, + changePassword: async ( + _, + { oldPassword, newPassword }, + { driver, user } + ) => { + const session = driver.session() + let result = await session.run( + `MATCH (user:User {email: $userEmail}) + RETURN user {.id, .email, .password}`, + { + userEmail: user.email + } + ) + + const [currentUser] = result.records.map(function (record) { + return record.get('user') + }) + + if (!(await bcrypt.compareSync(oldPassword, currentUser.password))) { + throw new AuthenticationError('Old password isn\'t valid') + } + + if (await bcrypt.compareSync(newPassword, currentUser.password)) { + throw new AuthenticationError( + 'Old password and New password should not be same' + ) + } else { + const newHashedPassword = await bcrypt.hashSync(newPassword, 10) + session.run( + `MATCH (user:User {email: $userEmail}) + SET user.password = $newHashedPassword + RETURN user + `, + { + userEmail: user.email, + newHashedPassword + } + ) + session.close() + + return encode(currentUser) + } } } } diff --git a/src/schema.graphql b/src/schema.graphql index 0cf099411..b6abd8f81 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -9,6 +9,7 @@ type Mutation { "Get a JWT Token for the given Email and password" login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! + changePassword(oldPassword:String!, newPassword: String!): String! report(resource: Resource!, description: String): Report "Shout the given Type and ID" shout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ From 35339b4674ec46b483f16174554d94d2cd2e4187 Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sat, 9 Mar 2019 14:47:12 +0300 Subject: [PATCH 04/13] add changePassword mutation test --- src/resolvers/user_management.spec.js | 314 ++++++++++++++++---------- 1 file changed, 197 insertions(+), 117 deletions(-) diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index a3bf6fdd0..98574f0ac 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -1,9 +1,9 @@ -import Factory from '../seed/factories' -import { GraphQLClient, request } from 'graphql-request' -import jwt from 'jsonwebtoken' -import { host, login } from '../jest/helpers' +import Factory from "../seed/factories"; +import { GraphQLClient, request } from "graphql-request"; +import jwt from "jsonwebtoken"; +import { host, login } from "../jest/helpers"; -const factory = Factory() +const factory = Factory(); // here is the decoded JWT token: // { @@ -21,59 +21,71 @@ const factory = Factory() // iss: 'http://localhost:4000', // sub: 'u3' // } -const jennyRostocksHeaders = { authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' } +const jennyRostocksHeaders = { + authorization: + "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc" +}; beforeEach(async () => { - await factory.create('User', { - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', - id: 'acb2d923-f3af-479e-9f00-61b12e864666', - name: 'Matilde Hermiston', - slug: 'matilde-hermiston', - role: 'user', - email: 'test@example.org', - password: '1234' - }) -}) + await factory.create("User", { + avatar: + "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", + id: "acb2d923-f3af-479e-9f00-61b12e864666", + name: "Matilde Hermiston", + slug: "matilde-hermiston", + role: "user", + email: "test@example.org", + password: "1234" + }); +}); afterEach(async () => { - await factory.cleanDatabase() -}) + await factory.cleanDatabase(); +}); -describe('isLoggedIn', () => { - const query = '{ isLoggedIn }' - describe('unauthenticated', () => { - it('returns false', async () => { - await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false }) - }) - }) +describe("isLoggedIn", () => { + const query = "{ isLoggedIn }"; + describe("unauthenticated", () => { + it("returns false", async () => { + await expect(request(host, query)).resolves.toEqual({ + isLoggedIn: false + }); + }); + }); - describe('with malformed JWT Bearer token', () => { - const headers = { authorization: 'blah' } - const client = new GraphQLClient(host, { headers }) + describe("with malformed JWT Bearer token", () => { + const headers = { authorization: "blah" }; + const client = new GraphQLClient(host, { headers }); - it('returns false', async () => { - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) - }) - }) + it("returns false", async () => { + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: false + }); + }); + }); - describe('with valid JWT Bearer token', () => { - const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) + describe("with valid JWT Bearer token", () => { + const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); - it('returns false', async () => { - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) - }) + it("returns false", async () => { + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: false + }); + }); - describe('and a corresponding user in the database', () => { - it('returns true', async () => { + describe("and a corresponding user in the database", () => { + it("returns true", async () => { // see the decoded token above - await factory.create('User', { id: 'u3' }) - await expect(client.request(query)).resolves.toEqual({ isLoggedIn: true }) - }) - }) - }) -}) + await factory.create("User", { id: "u3" }); + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: true + }); + }); + }); + }); +}); -describe('currentUser', () => { +describe("currentUser", () => { const query = `{ currentUser { id @@ -83,97 +95,165 @@ describe('currentUser', () => { email role } - }` + }`; - describe('unauthenticated', () => { - it('returns null', async () => { - const expected = { currentUser: null } - await expect(request(host, query)).resolves.toEqual(expected) - }) - }) + describe("unauthenticated", () => { + it("returns null", async () => { + const expected = { currentUser: null }; + await expect(request(host, query)).resolves.toEqual(expected); + }); + }); - describe('with valid JWT Bearer Token', () => { - let client - let headers + describe("with valid JWT Bearer Token", () => { + let client; + let headers; - describe('but no corresponding user in the database', () => { + describe("but no corresponding user in the database", () => { beforeEach(async () => { - client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) - }) + client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); + }); - it('returns null', async () => { - const expected = { currentUser: null } - await expect(client.request(query)).resolves.toEqual(expected) - }) - }) + it("returns null", async () => { + const expected = { currentUser: null }; + await expect(client.request(query)).resolves.toEqual(expected); + }); + }); - describe('and corresponding user in the database', () => { + describe("and corresponding user in the database", () => { beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) - }) + headers = await login({ email: "test@example.org", password: "1234" }); + client = new GraphQLClient(host, { headers }); + }); - it('returns the whole user object', async () => { + it("returns the whole user object", async () => { const expected = { currentUser: { - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', - email: 'test@example.org', - id: 'acb2d923-f3af-479e-9f00-61b12e864666', - name: 'Matilde Hermiston', - slug: 'matilde-hermiston', - role: 'user' + avatar: + "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", + email: "test@example.org", + id: "acb2d923-f3af-479e-9f00-61b12e864666", + name: "Matilde Hermiston", + slug: "matilde-hermiston", + role: "user" } - } - await expect(client.request(query)).resolves.toEqual(expected) - }) - }) - }) -}) + }; + await expect(client.request(query)).resolves.toEqual(expected); + }); + }); + }); +}); -describe('login', () => { - const mutation = (params) => { - const { email, password } = params +describe("login", () => { + const mutation = params => { + const { email, password } = params; return ` mutation { login(email:"${email}", password:"${password}") - }` - } + }`; + }; - describe('ask for a `token`', () => { - describe('with valid email/password combination', () => { - it('responds with a JWT token', async () => { - const data = await request(host, mutation({ - email: 'test@example.org', - password: '1234' - })) - const token = data.login + describe("ask for a `token`", () => { + describe("with valid email/password combination", () => { + it("responds with a JWT token", async () => { + const data = await request( + host, + mutation({ + email: "test@example.org", + password: "1234" + }) + ); + const token = data.login; jwt.verify(token, process.env.JWT_SECRET, (err, data) => { - expect(data.email).toEqual('test@example.org') - expect(err).toBeNull() - }) - }) - }) + expect(data.email).toEqual("test@example.org"); + expect(err).toBeNull(); + }); + }); + }); - describe('with a valid email but incorrect password', () => { + describe("with a valid email but incorrect password", () => { it('responds with "Incorrect email address or password."', async () => { await expect( - request(host, mutation({ - email: 'test@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) + request( + host, + mutation({ + email: "test@example.org", + password: "wrong" + }) + ) + ).rejects.toThrow("Incorrect email address or password."); + }); + }); - describe('with a non-existing email', () => { + describe("with a non-existing email", () => { it('responds with "Incorrect email address or password."', async () => { await expect( - request(host, mutation({ - email: 'non-existent@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) - }) -}) + request( + host, + mutation({ + email: "non-existent@example.org", + password: "wrong" + }) + ) + ).rejects.toThrow("Incorrect email address or password."); + }); + }); + }); +}); + +describe("change password", () => { + let headers; + let client; + + beforeEach(async () => { + headers = await login({ email: "test@example.org", password: "1234" }); + client = new GraphQLClient(host, { headers }); + }); + + const mutation = params => { + const { oldPassword, newPassword } = params; + return ` + mutation { + changePassword(oldPassword:"${oldPassword}", newPassword:"${newPassword}") + }`; + }; + + describe("should be authenticated before changing password", () => { + it('should throw not "Not Authorised!', async () => { + await expect( + request( + host, + mutation({ + oldPassword: "1234", + newPassword: "1234" + }) + ) + ).rejects.toThrow("Not Authorised!"); + }); + }); + + describe("old and new password should not match", () => { + it('responds with "Old password and New password should not be same"', async () => { + await expect( + client.request( + mutation({ + oldPassword: "1234", + newPassword: "1234" + }) + ) + ).rejects.toThrow("Old password and New password should not be same"); + }); + }); + + describe("incorrect old password", () => { + it('responds with "Old password isn\'t valid"', async () => { + await expect( + client.request( + mutation({ + oldPassword: "notOldPassword", + newPassword: "12345" + }) + ) + ).rejects.toThrow("Old password isn't valid"); + }); + }); +}); From 3fbe4cb2e6e32555adb00daf08b2ed0177c800f0 Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sun, 10 Mar 2019 00:48:16 +0300 Subject: [PATCH 05/13] add use single quotes --- src/resolvers/user_management.spec.js | 280 +++++++++++++------------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index 98574f0ac..5aaadfeed 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -1,9 +1,9 @@ -import Factory from "../seed/factories"; -import { GraphQLClient, request } from "graphql-request"; -import jwt from "jsonwebtoken"; -import { host, login } from "../jest/helpers"; +import Factory from '../seed/factories' +import { GraphQLClient, request } from 'graphql-request' +import jwt from 'jsonwebtoken' +import { host, login } from '../jest/helpers' -const factory = Factory(); +const factory = Factory() // here is the decoded JWT token: // { @@ -23,69 +23,69 @@ const factory = Factory(); // } const jennyRostocksHeaders = { authorization: - "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc" -}; + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' +} beforeEach(async () => { - await factory.create("User", { + await factory.create('User', { avatar: - "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", - id: "acb2d923-f3af-479e-9f00-61b12e864666", - name: "Matilde Hermiston", - slug: "matilde-hermiston", - role: "user", - email: "test@example.org", - password: "1234" - }); -}); + 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user', + email: 'test@example.org', + password: '1234' + }) +}) afterEach(async () => { - await factory.cleanDatabase(); -}); + await factory.cleanDatabase() +}) -describe("isLoggedIn", () => { - const query = "{ isLoggedIn }"; - describe("unauthenticated", () => { - it("returns false", async () => { +describe('isLoggedIn', () => { + const query = '{ isLoggedIn }' + describe('unauthenticated', () => { + it('returns false', async () => { await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false - }); - }); - }); + }) + }) + }) - describe("with malformed JWT Bearer token", () => { - const headers = { authorization: "blah" }; - const client = new GraphQLClient(host, { headers }); + describe('with malformed JWT Bearer token', () => { + const headers = { authorization: 'blah' } + const client = new GraphQLClient(host, { headers }) - it("returns false", async () => { + it('returns false', async () => { await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false - }); - }); - }); + }) + }) + }) - describe("with valid JWT Bearer token", () => { - const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); + describe('with valid JWT Bearer token', () => { + const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) - it("returns false", async () => { + it('returns false', async () => { await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false - }); - }); + }) + }) - describe("and a corresponding user in the database", () => { - it("returns true", async () => { + describe('and a corresponding user in the database', () => { + it('returns true', async () => { // see the decoded token above - await factory.create("User", { id: "u3" }); + await factory.create('User', { id: 'u3' }) await expect(client.request(query)).resolves.toEqual({ isLoggedIn: true - }); - }); - }); - }); -}); + }) + }) + }) + }) +}) -describe("currentUser", () => { +describe('currentUser', () => { const query = `{ currentUser { id @@ -95,165 +95,165 @@ describe("currentUser", () => { email role } - }`; + }` - describe("unauthenticated", () => { - it("returns null", async () => { - const expected = { currentUser: null }; - await expect(request(host, query)).resolves.toEqual(expected); - }); - }); + describe('unauthenticated', () => { + it('returns null', async () => { + const expected = { currentUser: null } + await expect(request(host, query)).resolves.toEqual(expected) + }) + }) - describe("with valid JWT Bearer Token", () => { - let client; - let headers; + describe('with valid JWT Bearer Token', () => { + let client + let headers - describe("but no corresponding user in the database", () => { + describe('but no corresponding user in the database', () => { beforeEach(async () => { - client = new GraphQLClient(host, { headers: jennyRostocksHeaders }); - }); + client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) + }) - it("returns null", async () => { - const expected = { currentUser: null }; - await expect(client.request(query)).resolves.toEqual(expected); - }); - }); + it('returns null', async () => { + const expected = { currentUser: null } + await expect(client.request(query)).resolves.toEqual(expected) + }) + }) - describe("and corresponding user in the database", () => { + describe('and corresponding user in the database', () => { beforeEach(async () => { - headers = await login({ email: "test@example.org", password: "1234" }); - client = new GraphQLClient(host, { headers }); - }); + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) - it("returns the whole user object", async () => { + it('returns the whole user object', async () => { const expected = { currentUser: { avatar: - "https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg", - email: "test@example.org", - id: "acb2d923-f3af-479e-9f00-61b12e864666", - name: "Matilde Hermiston", - slug: "matilde-hermiston", - role: "user" + 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', + email: 'test@example.org', + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user' } - }; - await expect(client.request(query)).resolves.toEqual(expected); - }); - }); - }); -}); + } + await expect(client.request(query)).resolves.toEqual(expected) + }) + }) + }) +}) -describe("login", () => { +describe('login', () => { const mutation = params => { - const { email, password } = params; + const { email, password } = params return ` mutation { login(email:"${email}", password:"${password}") - }`; - }; + }` + } - describe("ask for a `token`", () => { - describe("with valid email/password combination", () => { - it("responds with a JWT token", async () => { + describe('ask for a `token`', () => { + describe('with valid email/password combination', () => { + it('responds with a JWT token', async () => { const data = await request( host, mutation({ - email: "test@example.org", - password: "1234" + email: 'test@example.org', + password: '1234' }) - ); - const token = data.login; + ) + const token = data.login jwt.verify(token, process.env.JWT_SECRET, (err, data) => { - expect(data.email).toEqual("test@example.org"); - expect(err).toBeNull(); - }); - }); - }); + expect(data.email).toEqual('test@example.org') + expect(err).toBeNull() + }) + }) + }) - describe("with a valid email but incorrect password", () => { + describe('with a valid email but incorrect password', () => { it('responds with "Incorrect email address or password."', async () => { await expect( request( host, mutation({ - email: "test@example.org", - password: "wrong" + email: 'test@example.org', + password: 'wrong' }) ) - ).rejects.toThrow("Incorrect email address or password."); - }); - }); + ).rejects.toThrow('Incorrect email address or password.') + }) + }) - describe("with a non-existing email", () => { + describe('with a non-existing email', () => { it('responds with "Incorrect email address or password."', async () => { await expect( request( host, mutation({ - email: "non-existent@example.org", - password: "wrong" + email: 'non-existent@example.org', + password: 'wrong' }) ) - ).rejects.toThrow("Incorrect email address or password."); - }); - }); - }); -}); + ).rejects.toThrow('Incorrect email address or password.') + }) + }) + }) +}) -describe("change password", () => { - let headers; - let client; +describe('change password', () => { + let headers + let client beforeEach(async () => { - headers = await login({ email: "test@example.org", password: "1234" }); - client = new GraphQLClient(host, { headers }); - }); + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) const mutation = params => { - const { oldPassword, newPassword } = params; + const { oldPassword, newPassword } = params return ` mutation { changePassword(oldPassword:"${oldPassword}", newPassword:"${newPassword}") - }`; - }; + }` + } - describe("should be authenticated before changing password", () => { + describe('should be authenticated before changing password', () => { it('should throw not "Not Authorised!', async () => { await expect( request( host, mutation({ - oldPassword: "1234", - newPassword: "1234" + oldPassword: '1234', + newPassword: '1234' }) ) - ).rejects.toThrow("Not Authorised!"); - }); - }); + ).rejects.toThrow('Not Authorised!') + }) + }) - describe("old and new password should not match", () => { + describe('old and new password should not match', () => { it('responds with "Old password and New password should not be same"', async () => { await expect( client.request( mutation({ - oldPassword: "1234", - newPassword: "1234" + oldPassword: '1234', + newPassword: '1234' }) ) - ).rejects.toThrow("Old password and New password should not be same"); - }); - }); + ).rejects.toThrow('Old password and New password should not be same') + }) + }) - describe("incorrect old password", () => { + describe('incorrect old password', () => { it('responds with "Old password isn\'t valid"', async () => { await expect( client.request( mutation({ - oldPassword: "notOldPassword", - newPassword: "12345" + oldPassword: 'notOldPassword', + newPassword: '12345' }) ) - ).rejects.toThrow("Old password isn't valid"); - }); - }); -}); + ).rejects.toThrow('Old password isn\'t valid') + }) + }) +}) From 6cba9f1fd8f584b5b53ecaf32f3feac276f99b99 Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sun, 10 Mar 2019 00:50:16 +0300 Subject: [PATCH 06/13] remove image url --- src/resolvers/user_management.spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index 5aaadfeed..8007737f0 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -28,8 +28,6 @@ const jennyRostocksHeaders = { beforeEach(async () => { await factory.create('User', { - avatar: - 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', id: 'acb2d923-f3af-479e-9f00-61b12e864666', name: 'Matilde Hermiston', slug: 'matilde-hermiston', From 0a31e5278c35911691bac5d24a500178027f262f Mon Sep 17 00:00:00 2001 From: kachulio1 Date: Sun, 10 Mar 2019 01:44:41 +0300 Subject: [PATCH 07/13] add test for correct credentials --- src/resolvers/user_management.js | 50 ++++++++++++--------------- src/resolvers/user_management.spec.js | 28 +++++++++++---- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index 3a7698e24..36865646f 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -30,32 +30,28 @@ export default { // throw new Error('Already logged in.') // } const session = driver.session() - return session - .run( - 'MATCH (user:User {email: $userEmail}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', - { - userEmail: email - } - ) - .then(async result => { - session.close() - const [currentUser] = await result.records.map(function (record) { - return record.get('user') - }) + const result = await session.run( + 'MATCH (user:User {email: $userEmail}) ' + + 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', + { + userEmail: email + } + ) - if ( - currentUser && - (await bcrypt.compareSync(password, currentUser.password)) - ) { - delete currentUser.password - return encode(currentUser) - } else { - throw new AuthenticationError( - 'Incorrect email address or password.' - ) - } - }) + session.close() + const [currentUser] = await result.records.map(function (record) { + return record.get('user') + }) + + if ( + currentUser && + (await bcrypt.compareSync(password, currentUser.password)) + ) { + delete currentUser.password + return encode(currentUser) + } else { + throw new AuthenticationError('Incorrect email address or password.') + } }, changePassword: async ( _, @@ -76,12 +72,12 @@ export default { }) if (!(await bcrypt.compareSync(oldPassword, currentUser.password))) { - throw new AuthenticationError('Old password isn\'t valid') + throw new AuthenticationError('Old password is not correct') } if (await bcrypt.compareSync(newPassword, currentUser.password)) { throw new AuthenticationError( - 'Old password and New password should not be same' + 'Old password and new password should be different' ) } else { const newHashedPassword = await bcrypt.hashSync(newPassword, 10) diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index 8007737f0..c4b09df37 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -28,6 +28,7 @@ const jennyRostocksHeaders = { beforeEach(async () => { await factory.create('User', { + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', id: 'acb2d923-f3af-479e-9f00-61b12e864666', name: 'Matilde Hermiston', slug: 'matilde-hermiston', @@ -126,8 +127,7 @@ describe('currentUser', () => { it('returns the whole user object', async () => { const expected = { currentUser: { - avatar: - 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', email: 'test@example.org', id: 'acb2d923-f3af-479e-9f00-61b12e864666', name: 'Matilde Hermiston', @@ -216,7 +216,7 @@ describe('change password', () => { } describe('should be authenticated before changing password', () => { - it('should throw not "Not Authorised!', async () => { + it('throws not "Not Authorised!', async () => { await expect( request( host, @@ -230,7 +230,7 @@ describe('change password', () => { }) describe('old and new password should not match', () => { - it('responds with "Old password and New password should not be same"', async () => { + it('responds with "Old password and new password should be different"', async () => { await expect( client.request( mutation({ @@ -238,7 +238,7 @@ describe('change password', () => { newPassword: '1234' }) ) - ).rejects.toThrow('Old password and New password should not be same') + ).rejects.toThrow('Old password and new password should be different') }) }) @@ -251,7 +251,23 @@ describe('change password', () => { newPassword: '12345' }) ) - ).rejects.toThrow('Old password isn\'t valid') + ).rejects.toThrow('Old password is not correct') + }) + }) + + describe('correct password', () => { + it('changes the password if given correct credentials "', async () => { + let response = await client.request( + mutation({ + oldPassword: '1234', + newPassword: '12345' + }) + ) + await expect( + response + ).toEqual(expect.objectContaining({ + changePassword: expect.any(String) + })) }) }) }) From 22b521b93db3d20a190e2715688887f6228a93cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 11 Mar 2019 17:02:31 +0100 Subject: [PATCH 08/13] Deleted a line in graphql.schema --- src/schema.graphql | 1 - 1 file changed, 1 deletion(-) diff --git a/src/schema.graphql b/src/schema.graphql index a542e1229..06a53afba 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -26,7 +26,6 @@ type Mutation { DELETE r RETURN COUNT(r) > 0 """) - "Follow the given Type and ID" follow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) From 460f94ea3f37929e27398abe9c65487a75851b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 13 Mar 2019 14:32:15 +0100 Subject: [PATCH 09/13] Add unauthenticated test to follow and shout close #234 --- src/middleware/permissionsMiddleware.js | 5 +- src/resolvers/follow.spec.js | 86 +++++++++++------ src/resolvers/shout.spec.js | 121 ++++++++++++++---------- 3 files changed, 132 insertions(+), 80 deletions(-) diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index 7fb6e75b8..08feb1e5e 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -56,10 +56,13 @@ const permissions = shield({ CreateBadge: isAdmin, UpdateBadge: isAdmin, DeleteBadge: isAdmin, + follow: isAuthenticated, + unfollow: isAuthenticated, + shout: isAuthenticated, + unshout: isAuthenticated, enable: isModerator, disable: isModerator - // addFruitToBasket: isAuthenticated // CreateUser: allow, }, User: { diff --git a/src/resolvers/follow.spec.js b/src/resolvers/follow.spec.js index 3c16560e5..081e49081 100644 --- a/src/resolvers/follow.spec.js +++ b/src/resolvers/follow.spec.js @@ -4,6 +4,7 @@ import { host, login } from '../jest/helpers' const factory = Factory() let clientUser1 +let headersUser1 const mutationFollowUser = (id) => ` mutation { @@ -27,18 +28,25 @@ beforeEach(async () => { email: 'test2@example.org', password: '1234' }) + + headersUser1 = await login({ email: 'test@example.org', password: '1234' }) + clientUser1 = new GraphQLClient(host, { headers: headersUser1 }) }) afterEach(async () => { await factory.cleanDatabase() }) -describe('follow ', () => { - describe('(un)follow user', () => { - let headersUser1 - beforeEach(async () => { - headersUser1 = await login({ email: 'test@example.org', password: '1234' }) - clientUser1 = new GraphQLClient(host, { headers: headersUser1 }) +describe('follow', () => { + describe('follow user', () => { + describe('unauthenticated follow', () => { + it('throws authorization error', async () => { + let client + client = new GraphQLClient(host) + await expect( + client.request(mutationFollowUser('u2')) + ).rejects.toThrow('Not Authorised') + }) }) it('I can follow another user', async () => { @@ -65,31 +73,6 @@ describe('follow ', () => { expect(User[0]).toMatchObject(expected2) }) - it('I can unfollow a user', async () => { - // follow - await clientUser1.request( - mutationFollowUser('u2') - ) - const expected = { - unfollow: true - } - // unfollow - const res = await clientUser1.request(mutationUnfollowUser('u2')) - expect(res).toMatchObject(expected) - - const { User } = await clientUser1.request(`{ - User(id: "u2") { - followedBy { id } - followedByCurrentUser - } - }`) - const expected2 = { - followedBy: [], - followedByCurrentUser: false - } - expect(User[0]).toMatchObject(expected2) - }) - it('I can`t follow myself', async () => { const res = await clientUser1.request( mutationFollowUser('u1') @@ -112,4 +95,45 @@ describe('follow ', () => { expect(User[0]).toMatchObject(expected2) }) }) + describe('unfollow user', () => { + describe('unauthenticated follow', () => { + it('throws authorization error', async () => { + // follow + await clientUser1.request( + mutationFollowUser('u2') + ) + // unfollow + let client + client = new GraphQLClient(host) + await expect( + client.request(mutationUnfollowUser('u2')) + ).rejects.toThrow('Not Authorised') + }) + }) + + it('I can unfollow a user', async () => { + // follow + await clientUser1.request( + mutationFollowUser('u2') + ) + // unfollow + const expected = { + unfollow: true + } + const res = await clientUser1.request(mutationUnfollowUser('u2')) + expect(res).toMatchObject(expected) + + const { User } = await clientUser1.request(`{ + User(id: "u2") { + followedBy { id } + followedByCurrentUser + } + }`) + const expected2 = { + followedBy: [], + followedByCurrentUser: false + } + expect(User[0]).toMatchObject(expected2) + }) + }) }) diff --git a/src/resolvers/shout.spec.js b/src/resolvers/shout.spec.js index 490191c7a..88866a74f 100644 --- a/src/resolvers/shout.spec.js +++ b/src/resolvers/shout.spec.js @@ -4,6 +4,7 @@ import { host, login } from '../jest/helpers' const factory = Factory() let clientUser1, clientUser2 +let headersUser1, headersUser2 const mutationShoutPost = (id) => ` mutation { @@ -27,37 +28,44 @@ beforeEach(async () => { email: 'test2@example.org', password: '1234' }) + + headersUser1 = await login({ email: 'test@example.org', password: '1234' }) + headersUser2 = await login({ email: 'test2@example.org', password: '1234' }) + clientUser1 = new GraphQLClient(host, { headers: headersUser1 }) + clientUser2 = new GraphQLClient(host, { headers: headersUser2 }) + + await clientUser1.request(` + mutation { + CreatePost(id: "p1", title: "Post Title 1", content: "Some Post Content 1") { + id + title + } + } + `) + await clientUser2.request(` + mutation { + CreatePost(id: "p2", title: "Post Title 2", content: "Some Post Content 2") { + id + title + } + } + `) }) afterEach(async () => { await factory.cleanDatabase() }) -describe('shout ', () => { - describe('(un)shout foreign post', () => { - let headersUser1, headersUser2 - beforeEach(async () => { - headersUser1 = await login({ email: 'test@example.org', password: '1234' }) - headersUser2 = await login({ email: 'test2@example.org', password: '1234' }) - clientUser1 = new GraphQLClient(host, { headers: headersUser1 }) - clientUser2 = new GraphQLClient(host, { headers: headersUser2 }) - - await clientUser1.request(` - mutation { - CreatePost(id: "p1", title: "Post Title 1", content: "Some Post Content 1") { - id - title - } - } - `) - await clientUser2.request(` - mutation { - CreatePost(id: "p2", title: "Post Title 2", content: "Some Post Content 2") { - id - title - } - } - `) +describe('shout', () => { + describe('shout foreign post', () => { + describe('unauthenticated shout', () => { + it('throws authorization error', async () => { + let client + client = new GraphQLClient(host) + await expect( + client.request(mutationShoutPost('p1')) + ).rejects.toThrow('Not Authorised') + }) }) it('I shout a post of another user', async () => { @@ -80,29 +88,6 @@ describe('shout ', () => { expect(Post[0]).toMatchObject(expected2) }) - it('I unshout a post of another user', async () => { - // shout - await clientUser1.request( - mutationShoutPost('p2') - ) - const expected = { - unshout: true - } - // unshout - const res = await clientUser1.request(mutationUnshoutPost('p2')) - expect(res).toMatchObject(expected) - - const { Post } = await clientUser1.request(`{ - Post(id: "p2") { - shoutedByCurrentUser - } - }`) - const expected2 = { - shoutedByCurrentUser: false - } - expect(Post[0]).toMatchObject(expected2) - }) - it('I can`t shout my own post', async () => { const res = await clientUser1.request( mutationShoutPost('p1') @@ -123,4 +108,44 @@ describe('shout ', () => { expect(Post[0]).toMatchObject(expected2) }) }) + + describe('unshout foreign post', () => { + describe('unauthenticated shout', () => { + it('throws authorization error', async () => { + // shout + await clientUser1.request( + mutationShoutPost('p2') + ) + // unshout + let client + client = new GraphQLClient(host) + await expect( + client.request(mutationUnshoutPost('p2')) + ).rejects.toThrow('Not Authorised') + }) + }) + + it('I unshout a post of another user', async () => { + // shout + await clientUser1.request( + mutationShoutPost('p2') + ) + const expected = { + unshout: true + } + // unshout + const res = await clientUser1.request(mutationUnshoutPost('p2')) + expect(res).toMatchObject(expected) + + const { Post } = await clientUser1.request(`{ + Post(id: "p2") { + shoutedByCurrentUser + } + }`) + const expected2 = { + shoutedByCurrentUser: false + } + expect(Post[0]).toMatchObject(expected2) + }) + }) }) From e9e0c84cb2776f60aa8ad068ae38e537ee559f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 13 Mar 2019 16:48:56 +0100 Subject: [PATCH 10/13] Fixed merge error CC @Lulalaby --- src/schema.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schema.graphql b/src/schema.graphql index 752532d8b..4e0347cc7 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -10,7 +10,7 @@ type Mutation { login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! changePassword(oldPassword:String!, newPassword: String!): String! - report(resource: Resource!, description: String): Report + report(id: ID!, description: String): Report disable(id: ID!): ID enable(id: ID!): ID "Shout the given Type and ID" From 57fc99fc3f5b76be6c9531025f83c4a2059d2030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 13 Mar 2019 17:01:49 +0100 Subject: [PATCH 11/13] Fix merge error again cc @Lulaby pay attention when merging `master` --- src/middleware/permissionsMiddleware.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index 9e1bc6fbe..62999c235 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -56,8 +56,6 @@ const permissions = shield({ CreateBadge: isAdmin, UpdateBadge: isAdmin, DeleteBadge: isAdmin, - enable: isModerator, - disable: isModerator, // addFruitToBasket: isAuthenticated follow: isAuthenticated, unfollow: isAuthenticated, From e6d51d04bc4ba41d905c8346112b44e3e8ce167c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 13 Mar 2019 16:27:59 +0000 Subject: [PATCH 12/13] Bump babel-jest from 24.3.1 to 24.5.0 Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 24.3.1 to 24.5.0. - [Release notes](https://github.com/facebook/jest/releases) - [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/facebook/jest/commits/v24.5.0/packages/babel-jest) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 122 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 106 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index fc789e20d..c785fe5ce 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "apollo-server-testing": "~2.4.8", "babel-core": "~7.0.0-0", "babel-eslint": "~10.0.1", - "babel-jest": "~24.3.1", + "babel-jest": "~24.5.0", "chai": "~4.2.0", "eslint": "~5.15.1", "eslint-config-standard": "~12.0.0", diff --git a/yarn.lock b/yarn.lock index 6a9739214..47dc152cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -802,6 +802,16 @@ jest-message-util "^24.3.0" jest-mock "^24.3.0" +"@jest/fake-timers@^24.5.0": + version "24.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.5.0.tgz#4a29678b91fd0876144a58f8d46e6c62de0266f0" + integrity sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw== + dependencies: + "@jest/types" "^24.5.0" + "@types/node" "*" + jest-message-util "^24.5.0" + jest-mock "^24.5.0" + "@jest/reporters@^24.3.1": version "24.3.1" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.3.1.tgz#68e4abc8d4233acd0dd87287f3bd270d81066248" @@ -846,31 +856,40 @@ "@jest/types" "^24.3.0" "@types/istanbul-lib-coverage" "^1.1.0" -"@jest/transform@^24.3.1": - version "24.3.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.3.1.tgz#ce9e1329eb5e640f493bcd5c8eb9970770959bfc" - integrity sha512-PpjylI5goT4Si69+qUjEeHuKjex0LjjrqJzrMYzlOZn/+SCumGKuGC0UQFeEPThyGsFvWH1Q4gj0R66eOHnIpw== +"@jest/test-result@^24.5.0": + version "24.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.5.0.tgz#ab66fb7741a04af3363443084e72ea84861a53f2" + integrity sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A== + dependencies: + "@jest/console" "^24.3.0" + "@jest/types" "^24.5.0" + "@types/istanbul-lib-coverage" "^1.1.0" + +"@jest/transform@^24.3.1", "@jest/transform@^24.5.0": + version "24.5.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.5.0.tgz#6709fc26db918e6af63a985f2cc3c464b4cf99d9" + integrity sha512-XSsDz1gdR/QMmB8UCKlweAReQsZrD/DK7FuDlNo/pE8EcKMrfi2kqLRk8h8Gy/PDzgqJj64jNEzOce9pR8oj1w== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^24.3.0" + "@jest/types" "^24.5.0" babel-plugin-istanbul "^5.1.0" chalk "^2.0.1" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.1.15" - jest-haste-map "^24.3.1" + jest-haste-map "^24.5.0" jest-regex-util "^24.3.0" - jest-util "^24.3.0" + jest-util "^24.5.0" micromatch "^3.1.10" realpath-native "^1.1.0" slash "^2.0.0" source-map "^0.6.1" write-file-atomic "2.4.1" -"@jest/types@^24.3.0": - version "24.3.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.3.0.tgz#3f6e117e47248a9a6b5f1357ec645bd364f7ad23" - integrity sha512-VoO1F5tU2n/93QN/zaZ7Q8SeV/Rj+9JJOgbvKbBwy4lenvmdj1iDaQEPXGTKrO6OSvDeb2drTFipZJYxgo6kIQ== +"@jest/types@^24.3.0", "@jest/types@^24.5.0": + version "24.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.5.0.tgz#feee214a4d0167b0ca447284e95a57aa10b3ee95" + integrity sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA== dependencies: "@types/istanbul-lib-coverage" "^1.1.0" "@types/yargs" "^12.0.9" @@ -1702,13 +1721,13 @@ babel-eslint@~10.0.1: eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" -babel-jest@^24.3.1, babel-jest@~24.3.1: - version "24.3.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.3.1.tgz#168468a37e90426520c5293da4f55e1a512063b0" - integrity sha512-6KaXyUevY0KAxD5Ba+EBhyfwvc+R2f7JV7BpBZ5T8yJGgj0M1hYDfRhDq35oD5MzprMf/ggT81nEuLtMyxfDIg== +babel-jest@^24.3.1, babel-jest@~24.5.0: + version "24.5.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.5.0.tgz#0ea042789810c2bec9065f7c8ab4dc18e1d28559" + integrity sha512-0fKCXyRwxFTJL0UXDJiT2xYxO9Lu2vBd9n+cC+eDjESzcVG3s2DRGAxbzJX21fceB1WYoBjAh8pQ83dKcl003g== dependencies: - "@jest/transform" "^24.3.1" - "@jest/types" "^24.3.0" + "@jest/transform" "^24.5.0" + "@jest/types" "^24.5.0" "@types/babel__core" "^7.1.0" babel-plugin-istanbul "^5.1.0" babel-preset-jest "^24.3.0" @@ -4325,6 +4344,21 @@ jest-haste-map@^24.3.1: micromatch "^3.1.10" sane "^4.0.3" +jest-haste-map@^24.5.0: + version "24.5.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.5.0.tgz#3f17d0c548b99c0c96ed2893f9c0ccecb2eb9066" + integrity sha512-mb4Yrcjw9vBgSvobDwH8QUovxApdimGcOkp+V1ucGGw4Uvr3VzZQBJhNm1UY3dXYm4XXyTW2G7IBEZ9pM2ggRQ== + dependencies: + "@jest/types" "^24.5.0" + fb-watchman "^2.0.0" + graceful-fs "^4.1.15" + invariant "^2.2.4" + jest-serializer "^24.4.0" + jest-util "^24.5.0" + jest-worker "^24.4.0" + micromatch "^3.1.10" + sane "^4.0.3" + jest-jasmine2@^24.3.1: version "24.3.1" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.3.1.tgz#127d628d3ac0829bd3c0fccacb87193e543b420b" @@ -4378,6 +4412,20 @@ jest-message-util@^24.3.0: slash "^2.0.0" stack-utils "^1.0.1" +jest-message-util@^24.5.0: + version "24.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.5.0.tgz#181420a65a7ef2e8b5c2f8e14882c453c6d41d07" + integrity sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/test-result" "^24.5.0" + "@jest/types" "^24.5.0" + "@types/stack-utils" "^1.0.1" + chalk "^2.0.1" + micromatch "^3.1.10" + slash "^2.0.0" + stack-utils "^1.0.1" + jest-mock@^24.3.0: version "24.3.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.3.0.tgz#95a86b6ad474e3e33227e6dd7c4ff6b07e18d3cb" @@ -4385,6 +4433,13 @@ jest-mock@^24.3.0: dependencies: "@jest/types" "^24.3.0" +jest-mock@^24.5.0: + version "24.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.5.0.tgz#976912c99a93f2a1c67497a9414aa4d9da4c7b76" + integrity sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw== + dependencies: + "@jest/types" "^24.5.0" + jest-regex-util@^24.3.0: version "24.3.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36" @@ -4468,6 +4523,11 @@ jest-serializer@^24.3.0: resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.3.0.tgz#074e307300d1451617cf2630d11543ee4f74a1c8" integrity sha512-RiSpqo2OFbVLJN/PgAOwQIUeHDfss6NBUDTLhjiJM8Bb5rMrwRqHfkaqahIsOf9cXXB5UjcqDCzbQ7AIoMqWkg== +jest-serializer@^24.4.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3" + integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q== + jest-snapshot@^24.3.1: version "24.3.1" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.3.1.tgz#0f22a86c1b8c87e823f5ad095e82c19d9ed93d72" @@ -4505,6 +4565,25 @@ jest-util@^24.3.0: slash "^2.0.0" source-map "^0.6.0" +jest-util@^24.5.0: + version "24.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.5.0.tgz#9d9cb06d9dcccc8e7cc76df91b1635025d7baa84" + integrity sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q== + dependencies: + "@jest/console" "^24.3.0" + "@jest/fake-timers" "^24.5.0" + "@jest/source-map" "^24.3.0" + "@jest/test-result" "^24.5.0" + "@jest/types" "^24.5.0" + "@types/node" "*" + callsites "^3.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.15" + is-ci "^2.0.0" + mkdirp "^0.5.1" + slash "^2.0.0" + source-map "^0.6.0" + jest-validate@^24.3.1: version "24.3.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.3.1.tgz#9359eea5a767a3d20b4fa7a5764fd78330ba8312" @@ -4540,6 +4619,15 @@ jest-worker@^24.3.1: merge-stream "^1.0.1" supports-color "^6.1.0" +jest-worker@^24.4.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.4.0.tgz#fbc452b0120bb5c2a70cdc88fa132b48eeb11dd0" + integrity sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ== + dependencies: + "@types/node" "*" + merge-stream "^1.0.1" + supports-color "^6.1.0" + jest@~24.3.1: version "24.3.1" resolved "https://registry.yarnpkg.com/jest/-/jest-24.3.1.tgz#81959de0d57b2df923510f4fafe266712d37dcca" From 412f220dba4a838acf6c7e6a2b323ffc765d1272 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 13 Mar 2019 16:28:31 +0000 Subject: [PATCH 13/13] Bump eslint-plugin-jest from 22.3.0 to 22.3.2 Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 22.3.0 to 22.3.2. - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases) - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v22.3.0...v22.3.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fc789e20d..03ee9af5f 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "eslint": "~5.15.1", "eslint-config-standard": "~12.0.0", "eslint-plugin-import": "~2.16.0", - "eslint-plugin-jest": "~22.3.0", + "eslint-plugin-jest": "~22.3.2", "eslint-plugin-node": "~8.0.1", "eslint-plugin-promise": "~4.0.1", "eslint-plugin-standard": "~4.0.0", diff --git a/yarn.lock b/yarn.lock index 6a9739214..f9e75ab16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2748,10 +2748,10 @@ eslint-plugin-import@~2.16.0: read-pkg-up "^2.0.0" resolve "^1.9.0" -eslint-plugin-jest@~22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.3.0.tgz#a10f10dedfc92def774ec9bb5bfbd2fb8e1c96d2" - integrity sha512-P1mYVRNlOEoO5T9yTqOfucjOYf1ktmJ26NjwjH8sxpCFQa6IhBGr5TpKl3hcAAT29hOsRJVuMWmTsHoUVo9FoA== +eslint-plugin-jest@~22.3.2: + version "22.3.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.3.2.tgz#702ac04b06223c9241d92b986165318db474ca81" + integrity sha512-K1i3qORvcX2VuGLI4N+slreGpeObAWkT5gi1ya8olZ6YXwnxzBrMlif3uEUHgXwPIStpO26vAlRX0SgFy8SkZA== eslint-plugin-node@~8.0.1: version "8.0.1"