diff --git a/common/locales/en/api-v3.json b/common/locales/en/api-v3.json index bc71703017..f030c020f7 100644 --- a/common/locales/en/api-v3.json +++ b/common/locales/en/api-v3.json @@ -66,5 +66,10 @@ "emailsMustBeAnArray": "Email invites must be a an Array.", "canOnlyInviteMaxInvites": "You can only invite \"<%= maxInvites %>\" at a time", "cantOnlyUnlinkChalTask": "Only challenges tasks can be unlinked.", - "questInviteNotFound": "No quest invitation found." + "questInviteNotFound": "No quest invitation found.", + "guildQuestsNotSupported": "Guilds cannot be invited on quests.", + "questNotFound": "Quest \"<%= key %>\" not found.", + "questNotOwned": "You don't own that quest scroll.", + "questLevelTooHigh": "You must be Level <%= level %> to begin this quest.", + "questAlreadyUnderway": "Your party is already on a quest. Try again when the current quest has ended." } diff --git a/test/api/v3/integration/groups/POST-groups_groupId_quests_accept.test.js b/test/api/v3/integration/groups/POST-groups_groupId_quests_accept.test.js index 44286e6e79..a50497555b 100644 --- a/test/api/v3/integration/groups/POST-groups_groupId_quests_accept.test.js +++ b/test/api/v3/integration/groups/POST-groups_groupId_quests_accept.test.js @@ -10,7 +10,7 @@ describe.skip('POST /groups/:groupId/quests/accept', () => { let member; beforeEach(async () => { - let { group, groupLeader, members } = await createAndPopulateGroup({ + let { group, groupLeader, members } = await createAndPopulateGroup( { type: 'party', privacy: 'private' }, members: 1, }); diff --git a/test/api/v3/integration/groups/POST-groups_groupId_quests_invite.test.js b/test/api/v3/integration/groups/POST-groups_groupId_quests_invite.test.js new file mode 100644 index 0000000000..76ccf25e51 --- /dev/null +++ b/test/api/v3/integration/groups/POST-groups_groupId_quests_invite.test.js @@ -0,0 +1,120 @@ +import { + createAndPopulateGroup, + generateUser, + translate as t, +} from '../../../../helpers/api-v3-integration.helper'; +import { v4 as generateUUID } from 'uuid'; + +describe.skip('POST /groups/:groupId/quests/invite', () => { + let questingGroup; + let leader; + let member; + const PET_QUEST = 'whale'; + + beforeEach(async () => { + let { group, groupLeader, members } = await createAndPopulateGroup( + { type: 'party', privacy: 'private' }, + members: 1, + }); + + questingGroup = group; + leader = groupLeader; + member = members[0]; + }); + + context('failure conditions', () => { + it('does not issue invites with an invalid group ID', async () => { + await expect(leader.post(`/groups/${generateUUID()}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('groupNotFound'), + }); + }); + + it('does not issue invites for a group in which user is not a member', async () => { + let { alternateGroup } = await createAndPopulateGroup( + { type: 'party', privacy: 'private' }, + members: 1, + }); + + await expect(leader.post(`/groups/${alternateGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('groupNotFound'), + }); + )}; + + it('does not issue invites for Guilds', async () => { + let { alternateGroup } = await createAndPopulateGroup( + { type: 'guild', privacy: 'public' }, + members: 1, + }); + + await expect(leader.post(`/groups/${alternateGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 401, + error: 'NotAuthorized', + message: t('guildQuestsNotSupported'), + }); + )}; + + it('does not issue invites with an invalid quest key', async () => { + const FAKE_QUEST = 'herkimer'; + + await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${FAKE_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('questNotFound', {key: FAKE_QUEST}), + }); + )}; + + it('does not issue invites for a quest the user does not own', async () => { + await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 401, + error: 'NotAuthorized', + message: t('questNotOwned'), + }); + )}; + + it('does not issue invites if the user is of insufficient Level', async () => { + const LEVELED_QUEST = 'atom1'; + const LEVELED_QUEST_REQ = 15; + leader.items.quests[LEVELED_QUEST] = 1; + + await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${LEVELED_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 401, + error: 'NotAuthorized', + message: t('questLevelTooHigh', {level: LEVELED_QUEST_REQ}), + }); + )}; + + it('does not issue invites if a quest is already underway', async () => { + leader.items.quests[PET_QUEST] = 2; + + await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`); + + await expect(leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.be.rejected.and.eql({ + code: 401, + error: 'NotAuthorized', + message: t('questAlreadyUnderway'), + }); + )}; + )}; + + context('successfully issuing a quest invitation', () => { + it('sends an invite to all party members', async () => { + leader.items.quests[PET_QUEST] = 1; + + await expect(leader.post(`groups/${questingGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.deep.equal([{ + + }]); + )}; + + it('allows non-leader party members to send invites', () => { + member.items.quests[PET_QUEST] = 1; + + await expect(member.post(`groups/${questingGroup._id}/quests/invite/${PET_QUEST}`)).to.eventually.deep.equal([{ + + }]); + )}; + )}; +)};