mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-13 12:47:28 +01:00
commit d30dff2311087ff2fe5f3e2a913c594abeee6b0e Author: Sabe Jones <sabe@habitica.com> Date: Tue Feb 27 16:01:11 2024 -0600 fix(challenge): move isOfficial to mount process commit ae52dca3cd0b4fd490f07b1979049803ce2f1e2f Merge: 2b20ff1e462c6e82a58aAuthor: Sabe Jones <sabe@habitica.com> Date: Tue Feb 27 15:20:40 2024 -0600 Merge branch 'release' into phillip/challenges_official commit 2b20ff1e46b1447eac3f9dbdf29566154c9fa656 Author: Sabe Jones <sabe@habitica.com> Date: Wed Feb 14 15:31:22 2024 -0600 fix(tests): correct lint and TypeError commit 5dae5c716f11db4c652e423eab43805ddfac3455 Merge: 29d9edc7aa1a3c2f64e4Author: Sabe Jones <sabe@habitica.com> Date: Wed Feb 14 15:01:18 2024 -0600 Merge branch 'release' into phillip/challenges_official commit 29d9edc7aa7445d24f5be24ca923719a4ab5f70d Author: Sabe Jones <sabe@habitica.com> Date: Wed Feb 14 14:41:16 2024 -0600 fix(challenges): don't momentarily show Report on official commit f994d12775107cba7ec816ee522cfeb0c69ef567 Author: Phillip Thelen <phillip@habitica.com> Date: Tue Feb 13 10:08:08 2024 +0100 hide report button for official challenges commit ac06dcaca701b91913d5fc5307626b1616a9e0e8 Author: Phillip Thelen <phillip@habitica.com> Date: Tue Feb 13 10:04:49 2024 +0100 prevent official challenges from being flagged commit a07ce1e6de66a2c833c6f392cf396a7743ca0f97 Author: Phillip Thelen <phillip@habitica.com> Date: Mon Feb 5 19:12:17 2024 +0100 test shouldn’t be exclusive commit 4c2436a1a0fa905530b7e1cd66f75a2b07be5810 Author: Phillip Thelen <phillip@habitica.com> Date: Mon Feb 5 19:11:20 2024 +0100 remove log commit 292f3a578d51fd08c572afc574cc73d08356f46a Author: Phillip Thelen <phillip@habitica.com> Date: Mon Feb 5 19:10:13 2024 +0100 Automatically set official field on challenges if habitica_official cateogory is set
402 lines
12 KiB
JavaScript
402 lines
12 KiB
JavaScript
import { v4 as generateUUID } from 'uuid';
|
|
import {
|
|
generateUser,
|
|
createAndPopulateGroup,
|
|
translate as t,
|
|
} from '../../../../helpers/api-integration/v3';
|
|
import { MAX_SUMMARY_SIZE_FOR_CHALLENGES } from '../../../../../website/common/script/constants';
|
|
|
|
describe('POST /challenges', () => {
|
|
it('returns error when group is empty', async () => {
|
|
const user = await generateUser();
|
|
|
|
await expect(user.post('/challenges')).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('returns error when groupId is not for a valid group', async () => {
|
|
const user = await generateUser();
|
|
|
|
await expect(user.post('/challenges', {
|
|
group: generateUUID(),
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 404,
|
|
error: 'NotFound',
|
|
message: t('groupNotFound'),
|
|
});
|
|
});
|
|
|
|
it('returns error when creating a challenge in the tavern with no prize', async () => {
|
|
const user = await generateUser();
|
|
|
|
await expect(user.post('/challenges', {
|
|
group: 'habitrpg',
|
|
prize: 0,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('tavChalsMinPrize'),
|
|
});
|
|
});
|
|
|
|
it('returns error when creating a challenge with summary with greater than MAX_SUMMARY_SIZE_FOR_CHALLENGES characters', async () => {
|
|
const user = await generateUser();
|
|
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_CHALLENGES + 1);
|
|
const group = createAndPopulateGroup({
|
|
members: 1,
|
|
});
|
|
await expect(user.post('/challenges', {
|
|
group: group._id,
|
|
summary,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
context('creating a Challenge for a Group Plan', () => {
|
|
let groupLeader;
|
|
let group;
|
|
let groupMember;
|
|
|
|
beforeEach(async () => {
|
|
const populatedGroup = await createAndPopulateGroup({
|
|
members: 1,
|
|
leaderDetails: {
|
|
balance: 3,
|
|
},
|
|
groupDetails: {
|
|
type: 'guild',
|
|
leaderOnly: {
|
|
challenges: true,
|
|
},
|
|
},
|
|
upgradeToGroupPlan: true,
|
|
});
|
|
|
|
groupLeader = await populatedGroup.groupLeader.sync();
|
|
await groupLeader.updateOne({ permissions: {} });
|
|
group = populatedGroup.group;
|
|
groupMember = populatedGroup.members[0]; // eslint-disable-line prefer-destructuring
|
|
});
|
|
|
|
it('returns an error when non-leader member creates a challenge in leaderOnly group', async () => {
|
|
await expect(groupMember.post('/challenges', {
|
|
group: group._id,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('onlyGroupLeaderChal'),
|
|
});
|
|
});
|
|
|
|
it('allows non-leader member to create a challenge', async () => {
|
|
const populatedGroup = await createAndPopulateGroup({
|
|
members: 1,
|
|
});
|
|
|
|
group = populatedGroup.group;
|
|
groupMember = populatedGroup.members[0]; // eslint-disable-line prefer-destructuring
|
|
|
|
const chal = await groupMember.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
});
|
|
|
|
expect(chal.leader).to.eql({
|
|
_id: groupMember._id,
|
|
profile: { name: groupMember.profile.name },
|
|
});
|
|
});
|
|
|
|
it('doesn\'t take gems from user or group when challenge has no prize', async () => {
|
|
const oldUserBalance = groupLeader.balance;
|
|
const oldGroupBalance = group.balance;
|
|
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
prize: 0,
|
|
});
|
|
|
|
await expect(groupLeader.sync()).to.eventually.have.property('balance', oldUserBalance);
|
|
await expect(group.sync()).to.eventually.have.property('balance', oldGroupBalance);
|
|
});
|
|
|
|
it('returns error when user and group can\'t pay prize', async () => {
|
|
await expect(groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
prize: 20,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('cantAfford'),
|
|
});
|
|
});
|
|
|
|
it('takes prize out of group if it has sufficient funds', async () => {
|
|
const oldUserBalance = groupLeader.balance;
|
|
const oldGroupBalance = group.balance;
|
|
const prize = 4;
|
|
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
prize,
|
|
});
|
|
|
|
await expect(group.sync()).to.eventually.have.property('balance', oldGroupBalance - prize / 4);
|
|
await expect(groupLeader.sync()).to.eventually.have.property('balance', oldUserBalance);
|
|
});
|
|
|
|
it('takes prize out of both group and user if group doesn\'t have enough', async () => {
|
|
const oldUserBalance = groupLeader.balance;
|
|
const prize = 8;
|
|
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
prize,
|
|
});
|
|
|
|
await expect(group.sync()).to.eventually.have.property('balance', 0);
|
|
await expect(groupLeader.sync()).to.eventually.have.property('balance', oldUserBalance - (prize / 4 - 1));
|
|
});
|
|
|
|
it('takes prize out of user if group has no balance', async () => {
|
|
const oldUserBalance = groupLeader.balance;
|
|
const prize = 8;
|
|
|
|
await group.updateOne({ balance: 0 });
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
prize,
|
|
});
|
|
|
|
await expect(group.sync()).to.eventually.have.property('balance', 0);
|
|
await expect(groupLeader.sync()).to.eventually.have.property('balance', oldUserBalance - prize / 4);
|
|
});
|
|
|
|
it('increases challenge count of group', async () => {
|
|
const oldChallengeCount = group.challengeCount;
|
|
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
});
|
|
|
|
await expect(group.sync()).to.eventually.have.property('challengeCount', oldChallengeCount + 1);
|
|
});
|
|
|
|
it('sets challenge as official if created by admin and official flag is set', async () => {
|
|
await groupLeader.updateOne({
|
|
permissions: {
|
|
challengeAdmin: true,
|
|
},
|
|
});
|
|
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
official: true,
|
|
});
|
|
|
|
expect(challenge.official).to.eql(true);
|
|
});
|
|
|
|
it('doesn\'t set challenge as official if official flag is set by non-admin', async () => {
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
official: true,
|
|
});
|
|
|
|
expect(challenge.official).to.eql(false);
|
|
});
|
|
|
|
it('returns an error when challenge validation fails; doesn\'s save user or group', async () => {
|
|
const oldChallengeCount = group.challengeCount;
|
|
const oldUserBalance = groupLeader.balance;
|
|
const oldGroupBalance = group.balance;
|
|
|
|
await expect(groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
prize: 8,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'Challenge validation failed',
|
|
});
|
|
|
|
group = await group.sync();
|
|
groupLeader = await groupLeader.sync();
|
|
|
|
expect(group.challengeCount).to.eql(oldChallengeCount);
|
|
expect(group.balance).to.eql(oldGroupBalance);
|
|
expect(groupLeader.balance).to.eql(oldUserBalance);
|
|
});
|
|
|
|
it('sets all properties of the challenge as passed', async () => {
|
|
const name = 'Test Challenge';
|
|
const shortName = 'TC Label';
|
|
const description = 'Test Description';
|
|
const prize = 4;
|
|
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name,
|
|
shortName,
|
|
description,
|
|
prize,
|
|
});
|
|
|
|
expect(challenge.leader).to.eql({
|
|
_id: groupLeader._id,
|
|
profile: { name: groupLeader.profile.name },
|
|
});
|
|
expect(challenge.name).to.eql(name);
|
|
expect(challenge.shortName).to.eql(shortName);
|
|
expect(challenge.description).to.eql(description);
|
|
expect(challenge.official).to.eql(false);
|
|
expect(challenge.group).to.eql({
|
|
_id: group._id,
|
|
privacy: group.privacy,
|
|
name: group.name,
|
|
type: group.type,
|
|
});
|
|
expect(challenge.memberCount).to.eql(0);
|
|
expect(challenge.prize).to.eql(prize);
|
|
});
|
|
|
|
it('does not add challenge to creator\'s challenges', async () => {
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
});
|
|
|
|
await groupLeader.sync();
|
|
expect(groupLeader.challenges.length).to.equal(0);
|
|
});
|
|
|
|
it('does not award joinedChallenge achievement for creating a challenge', async () => {
|
|
await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
});
|
|
groupLeader = await groupLeader.sync();
|
|
expect(groupLeader.achievements.joinedChallenge).to.not.be.true;
|
|
});
|
|
|
|
it('sets summary to challenges name when not supplied', async () => {
|
|
const name = 'Test Challenge';
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name,
|
|
shortName: 'TC Label',
|
|
});
|
|
|
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
|
|
|
expect(updatedChallenge.summary).to.eql(name);
|
|
});
|
|
|
|
it('sets summary to challenges', async () => {
|
|
const name = 'Test Challenge';
|
|
const summary = 'Test Summary Challenge';
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name,
|
|
shortName: 'TC Label',
|
|
summary,
|
|
});
|
|
|
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
|
|
|
expect(updatedChallenge.summary).to.eql(summary);
|
|
});
|
|
|
|
it('sets categories for challenges', async () => {
|
|
const testCategory = { _id: '65c1172997c0b24600371ea9', slug: 'test', name: 'Test' };
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
categories: [testCategory],
|
|
});
|
|
|
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
|
|
|
expect(updatedChallenge.categories).to.eql([testCategory]);
|
|
});
|
|
|
|
it('does not set habitica_official category for non-admins', async () => {
|
|
const testCategory = { _id: '65c1172997c0b24600371ea9', slug: 'habitica_official', name: 'habitica_official' };
|
|
await expect(groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
categories: [testCategory],
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('noPrivAccess'),
|
|
});
|
|
});
|
|
|
|
it('sets habitica_official category for admins', async () => {
|
|
await groupLeader.updateOne({
|
|
permissions: {
|
|
challengeAdmin: true,
|
|
},
|
|
});
|
|
|
|
const testCategory = { _id: '65c1172997c0b24600371ea9', slug: 'habitica_official', name: 'habitica_official' };
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
categories: [testCategory],
|
|
});
|
|
|
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
|
expect(updatedChallenge.categories).to.eql([testCategory]);
|
|
});
|
|
|
|
it('sets official if the habitica_official category is set for admins', async () => {
|
|
await groupLeader.updateOne({
|
|
permissions: {
|
|
challengeAdmin: true,
|
|
},
|
|
});
|
|
|
|
const testCategory = { _id: '65c1172997c0b24600371ea9', slug: 'habitica_official', name: 'habitica_official' };
|
|
const challenge = await groupLeader.post('/challenges', {
|
|
group: group._id,
|
|
name: 'Test Challenge',
|
|
shortName: 'TC Label',
|
|
categories: [testCategory],
|
|
});
|
|
|
|
const updatedChallenge = await groupLeader.get(`/challenges/${challenge._id}`);
|
|
expect(updatedChallenge.official).to.eql(true);
|
|
});
|
|
});
|
|
});
|