From 83b36e8e351a95f5be9276c18579e574c4e8edfb Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Sun, 3 Mar 2019 15:55:11 +0100 Subject: [PATCH 01/10] Output distinct counts --- src/schema.graphql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/schema.graphql b/src/schema.graphql index 1f9bcb477..20a0b3652 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -84,13 +84,13 @@ type User { updatedAt: String friends: [User]! @relation(name: "FRIENDS", direction: "BOTH") - friendsCount: Int! @cypher(statement: "MATCH (this)<-[:FRIENDS]->(r:User) RETURN COUNT(r)") + friendsCount: Int! @cypher(statement: "MATCH (this)<-[:FRIENDS]->(r:User) RETURN COUNT(DISTINCT r)") following: [User]! @relation(name: "FOLLOWS", direction: "OUT") - followingCount: Int! @cypher(statement: "MATCH (this)-[:FOLLOWS]->(r:User) RETURN COUNT(r)") + followingCount: Int! @cypher(statement: "MATCH (this)-[:FOLLOWS]->(r:User) RETURN COUNT(DISTINCT r)") followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN") - followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(r)") + followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)") #contributions: [WrittenPost]! #contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]! @@ -109,7 +109,7 @@ type User { commentsCount: Int! @cypher(statement: "MATCH (this)-[:WROTE]->(r:Comment) WHERE NOT r.deleted = true RETURN COUNT(r)") shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT") - shoutedCount: Int! @cypher(statement: "MATCH (this)-[:SHOUTED]->(r:Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(r)") + shoutedCount: Int! @cypher(statement: "MATCH (this)-[:SHOUTED]->(r:Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)") organizationsCreated: [Organization] @relation(name: "CREATED_ORGA", direction: "OUT") organizationsOwned: [Organization] @relation(name: "OWNING_ORGA", direction: "OUT") @@ -149,7 +149,7 @@ type Post { commentsCount: Int! @cypher(statement: "MATCH (this)<-[:COMMENTS]-(r:Comment) RETURN COUNT(r)") shoutedBy: [User]! @relation(name: "SHOUTED", direction: "IN") - shoutedCount: Int! @cypher(statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(r)") + shoutedCount: Int! @cypher(statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)") } type Comment { @@ -223,7 +223,7 @@ type Tag { name: String! taggedPosts: [Post]! @relation(name: "TAGGED", direction: "IN") taggedOrganizations: [Organization]! @relation(name: "TAGGED", direction: "IN") - taggedCount: Int! @cypher(statement: "MATCH (this)<-[:TAGGED]-(p) RETURN COUNT(p)") + taggedCount: Int! @cypher(statement: "MATCH (this)<-[:TAGGED]-(p) RETURN COUNT(DISTINCT p)") taggedCountUnique: Int! @cypher(statement: "MATCH (this)<-[:TAGGED]-(p)<-[:WROTE]-(u:User) RETURN COUNT(DISTINCT u)") deleted: Boolean disabled: Boolean From 257183ac3f4e702f56063ebea206d7fb7795d84d Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Sun, 3 Mar 2019 19:29:25 +0100 Subject: [PATCH 02/10] added currentUserId to cypher params --- package.json | 2 +- src/server.js | 5 ++++- yarn.lock | 52 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 570841630..2d6696164 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "lodash": "~4.17.11", "ms": "~2.1.1", "neo4j-driver": "~1.7.2", - "neo4j-graphql-js": "~2.3.1", + "neo4j-graphql-js": "~2.4.1", "node-fetch": "~2.3.0", "npm-run-all": "~4.1.5", "sanitize-html": "~1.20.0", diff --git a/src/server.js b/src/server.js index 2fc3af871..8e1cd36da 100644 --- a/src/server.js +++ b/src/server.js @@ -45,7 +45,10 @@ const createServer = (options) => { return { driver, user, - req: request + req: request, + cypherParams: { + currentUserId: user ? user.id : null + } } }, schema: schema, diff --git a/yarn.lock b/yarn.lock index fd3c53297..5e59726cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1092,6 +1092,14 @@ apollo-env@0.3.3: core-js "3.0.0-beta.13" node-fetch "^2.2.0" +apollo-errors@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/apollo-errors/-/apollo-errors-1.9.0.tgz#f1ed0ca0a6be5cd2f24e2eaa7b0860a10146ff51" + integrity sha512-XVukHd0KLvgY6tNjsPS3/Re3U6RQlTKrTbIpqqeTMo2N34uQMr+H1UheV21o8hOZBAFosvBORVricJiP5vfmrw== + dependencies: + assert "^1.4.1" + extendable-error "^0.1.5" + apollo-graphql@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.1.1.tgz#dc5eac3062abf9f063ac9869f0ef5c54fdc136e5" @@ -1378,6 +1386,13 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +assert@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -2800,6 +2815,11 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +extendable-error@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/extendable-error/-/extendable-error-0.1.5.tgz#122308a7097bc89a263b2c4fbf089c78140e3b6d" + integrity sha1-EiMIpwl7yJomOyxPvwiceBQOO20= + external-editor@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" @@ -3155,6 +3175,15 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +graphql-auth-directives@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/graphql-auth-directives/-/graphql-auth-directives-2.1.0.tgz#85b83817844e2ec5fba8fe5de444287d6dd0f85a" + integrity sha512-mRVsjeMeMABPyjxyzl9mhkcW02YBwSj7dnu7C6wy2dIhiby6xTKy6Q54C8KeqXSYsy6ua4VmBH++d7GKqpvIoA== + dependencies: + apollo-errors "^1.9.0" + graphql-tools "^4.0.4" + jsonwebtoken "^8.3.0" + graphql-custom-directives@~0.2.14: version "0.2.14" resolved "https://registry.yarnpkg.com/graphql-custom-directives/-/graphql-custom-directives-0.2.14.tgz#88611b8cb074477020ad85af47bfe168c4c23992" @@ -3588,6 +3617,11 @@ inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -4432,7 +4466,7 @@ jsonify@~0.0.0: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= -jsonwebtoken@~8.5.0: +jsonwebtoken@^8.3.0, jsonwebtoken@~8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#ebd0ca2a69797816e1c5af65b6c759787252947e" integrity sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA== @@ -4941,12 +4975,13 @@ neo4j-driver@^1.7.2, neo4j-driver@~1.7.2: text-encoding "^0.6.4" uri-js "^4.2.1" -neo4j-graphql-js@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/neo4j-graphql-js/-/neo4j-graphql-js-2.3.1.tgz#9a5de7e312594d63481e947a0cbe4e08b05ffed3" - integrity sha512-9DExWXD2vFdDJOmqorT1ygFOUEos7KF8KyF8Wt3jYxejWUuq+a5fAFBu7+YDH8QbvA23paKPEX0Pn1nS+Q5C1A== +neo4j-graphql-js@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/neo4j-graphql-js/-/neo4j-graphql-js-2.4.1.tgz#a1de65340fb6f1ad0ae6aadab90a0bb78b490b32" + integrity sha512-Py6RJuMT7A03Hzoo6qfKyo6DUnHQgbZlBcgucnhgQjbeysAzvM3F02UAVn/HxEtOgowAeGWjyjJvwozoNtiiqQ== dependencies: graphql "^14.0.2" + graphql-auth-directives "^2.0.0" lodash "^4.17.11" neo4j-driver "^1.7.2" @@ -6962,6 +6997,13 @@ util.promisify@^1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" From f39e27c47c2a90fe72a0edd287d93f34d54d6de3 Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Sun, 3 Mar 2019 19:29:40 +0100 Subject: [PATCH 03/10] Added followedByCurrentUser and shoutedByCurrentUser --- src/schema.graphql | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/schema.graphql b/src/schema.graphql index 20a0b3652..dd2bfde59 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -92,6 +92,12 @@ type User { followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN") followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)") + "Is the currently logged in user following that user?" + followedByCurrentUser: Boolean! @cypher(statement: """ + MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """) + #contributions: [WrittenPost]! #contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]! # @cypher( @@ -150,6 +156,12 @@ type Post { shoutedBy: [User]! @relation(name: "SHOUTED", direction: "IN") shoutedCount: Int! @cypher(statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)") + + "Has the currently logged in user shouted that post?" + shoutedByCurrentUser: Boolean! @cypher(statement: """ + MATCH (this)<-[:SHOUTED]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """) } type Comment { From e2add5a730ceafa6dff84ecce41db488549dcfe0 Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 10:56:47 +0100 Subject: [PATCH 04/10] Added (un)shout and (un)follow mutations --- src/schema.graphql | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/schema.graphql b/src/schema.graphql index dd2bfde59..e5a077f2d 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -1,12 +1,45 @@ type Query { isLoggedIn: Boolean! + "Get the currently logged in User based on the given JWT Token" currentUser: User + "Get the latest Network Statistics" statistics: Statistics! } type Mutation { + "Get a JWT Token for the given Email and password" login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! report(resource: Resource!, description: String): Report + + "Shout the given Type and ID" + shout(id: ID!, type: ShoutTypeEnum): String! @cypher(statement: """ + MATCH (n {id: $id}) + WHERE $type IN labels(n) + MERGE (:User {id: $cypherParams.currentUserId})-[r:SHOUTED]->(n) + RETURN COUNT(r) > 0 + """) + "Unshout the given Type and ID" + unshout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ + MATCH (:User {id: $cypherParams.currentUserId})-[r:SHOUTED]->(n {id: $id}) + WHERE $type IN labels(n) + DELETE r + RETURN COUNT(r) > 0 + """) + + "Follow the given Type and ID" + follow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ + MATCH (n {id: $id}) + WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId + MERGE (:User {id: $cypherParams.currentUserId})-[r:FOLLOWS]->(n) + RETURN COUNT(r) > 0 + """) + "Unfollow the given Type and ID" + unfollow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ + MATCH (:User {id: $cypherParams.currentUserId})-[r:FOLLOWS]->(n {id: $id}) + WHERE $type IN labels(n) + DELETE r + RETURN COUNT(r) > 0 + """) } type Statistics { @@ -214,6 +247,16 @@ enum BadgeStatusEnum { permanent temporary } +enum ShoutTypeEnum { + Post + Organization + Project +} +enum FollowTypeEnum { + User + Organization + Project +} type Organization { id: ID! From d7b1ea88c4dddd9de6df7cefdfb68e0ff2418038 Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 11:18:59 +0100 Subject: [PATCH 05/10] Fixed shouts and follows --- src/schema.graphql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/schema.graphql b/src/schema.graphql index e5a077f2d..f95bbb18a 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -13,9 +13,9 @@ type Mutation { "Shout the given Type and ID" shout(id: ID!, type: ShoutTypeEnum): String! @cypher(statement: """ - MATCH (n {id: $id}) + MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) WHERE $type IN labels(n) - MERGE (:User {id: $cypherParams.currentUserId})-[r:SHOUTED]->(n) + MERGE (u)-[r:SHOUTED]->(n) RETURN COUNT(r) > 0 """) "Unshout the given Type and ID" @@ -28,9 +28,9 @@ type Mutation { "Follow the given Type and ID" follow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ - MATCH (n {id: $id}) + MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId - MERGE (:User {id: $cypherParams.currentUserId})-[r:FOLLOWS]->(n) + MERGE (u)-[r:FOLLOWS]->(n) RETURN COUNT(r) > 0 """) "Unfollow the given Type and ID" From 45a004662f1fad9d206fc3ddf4fd7b5c3b0c614f Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 14:18:22 +0100 Subject: [PATCH 06/10] Disable shouting of own content --- src/schema.graphql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/schema.graphql b/src/schema.graphql index f95bbb18a..e6e2088f1 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -13,8 +13,8 @@ type Mutation { "Shout the given Type and ID" shout(id: ID!, type: ShoutTypeEnum): String! @cypher(statement: """ - MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) + MATCH (n {id: $id})<-[:WROTE]-(wu:User), (u:User {id: $cypherParams.currentUserId}) + WHERE $type IN labels(n) AND NOT wu.id = $cypherParams.currentUserId MERGE (u)-[r:SHOUTED]->(n) RETURN COUNT(r) > 0 """) From a292a522e9524f949f32fbd90fe913d0ce34fb60 Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 18:30:28 +0100 Subject: [PATCH 07/10] Fixed an issue and added basic testing for (un)shout --- src/resolvers/shout.spec.js | 97 +++++++++++++++++++++++++++++++++++++ src/schema.graphql | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/resolvers/shout.spec.js diff --git a/src/resolvers/shout.spec.js b/src/resolvers/shout.spec.js new file mode 100644 index 000000000..4f5ea6ed6 --- /dev/null +++ b/src/resolvers/shout.spec.js @@ -0,0 +1,97 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() +let clientUser1, clientUser2 + +const mutationShoutPost = (id) => ` + mutation { + shout(id: "${id}", type: Post) + } +` +const mutationUnshoutPost = (id) => ` + mutation { + unshout(id: "${id}", type: Post) + } +` + +beforeEach(async () => { + await factory.create('User', { + id: 'u1', + email: 'test@example.org', + password: '1234' + }) + await factory.create('User', { + id: 'u2', + email: 'test2@example.org', + password: '1234' + }) +}) + +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 + } + } + `) + }) + + it('I shout a post of another user', async () => { + const res = await clientUser1.request( + mutationShoutPost('p2') + ) + const expected = { + shout: true + } + expect(res).toMatchObject(expected) + }) + + 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) + }) + + it('I can`t shout my own post', async () => { + const res = await clientUser1.request( + mutationShoutPost('p1') + ) + const expected = { + shout: false + } + expect(res).toMatchObject(expected) + }) + }) +}) diff --git a/src/schema.graphql b/src/schema.graphql index e6e2088f1..b21773c00 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -12,7 +12,7 @@ type Mutation { report(resource: Resource!, description: String): Report "Shout the given Type and ID" - shout(id: ID!, type: ShoutTypeEnum): String! @cypher(statement: """ + shout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ MATCH (n {id: $id})<-[:WROTE]-(wu:User), (u:User {id: $cypherParams.currentUserId}) WHERE $type IN labels(n) AND NOT wu.id = $cypherParams.currentUserId MERGE (u)-[r:SHOUTED]->(n) From 4fdb1562f9c58b63e58fc46a69f6fd06e84aba4c Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 18:34:35 +0100 Subject: [PATCH 08/10] Added test for shoutedByCurrentUser flag on posts --- src/resolvers/shout.spec.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/resolvers/shout.spec.js b/src/resolvers/shout.spec.js index 4f5ea6ed6..440210720 100644 --- a/src/resolvers/shout.spec.js +++ b/src/resolvers/shout.spec.js @@ -69,6 +69,16 @@ describe('shout ', () => { shout: true } expect(res).toMatchObject(expected) + + const { Post } = await clientUser1.request(`{ + Post(id: "p2") { + shoutedByCurrentUser + } + }`) + const expected2 = { + shoutedByCurrentUser: true + } + expect(Post[0]).toMatchObject(expected2) }) it('I unshout a post of another user', async () => { @@ -82,6 +92,16 @@ describe('shout ', () => { // 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 () => { @@ -92,6 +112,16 @@ describe('shout ', () => { shout: false } expect(res).toMatchObject(expected) + + const { Post } = await clientUser1.request(`{ + Post(id: "p1") { + shoutedByCurrentUser + } + }`) + const expected2 = { + shoutedByCurrentUser: false + } + expect(Post[0]).toMatchObject(expected2) }) }) }) From c2aea104f4ed3a9b4d9e1c5ed5ba3a195fece02d Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 18:44:39 +0100 Subject: [PATCH 09/10] Added basic tests for follow mutation --- src/resolvers/follow.spec.js | 118 +++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/resolvers/follow.spec.js diff --git a/src/resolvers/follow.spec.js b/src/resolvers/follow.spec.js new file mode 100644 index 000000000..a7b0d3284 --- /dev/null +++ b/src/resolvers/follow.spec.js @@ -0,0 +1,118 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() +let clientUser1, clientUser2 + +const mutationFollowUser = (id) => ` + mutation { + follow(id: "${id}", type: User) + } +` +const mutationUnfollowUser = (id) => ` + mutation { + unfollow(id: "${id}", type: User) + } +` + +beforeEach(async () => { + await factory.create('User', { + id: 'u1', + email: 'test@example.org', + password: '1234' + }) + await factory.create('User', { + id: 'u2', + email: 'test2@example.org', + password: '1234' + }) +}) + +afterEach(async () => { + await factory.cleanDatabase() +}) + + +describe('follow ', () => { + describe('(un)follow user', () => { + 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 }) + }) + + it('I can follow another user', async () => { + const res = await clientUser1.request( + mutationFollowUser('u2') + ) + const expected = { + follow: true + } + expect(res).toMatchObject(expected) + + const { User } = await clientUser1.request(`{ + User(id: "u2") { + followedBy { id } + followedByCurrentUser + } + }`) + const expected2 = { + followedBy: [ + { id: 'u1' } + ], + followedByCurrentUser: true + } + 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') + ) + const expected = { + follow: false + } + expect(res).toMatchObject(expected) + + const { User } = await clientUser1.request(`{ + User(id: "u1") { + followedBy { id } + followedByCurrentUser + } + }`) + const expected2 = { + followedBy: [], + followedByCurrentUser: false + } + expect(User[0]).toMatchObject(expected2) + }) + }) +}) From 865fdebc5f06257646631965d4793df9514b1222 Mon Sep 17 00:00:00 2001 From: Grzegorz Leoniec Date: Tue, 5 Mar 2019 18:58:17 +0100 Subject: [PATCH 10/10] Fixed linting issues inside tests --- src/resolvers/follow.spec.js | 7 ++----- src/resolvers/shout.spec.js | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/resolvers/follow.spec.js b/src/resolvers/follow.spec.js index a7b0d3284..3c16560e5 100644 --- a/src/resolvers/follow.spec.js +++ b/src/resolvers/follow.spec.js @@ -3,7 +3,7 @@ import { GraphQLClient } from 'graphql-request' import { host, login } from '../jest/helpers' const factory = Factory() -let clientUser1, clientUser2 +let clientUser1 const mutationFollowUser = (id) => ` mutation { @@ -33,15 +33,12 @@ afterEach(async () => { await factory.cleanDatabase() }) - describe('follow ', () => { describe('(un)follow user', () => { - let headersUser1, headersUser2 + let headersUser1 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 }) }) it('I can follow another user', async () => { diff --git a/src/resolvers/shout.spec.js b/src/resolvers/shout.spec.js index 440210720..490191c7a 100644 --- a/src/resolvers/shout.spec.js +++ b/src/resolvers/shout.spec.js @@ -33,7 +33,6 @@ afterEach(async () => { await factory.cleanDatabase() }) - describe('shout ', () => { describe('(un)shout foreign post', () => { let headersUser1, headersUser2