import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../../db/factories' import { createGroupMutation, updateGroupMutation, joinGroupMutation, changeGroupMemberRoleMutation, groupMembersQuery, groupQuery, } from '../../db/graphql/groups' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' import CONFIG from '../../config' const driver = getDriver() const neode = getNeode() let authenticatedUser let user const categoryIds = ['cat9', 'cat4', 'cat15'] const descriptionAdditional100 = ' 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789' let variables = {} const { server } = createServer({ context: () => { return { driver, neode, user: authenticatedUser, } }, }) const { mutate, query } = createTestClient(server) const seedBasicsAndClearAuthentication = async () => { variables = {} user = await Factory.build( 'user', { id: 'current-user', name: 'TestUser', }, { email: 'test@example.org', password: '1234', }, ) await Promise.all([ neode.create('Category', { id: 'cat9', name: 'Democracy & Politics', slug: 'democracy-politics', icon: 'university', }), neode.create('Category', { id: 'cat4', name: 'Environment & Nature', slug: 'environment-nature', icon: 'tree', }), neode.create('Category', { id: 'cat15', name: 'Consumption & Sustainability', slug: 'consumption-sustainability', icon: 'shopping-cart', }), neode.create('Category', { id: 'cat27', name: 'Animal Protection', slug: 'animal-protection', icon: 'paw', }), ]) authenticatedUser = null } beforeAll(async () => { await cleanDatabase() }) afterAll(async () => { await cleanDatabase() }) describe('in mode', () => { describe('clean db after each single test', () => { beforeEach(async () => { await seedBasicsAndClearAuthentication() }) // TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543 afterEach(async () => { await cleanDatabase() }) describe('CreateGroup', () => { beforeEach(() => { variables = { ...variables, id: 'g589', name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, // locationName, // test this as result } }) describe('unauthenticated', () => { it('throws authorization error', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) it('creates a group', async () => { await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject( { data: { CreateGroup: { name: 'The Best Group', slug: 'the-group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', }, }, errors: undefined, }, ) }) it('assigns the authenticated user as owner', async () => { await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject( { data: { CreateGroup: { name: 'The Best Group', myRole: 'owner', }, }, errors: undefined, }, ) }) it('has "disabled" and "deleted" default to "false"', async () => { await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject( { data: { CreateGroup: { disabled: false, deleted: false } }, }, ) }) describe('description', () => { describe('length without HTML', () => { describe('less then 100 chars', () => { it('throws error: "Description too short!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, description: '0123456789' + '0123456789', }, }) expect(errors[0]).toHaveProperty('message', 'Description too short!') }) }) }) }) describe('categories', () => { beforeEach(() => { CONFIG.CATEGORIES_ACTIVE = true }) describe('with matching amount of categories', () => { it('has new categories', async () => { await expect( mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: ['cat4', 'cat27'], }, }), ).resolves.toMatchObject({ data: { CreateGroup: { categories: expect.arrayContaining([ expect.objectContaining({ id: 'cat4' }), expect.objectContaining({ id: 'cat27' }), ]), myRole: 'owner', }, }, errors: undefined, }) }) }) describe('not even one', () => { describe('by "categoryIds: null"', () => { it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: null }, }) expect(errors[0]).toHaveProperty('message', 'Too view categories!') }) }) describe('by "categoryIds: []"', () => { it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: [] }, }) expect(errors[0]).toHaveProperty('message', 'Too view categories!') }) }) }) describe('four', () => { it('throws error: "Too many categories!"', async () => { const { errors } = await mutate({ mutation: createGroupMutation, variables: { ...variables, categoryIds: ['cat9', 'cat4', 'cat15', 'cat27'] }, }) expect(errors[0]).toHaveProperty('message', 'Too many categories!') }) }) }) }) }) }) describe('building up – clean db after each resolver', () => { describe('Group', () => { beforeAll(async () => { await seedBasicsAndClearAuthentication() }) afterAll(async () => { await cleanDatabase() }) describe('unauthenticated', () => { it('throws authorization error', async () => { const { errors } = await query({ query: groupQuery, variables: {} }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { let otherUser let ownerOfHiddenGroupUser beforeAll(async () => { otherUser = await Factory.build( 'user', { id: 'other-user', name: 'Other TestUser', }, { email: 'other-user@example.org', password: '1234', }, ) ownerOfHiddenGroupUser = await Factory.build( 'user', { id: 'owner-of-hidden-group', name: 'Owner Of Hidden Group', }, { email: 'owner-of-hidden-group@example.org', password: '1234', }, ) authenticatedUser = await otherUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'others-group', name: 'Uninteresting Group', about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'global', categoryIds, }, }) authenticatedUser = await ownerOfHiddenGroupUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'hidden-group', name: 'Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) await mutate({ mutation: createGroupMutation, variables: { id: 'second-hidden-group', name: 'Second Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'second-hidden-group', userId: 'current-user', roleInGroup: 'pending', }, }) await mutate({ mutation: createGroupMutation, variables: { id: 'third-hidden-group', name: 'Third Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'third-hidden-group', userId: 'current-user', roleInGroup: 'usual', }, }) authenticatedUser = await user.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'my-group', name: 'The Best Group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, }, }) }) describe('query groups', () => { describe('in general finds only listed groups – no hidden groups where user is none or pending member', () => { describe('without any filters', () => { it('finds all listed groups', async () => { const result = await query({ query: groupQuery, variables: {} }) expect(result).toMatchObject({ data: { Group: expect.arrayContaining([ expect.objectContaining({ id: 'my-group', slug: 'the-best-group', myRole: 'owner', }), expect.objectContaining({ id: 'others-group', slug: 'uninteresting-group', myRole: null, }), expect.objectContaining({ id: 'third-hidden-group', slug: 'third-investigative-journalism-group', myRole: 'usual', }), ]), }, errors: undefined, }) expect(result.data.Group.length).toBe(3) }) describe('categories', () => { beforeEach(() => { CONFIG.CATEGORIES_ACTIVE = true }) it('has set categories', async () => { await expect(query({ query: groupQuery, variables: {} })).resolves.toMatchObject({ data: { Group: expect.arrayContaining([ expect.objectContaining({ id: 'my-group', slug: 'the-best-group', categories: expect.arrayContaining([ expect.objectContaining({ id: 'cat4' }), expect.objectContaining({ id: 'cat9' }), expect.objectContaining({ id: 'cat15' }), ]), myRole: 'owner', }), expect.objectContaining({ id: 'others-group', slug: 'uninteresting-group', categories: expect.arrayContaining([ expect.objectContaining({ id: 'cat4' }), expect.objectContaining({ id: 'cat9' }), expect.objectContaining({ id: 'cat15' }), ]), myRole: null, }), ]), }, errors: undefined, }) }) }) }) describe('with given id', () => { describe("id = 'my-group'", () => { it('finds only the listed group with this id', async () => { const result = await query({ query: groupQuery, variables: { id: 'my-group' } }) expect(result).toMatchObject({ data: { Group: [ expect.objectContaining({ id: 'my-group', slug: 'the-best-group', myRole: 'owner', }), ], }, errors: undefined, }) expect(result.data.Group.length).toBe(1) }) }) describe("id = 'third-hidden-group'", () => { it("finds only the hidden group where I'm 'usual' member", async () => { const result = await query({ query: groupQuery, variables: { id: 'third-hidden-group' }, }) expect(result).toMatchObject({ data: { Group: expect.arrayContaining([ expect.objectContaining({ id: 'third-hidden-group', slug: 'third-investigative-journalism-group', myRole: 'usual', }), ]), }, errors: undefined, }) expect(result.data.Group.length).toBe(1) }) }) describe("id = 'second-hidden-group'", () => { it("finds no hidden group where I'm 'pending' member", async () => { const result = await query({ query: groupQuery, variables: { id: 'second-hidden-group' }, }) expect(result.data.Group.length).toBe(0) }) }) describe("id = 'hidden-group'", () => { it("finds no hidden group where I'm not(!) a member at all", async () => { const result = await query({ query: groupQuery, variables: { id: 'hidden-group' }, }) expect(result.data.Group.length).toBe(0) }) }) }) describe('isMember = true', () => { it('finds only listed groups where user is member', async () => { const result = await query({ query: groupQuery, variables: { isMember: true } }) expect(result).toMatchObject({ data: { Group: expect.arrayContaining([ expect.objectContaining({ id: 'my-group', slug: 'the-best-group', myRole: 'owner', }), expect.objectContaining({ id: 'third-hidden-group', slug: 'third-investigative-journalism-group', myRole: 'usual', }), ]), }, errors: undefined, }) expect(result.data.Group.length).toBe(2) }) }) describe('isMember = false', () => { it('finds only listed groups where user is not(!) member', async () => { const result = await query({ query: groupQuery, variables: { isMember: false } }) expect(result).toMatchObject({ data: { Group: expect.arrayContaining([ expect.objectContaining({ id: 'others-group', slug: 'uninteresting-group', myRole: null, }), ]), }, errors: undefined, }) expect(result.data.Group.length).toBe(1) }) }) }) }) }) }) describe('JoinGroup', () => { beforeAll(async () => { await seedBasicsAndClearAuthentication() }) afterAll(async () => { await cleanDatabase() }) describe('unauthenticated', () => { it('throws authorization error', async () => { const { errors } = await mutate({ mutation: joinGroupMutation, variables: { groupId: 'not-existing-group', userId: 'current-user', }, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { let ownerOfClosedGroupUser let ownerOfHiddenGroupUser beforeAll(async () => { // create users ownerOfClosedGroupUser = await Factory.build( 'user', { id: 'owner-of-closed-group', name: 'Owner Of Closed Group', }, { email: 'owner-of-closed-group@example.org', password: '1234', }, ) ownerOfHiddenGroupUser = await Factory.build( 'user', { id: 'owner-of-hidden-group', name: 'Owner Of Hidden Group', }, { email: 'owner-of-hidden-group@example.org', password: '1234', }, ) // create groups // public-group authenticatedUser = await ownerOfClosedGroupUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'closed-group', name: 'Uninteresting Group', about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', categoryIds, }, }) authenticatedUser = await ownerOfHiddenGroupUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'hidden-group', name: 'Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) authenticatedUser = await user.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'public-group', name: 'The Best Group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, }, }) }) describe('public group', () => { describe('joined by "owner-of-closed-group"', () => { it('has "usual" as membership role', async () => { await expect( mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'owner-of-closed-group', }, }), ).resolves.toMatchObject({ data: { JoinGroup: { id: 'owner-of-closed-group', myRoleInGroup: 'usual', }, }, errors: undefined, }) }) }) describe('joined by its owner', () => { describe('does not create additional "MEMBER_OF" relation and therefore', () => { it('has still "owner" as membership role', async () => { await expect( mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'current-user', }, }), ).resolves.toMatchObject({ data: { JoinGroup: { id: 'current-user', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) }) }) describe('closed group', () => { describe('joined by "current-user"', () => { it('has "pending" as membership role', async () => { await expect( mutate({ mutation: joinGroupMutation, variables: { groupId: 'closed-group', userId: 'current-user', }, }), ).resolves.toMatchObject({ data: { JoinGroup: { id: 'current-user', myRoleInGroup: 'pending', }, }, errors: undefined, }) }) }) describe('joined by its owner', () => { describe('does not create additional "MEMBER_OF" relation and therefore', () => { it('has still "owner" as membership role', async () => { await expect( mutate({ mutation: joinGroupMutation, variables: { groupId: 'closed-group', userId: 'owner-of-closed-group', }, }), ).resolves.toMatchObject({ data: { JoinGroup: { id: 'owner-of-closed-group', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) }) }) describe('hidden group', () => { describe('joined by "owner-of-closed-group"', () => { it('throws authorization error', async () => { const { errors } = await query({ query: joinGroupMutation, variables: { groupId: 'hidden-group', userId: 'owner-of-closed-group', }, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('joined by its owner', () => { describe('does not create additional "MEMBER_OF" relation and therefore', () => { it('has still "owner" as membership role', async () => { await expect( mutate({ mutation: joinGroupMutation, variables: { groupId: 'hidden-group', userId: 'owner-of-hidden-group', }, }), ).resolves.toMatchObject({ data: { JoinGroup: { id: 'owner-of-hidden-group', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) }) }) }) }) describe('GroupMembers', () => { beforeAll(async () => { await seedBasicsAndClearAuthentication() }) afterAll(async () => { await cleanDatabase() }) describe('unauthenticated', () => { it('throws authorization error', async () => { variables = { id: 'not-existing-group', } const { errors } = await query({ query: groupMembersQuery, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { let otherUser let pendingUser let ownerOfClosedGroupUser let ownerOfHiddenGroupUser beforeAll(async () => { // create users otherUser = await Factory.build( 'user', { id: 'other-user', name: 'Other TestUser', }, { email: 'other-user@example.org', password: '1234', }, ) pendingUser = await Factory.build( 'user', { id: 'pending-user', name: 'Pending TestUser', }, { email: 'pending@example.org', password: '1234', }, ) ownerOfClosedGroupUser = await Factory.build( 'user', { id: 'owner-of-closed-group', name: 'Owner Of Closed Group', }, { email: 'owner-of-closed-group@example.org', password: '1234', }, ) ownerOfHiddenGroupUser = await Factory.build( 'user', { id: 'owner-of-hidden-group', name: 'Owner Of Hidden Group', }, { email: 'owner-of-hidden-group@example.org', password: '1234', }, ) // create groups // public-group authenticatedUser = await user.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'public-group', name: 'The Best Group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, }, }) await mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'owner-of-closed-group', }, }) await mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'owner-of-hidden-group', }, }) // closed-group authenticatedUser = await ownerOfClosedGroupUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'closed-group', name: 'Uninteresting Group', about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', categoryIds, }, }) await mutate({ mutation: joinGroupMutation, variables: { groupId: 'closed-group', userId: 'current-user', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'closed-group', userId: 'owner-of-hidden-group', roleInGroup: 'usual', }, }) // hidden-group authenticatedUser = await ownerOfHiddenGroupUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'hidden-group', name: 'Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) // 'JoinGroup' mutation does not work in hidden groups so we join them by 'ChangeGroupMemberRole' through the owner await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'pending-user', roleInGroup: 'pending', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'current-user', roleInGroup: 'usual', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'owner-of-closed-group', roleInGroup: 'admin', }, }) authenticatedUser = null }) describe('public group', () => { beforeEach(async () => { variables = { id: 'public-group', } }) describe('query group members', () => { describe('by owner "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'current-user', myRoleInGroup: 'owner', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'usual', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(3) }) }) describe('by usual member "owner-of-closed-group"', () => { beforeEach(async () => { authenticatedUser = await ownerOfClosedGroupUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'current-user', myRoleInGroup: 'owner', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'usual', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(3) }) }) describe('by none member "other-user"', () => { beforeEach(async () => { authenticatedUser = await otherUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'current-user', myRoleInGroup: 'owner', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'usual', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(3) }) }) }) }) describe('closed group', () => { beforeEach(async () => { variables = { id: 'closed-group', } }) describe('query group members', () => { describe('by owner "owner-of-closed-group"', () => { beforeEach(async () => { authenticatedUser = await ownerOfClosedGroupUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'current-user', myRoleInGroup: 'pending', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'owner', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'usual', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(3) }) }) describe('by usual member "owner-of-hidden-group"', () => { beforeEach(async () => { authenticatedUser = await ownerOfHiddenGroupUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'current-user', myRoleInGroup: 'pending', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'owner', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'usual', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(3) }) }) describe('by pending member "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) it('throws authorization error', async () => { const { errors } = await query({ query: groupMembersQuery, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('by none member "other-user"', () => { beforeEach(async () => { authenticatedUser = await otherUser.toJson() }) it('throws authorization error', async () => { const { errors } = await query({ query: groupMembersQuery, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) describe('hidden group', () => { beforeEach(async () => { variables = { id: 'hidden-group', } }) describe('query group members', () => { describe('by owner "owner-of-hidden-group"', () => { beforeEach(async () => { authenticatedUser = await ownerOfHiddenGroupUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'pending-user', myRoleInGroup: 'pending', }), expect.objectContaining({ id: 'current-user', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'admin', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'owner', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(4) }) }) describe('by usual member "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'pending-user', myRoleInGroup: 'pending', }), expect.objectContaining({ id: 'current-user', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'admin', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'owner', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(4) }) }) describe('by admin member "owner-of-closed-group"', () => { beforeEach(async () => { authenticatedUser = await ownerOfClosedGroupUser.toJson() }) it('finds all members', async () => { const result = await mutate({ mutation: groupMembersQuery, variables, }) expect(result).toMatchObject({ data: { GroupMembers: expect.arrayContaining([ expect.objectContaining({ id: 'pending-user', myRoleInGroup: 'pending', }), expect.objectContaining({ id: 'current-user', myRoleInGroup: 'usual', }), expect.objectContaining({ id: 'owner-of-closed-group', myRoleInGroup: 'admin', }), expect.objectContaining({ id: 'owner-of-hidden-group', myRoleInGroup: 'owner', }), ]), }, errors: undefined, }) expect(result.data.GroupMembers.length).toBe(4) }) }) describe('by pending member "pending-user"', () => { beforeEach(async () => { authenticatedUser = await pendingUser.toJson() }) it('throws authorization error', async () => { const { errors } = await query({ query: groupMembersQuery, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('by none member "other-user"', () => { beforeEach(async () => { authenticatedUser = await otherUser.toJson() }) it('throws authorization error', async () => { const { errors } = await query({ query: groupMembersQuery, variables }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) }) }) describe('ChangeGroupMemberRole', () => { let pendingMemberUser let usualMemberUser let adminMemberUser let ownerMemberUser let secondOwnerMemberUser beforeAll(async () => { await seedBasicsAndClearAuthentication() // create users pendingMemberUser = await Factory.build( 'user', { id: 'pending-member-user', name: 'Pending Member TestUser', }, { email: 'pending-member-user@example.org', password: '1234', }, ) usualMemberUser = await Factory.build( 'user', { id: 'usual-member-user', name: 'Usual Member TestUser', }, { email: 'usual-member-user@example.org', password: '1234', }, ) adminMemberUser = await Factory.build( 'user', { id: 'admin-member-user', name: 'Admin Member TestUser', }, { email: 'admin-member-user@example.org', password: '1234', }, ) ownerMemberUser = await Factory.build( 'user', { id: 'owner-member-user', name: 'Owner Member TestUser', }, { email: 'owner-member-user@example.org', password: '1234', }, ) secondOwnerMemberUser = await Factory.build( 'user', { id: 'second-owner-member-user', name: 'Second Owner Member TestUser', }, { email: 'second-owner-member-user@example.org', password: '1234', }, ) // create groups // public-group authenticatedUser = await usualMemberUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'public-group', name: 'The Best Group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, }, }) await mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'owner-of-closed-group', }, }) await mutate({ mutation: joinGroupMutation, variables: { groupId: 'public-group', userId: 'owner-of-hidden-group', }, }) // closed-group authenticatedUser = await ownerMemberUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'closed-group', name: 'Uninteresting Group', about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', categoryIds, }, }) // hidden-group authenticatedUser = await adminMemberUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'hidden-group', name: 'Investigative Journalism Group', about: 'We will change all.', description: 'We research …' + descriptionAdditional100, groupType: 'hidden', actionRadius: 'global', categoryIds, }, }) // 'JoinGroup' mutation does not work in hidden groups so we join them by 'ChangeGroupMemberRole' through the owner await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'admin-member-user', roleInGroup: 'usual', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'second-owner-member-user', roleInGroup: 'usual', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'admin-member-user', roleInGroup: 'usual', }, }) await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'hidden-group', userId: 'second-owner-member-user', roleInGroup: 'usual', }, }) authenticatedUser = null }) afterAll(async () => { await cleanDatabase() }) describe('unauthenticated', () => { it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables: { groupId: 'not-existing-group', userId: 'current-user', roleInGroup: 'pending', }, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { describe('in all group types – here "closed-group" for example', () => { beforeEach(async () => { variables = { groupId: 'closed-group', } }) describe('join the members and give them their prospective roles', () => { describe('by owner "owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await ownerMemberUser.toJson() }) describe('for "usual-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'usual-member-user', } }) describe('as usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('has role usual', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'usual-member-user', myRoleInGroup: 'usual', }, }, errors: undefined, }) }) // the GQL mutation needs this fields in the result for testing it.todo('has "updatedAt" newer as "createdAt"') }) }) describe('for "admin-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'admin-member-user', } }) describe('as admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('has role admin', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'admin-member-user', myRoleInGroup: 'admin', }, }, errors: undefined, }) }) }) }) describe('for "second-owner-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'second-owner-member-user', } }) describe('as owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('has role owner', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'second-owner-member-user', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) }) }) }) describe('switch role', () => { describe('of owner "owner-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'owner-member-user', } }) describe('by owner themself "owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await ownerMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) // shall this be possible in the future? // or shall only an owner who gave the second owner the owner role downgrade themself for savety? // otherwise the first owner who downgrades the other one has the victory over the group! describe('by second owner "second-owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await secondOwnerMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('to same role owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('has role owner still', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'owner-member-user', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) }) describe('by admin "admin-member-user"', () => { beforeEach(async () => { authenticatedUser = await adminMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by usual member "usual-member-user"', () => { beforeEach(async () => { authenticatedUser = await usualMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by still pending member "pending-member-user"', () => { beforeEach(async () => { authenticatedUser = await pendingMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) describe('of admin "admin-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'admin-member-user', } }) describe('by owner "owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await ownerMemberUser.toJson() }) describe('to owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('has role owner', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'admin-member-user', myRoleInGroup: 'owner', }, }, errors: undefined, }) }) }) describe('back to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by usual member "usual-member-user"', () => { beforeEach(async () => { authenticatedUser = await usualMemberUser.toJson() }) describe('upgrade to owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by still pending member "pending-member-user"', () => { beforeEach(async () => { authenticatedUser = await pendingMemberUser.toJson() }) describe('upgrade to owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by none member "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) describe('upgrade to owner', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'owner', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to pending again', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'pending', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) describe('of usual member "usual-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'usual-member-user', } }) describe('by owner "owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await ownerMemberUser.toJson() }) describe('to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('has role admin', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'usual-member-user', myRoleInGroup: 'admin', }, }, errors: undefined, }) }) }) describe('back to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('has role usual again', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'usual-member-user', myRoleInGroup: 'usual', }, }, errors: undefined, }) }) }) }) describe('by usual member "usual-member-user"', () => { beforeEach(async () => { authenticatedUser = await usualMemberUser.toJson() }) describe('upgrade to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to pending', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'pending', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by still pending member "pending-member-user"', () => { beforeEach(async () => { authenticatedUser = await pendingMemberUser.toJson() }) describe('upgrade to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to pending', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'pending', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by none member "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) describe('upgrade to admin', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'admin', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('degrade to pending again', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'pending', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) describe('of still pending member "pending-member-user"', () => { beforeEach(async () => { variables = { ...variables, userId: 'pending-member-user', } }) describe('by owner "owner-member-user"', () => { beforeEach(async () => { authenticatedUser = await ownerMemberUser.toJson() }) describe('to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('has role usual', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'pending-member-user', myRoleInGroup: 'usual', }, }, errors: undefined, }) }) }) describe('back to pending', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'pending', } }) it('has role usual again', async () => { await expect( mutate({ mutation: changeGroupMemberRoleMutation, variables, }), ).resolves.toMatchObject({ data: { ChangeGroupMemberRole: { id: 'pending-member-user', myRoleInGroup: 'pending', }, }, errors: undefined, }) }) }) }) describe('by usual member "usual-member-user"', () => { beforeEach(async () => { authenticatedUser = await usualMemberUser.toJson() }) describe('upgrade to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by still pending member "pending-member-user"', () => { beforeEach(async () => { authenticatedUser = await pendingMemberUser.toJson() }) describe('upgrade to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) describe('by none member "current-user"', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) describe('upgrade to usual', () => { beforeEach(async () => { variables = { ...variables, roleInGroup: 'usual', } }) it('throws authorization error', async () => { const { errors } = await mutate({ mutation: changeGroupMemberRoleMutation, variables, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) }) }) }) }) describe('UpdateGroup', () => { beforeAll(async () => { await seedBasicsAndClearAuthentication() }) afterAll(async () => { await cleanDatabase() }) describe('unauthenticated', () => { it('throws authorization error', async () => { const { errors } = await mutate({ query: updateGroupMutation, variables: { id: 'my-group', slug: 'my-best-group', }, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated', () => { let otherUser beforeAll(async () => { otherUser = await Factory.build( 'user', { id: 'other-user', name: 'Other TestUser', }, { email: 'test2@example.org', password: '1234', }, ) authenticatedUser = await otherUser.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'others-group', name: 'Uninteresting Group', about: 'We will change nothing!', description: 'We love it like it is!?' + descriptionAdditional100, groupType: 'closed', actionRadius: 'global', categoryIds, }, }) authenticatedUser = await user.toJson() await mutate({ mutation: createGroupMutation, variables: { id: 'my-group', name: 'The Best Group', about: 'We will change the world!', description: 'Some description' + descriptionAdditional100, groupType: 'public', actionRadius: 'regional', categoryIds, }, }) }) describe('change group settings', () => { describe('as owner', () => { beforeEach(async () => { authenticatedUser = await user.toJson() }) it('has set the settings', async () => { await expect( mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', name: 'The New Group For Our Country', about: 'We will change the land!', description: 'Some country relevant description' + descriptionAdditional100, actionRadius: 'national', // avatar, // test this as result // locationName, // test this as result }, }), ).resolves.toMatchObject({ data: { UpdateGroup: { id: 'my-group', name: 'The New Group For Our Country', slug: 'the-new-group-for-our-country', // changing the slug is tested in the slugifyMiddleware about: 'We will change the land!', description: 'Some country relevant description' + descriptionAdditional100, actionRadius: 'national', // avatar, // test this as result // locationName, // test this as result myRole: 'owner', }, }, errors: undefined, }) }) describe('description', () => { describe('length without HTML', () => { describe('less then 100 chars', () => { it('throws error: "Description too short!"', async () => { const { errors } = await mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', description: '0123456789' + '0123456789', }, }) expect(errors[0]).toHaveProperty('message', 'Description too short!') }) }) }) }) describe('categories', () => { beforeEach(async () => { CONFIG.CATEGORIES_ACTIVE = true }) describe('with matching amount of categories', () => { it('has new categories', async () => { await expect( mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', categoryIds: ['cat4', 'cat27'], }, }), ).resolves.toMatchObject({ data: { UpdateGroup: { id: 'my-group', categories: expect.arrayContaining([ expect.objectContaining({ id: 'cat4' }), expect.objectContaining({ id: 'cat27' }), ]), myRole: 'owner', }, }, errors: undefined, }) }) }) describe('not even one', () => { describe('by "categoryIds: []"', () => { it('throws error: "Too view categories!"', async () => { const { errors } = await mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', categoryIds: [], }, }) expect(errors[0]).toHaveProperty('message', 'Too view categories!') }) }) }) describe('four', () => { it('throws error: "Too many categories!"', async () => { const { errors } = await mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', categoryIds: ['cat9', 'cat4', 'cat15', 'cat27'], }, }) expect(errors[0]).toHaveProperty('message', 'Too many categories!') }) }) }) }) describe('as no(!) owner', () => { it('throws authorization error', async () => { authenticatedUser = await otherUser.toJson() const { errors } = await mutate({ mutation: updateGroupMutation, variables: { id: 'my-group', name: 'The New Group For Our Country', about: 'We will change the land!', description: 'Some country relevant description' + descriptionAdditional100, actionRadius: 'national', categoryIds: ['cat4', 'cat27'], // test this as result // avatar, // test this as result // locationName, // test this as result }, }) expect(errors[0]).toHaveProperty('message', 'Not Authorized!') }) }) }) }) }) }) })