Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/__tests__/box/BoxService/updateOneById.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { BoxService } from '../../../box/box.service';
import BoxBuilderFactory from '../data/boxBuilderFactory';
import { ObjectId } from 'mongodb';
import BoxModule from '../modules/box.module';
import {
BOX_SESSION_MAX_PARTICIPANTS,
BOX_SESSION_MIN_PARTICIPANTS,
} from '../../../box/consts/boxSessionConstants';

describe('BoxService.updateOneById() test suite', () => {
let boxService: BoxService;
Expand All @@ -12,6 +16,7 @@ describe('BoxService.updateOneById() test suite', () => {
.setAdminPassword('password')
.setAdminPlayerId(new ObjectId())
.setAdminProfileId(new ObjectId())
.setTestersAmount(BOX_SESSION_MIN_PARTICIPANTS)
.build();

beforeEach(async () => {
Expand Down Expand Up @@ -58,6 +63,39 @@ describe('BoxService.updateOneById() test suite', () => {
expect(errors[0].field).toBe('_id');
});

it('Should return ServiceError LESS_THAN_MIN if testersAmount is below the session minimum', async () => {
const [wasUpdated, errors] = await boxService.updateOneById({
_id: existingBox._id,
testersAmount: BOX_SESSION_MIN_PARTICIPANTS - 1,
});

expect(wasUpdated).toBeNull();
expect(errors).toContainSE_LESS_THAN_MIN();
expect(errors[0].field).toBe('testersAmount');
});

it('Should return ServiceError MORE_THAN_MAX if testersAmount exceeds the session maximum', async () => {
const [wasUpdated, errors] = await boxService.updateOneById({
_id: existingBox._id,
testersAmount: BOX_SESSION_MAX_PARTICIPANTS + 1,
});

expect(wasUpdated).toBeNull();
expect(errors).toContainSE_MORE_THAN_MAX();
expect(errors[0].field).toBe('testersAmount');
});

it('Should return ServiceError NOT_NUMBER if testersAmount is not an integer', async () => {
const [wasUpdated, errors] = await boxService.updateOneById({
_id: existingBox._id,
testersAmount: 1.5,
});

expect(wasUpdated).toBeNull();
expect(errors).toContainSE_NOT_NUMBER();
expect(errors[0].field).toBe('testersAmount');
});

it('Should return ServiceError NOT_UNIQUE if the box with provided _id adminPassword already exists', async () => {
const otherBox = boxBuilder
.setAdminPassword('other-box-password')
Expand Down
58 changes: 51 additions & 7 deletions src/__tests__/box/SessionStarterService/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { Box } from '../../../box/schemas/box.schema';
import DailyTasksModule from '../../dailyTasks/modules/dailyTasks.module';
import { SessionStage } from '../../../box/enum/SessionStage.enum';
import ClanModule from '../../clan/modules/clan.module';
import { BOX_SESSION_TASK_COUNT } from '../../../box/consts/boxSessionConstants';
import { ServerTaskName } from '../../../dailyTasks/enum/serverTaskName.enum';
import { UITaskName } from '../../../dailyTasks/enum/uiTaskName.enum';
import SoulhomeModule from '../../clanInventory/modules/soulhome.module';

describe('SessionStarterService.start() test suite', () => {
let starter: SessionStarterService;
Expand All @@ -21,11 +25,17 @@ describe('SessionStarterService.start() test suite', () => {
const playerModel = PlayerModule.getPlayerModel();
const dailyTaskModel = DailyTasksModule.getDailyTaskModel();
const clanModel = ClanModule.getClanModel();
const soulHomeModel = SoulhomeModule.getSoulhomeModel();

const profileBuilder = ProfileBuilderFactory.getBuilder('Profile');
const playerBuilder = PlayerBuilderFactory.getBuilder('Player');
const dailyTaskBuilder = BoxBuilderFactory.getBuilder('PredefinedDailyTask');

beforeAll(async () => {
// Ensure the collection exists before SessionStarter opens a transaction.
await soulHomeModel.init();
});

beforeEach(async () => {
starter = await BoxModule.getSessionStarterService();

Expand All @@ -43,6 +53,7 @@ describe('SessionStarterService.start() test suite', () => {
.setAdminPlayerId(new ObjectId(adminInDb._id))
.setAdminProfileId(new ObjectId(adminProfInDb._id))
.setClansToCreate([{ name: 'sessionClan1' }, { name: 'sessionClan2' }])
.setTestersAmount(20)
.setDailyTasks([task1, task2])
.build();

Expand All @@ -67,16 +78,23 @@ describe('SessionStarterService.start() test suite', () => {
expect(isStarted).toBe(true);
});

it('Should create predefined daily tasks for each clan', async () => {
it('Should create every server and UI daily task for each clan', async () => {
await starter.start(existingBox._id);

const box = await boxModel.findById(existingBox._id);
const clanDailyTask = existingBox.dailyTasks;
const boxDailyTasksInDB = await dailyTaskModel.find({
clan_id: { $in: box.createdClan_ids },
});

expect(boxDailyTasksInDB).toHaveLength(clanDailyTask.length * 2);
const expectedTypes = [
...Object.values(ServerTaskName),
...Object.values(UITaskName),
];

for (const clanId of box.createdClan_ids) {
const clanTasks = await dailyTaskModel.find({ clan_id: clanId });
const taskTypes = clanTasks.map((task) => task.type);

expect(clanTasks).toHaveLength(BOX_SESSION_TASK_COUNT);
expect(new Set(taskTypes)).toHaveProperty('size', BOX_SESSION_TASK_COUNT);
expect(taskTypes).toEqual(expect.arrayContaining(expectedTypes));
}
});

it('Should set testers shared password for a box', async () => {
Expand Down Expand Up @@ -167,4 +185,30 @@ describe('SessionStarterService.start() test suite', () => {
expect(clanNames).toContain(name);
});
});

it('Should persist equal member limits and target points for an even participant count', async () => {
await starter.start(existingBox._id);

const boxInDB = await boxModel.findById(existingBox._id);
const clans = await Promise.all(
boxInDB.createdClan_ids.map((clanId) => clanModel.findById(clanId)),
);

expect(clans.map((clan) => clan.boxMemberLimit)).toEqual([10, 10]);
expect(clans.map((clan) => clan.targetPoints)).toEqual([4200, 4200]);
});

it('Should give the first clan the extra member for an odd participant count', async () => {
await boxModel.findByIdAndUpdate(existingBox._id, { testersAmount: 29 });

await starter.start(existingBox._id);

const boxInDB = await boxModel.findById(existingBox._id);
const clans = await Promise.all(
boxInDB.createdClan_ids.map((clanId) => clanModel.findById(clanId)),
);

expect(clans.map((clan) => clan.boxMemberLimit)).toEqual([15, 14]);
expect(clans.map((clan) => clan.targetPoints)).toEqual([6300, 5880]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,37 @@ describe('TesterAccountService.addTesterToClan() test suite', () => {
expect(clanAfter.playerCount).toBe(5);
});

it('Should follow Box clan member limits for an odd participant count', async () => {
const tester_ids = await createPlayers(29);
const clan_ids = await createBoxClans([15, 14]);

await runAddTesterToClanAsync(tester_ids, clan_ids);

const clansAfter = await Promise.all(
clan_ids.map((clanId) => clanModel.findById(clanId)),
);
expect(clansAfter.map((clan) => clan.playerCount)).toEqual([15, 14]);
expect(clansAfter.map((clan) => clan.targetPoints)).toEqual([6300, 5880]);
});

it('Should not add a tester when all Box clans are full', async () => {
const [tester_id] = await createPlayers(1);
const clan_ids = await createBoxClans([1, 1]);
await clanModel.updateMany({ _id: { $in: clan_ids } }, { playerCount: 1 });

const [testerClan, errors] = await service.addTesterToClan(
tester_id,
clan_ids,
);

expect(testerClan).toBeNull();
expect(errors).toContainSE_MORE_THAN_MAX();
expect(errors[0].field).toBe('boxMemberLimit');

const playerAfter = await playerModel.findById(tester_id);
expect(playerAfter.clan_id ?? null).toBeNull();
});

it('Should return REQUIRED ServiceError if player_id is null', async () => {
const clan_ids = await createClans(1);
const [testerClan, errors] = await service.addTesterToClan(null, clan_ids);
Expand Down Expand Up @@ -354,6 +385,23 @@ describe('TesterAccountService.addTesterToClan() test suite', () => {
return createdClan_ids;
}

async function createBoxClans(memberLimits: number[]) {
const createdClan_ids: string[] = [];
for (let i = 0; i < memberLimits.length; i++) {
const clanToCreate = clanBuilder
.setName(`box-clan-${i}`)
.setPlayerCount(0)
.setBoxMemberLimit(memberLimits[i])
.setTargetPoints(memberLimits[i] * 420)
.build();
const clanResp = await clanModel.create(clanToCreate);

createdClan_ids.push(clanResp._id.toString());
}

return createdClan_ids;
}

/**
* Runs the addTesterToClan() method for each player _id asynchronously
* @param player_ids
Expand Down
42 changes: 42 additions & 0 deletions src/__tests__/box/dto/configureBox.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { validate } from 'class-validator';
import { ConfigureBoxDto } from '../../../box/dto/configureBox.dto';
import {
BOX_SESSION_MAX_PARTICIPANTS,
BOX_SESSION_MIN_PARTICIPANTS,
} from '../../../box/consts/boxSessionConstants';

describe('ConfigureBoxDto', () => {
const createDto = (testersAmount?: number) => {
const dto = new ConfigureBoxDto();
dto.testersAmount = testersAmount;
return dto;
};

it.each([BOX_SESSION_MIN_PARTICIPANTS, BOX_SESSION_MAX_PARTICIPANTS])(
'accepts %i participants',
async (testersAmount) => {
await expect(validate(createDto(testersAmount))).resolves.toHaveLength(0);
},
);

it('allows testersAmount to be omitted', async () => {
await expect(validate(createDto())).resolves.toHaveLength(0);
});

it.each([0, -1, BOX_SESSION_MAX_PARTICIPANTS + 1])(
'rejects an out-of-range participant count of %i',
async (testersAmount) => {
const errors = await validate(createDto(testersAmount));

expect(errors).toHaveLength(1);
expect(errors[0].property).toBe('testersAmount');
},
);

it('rejects a non-integer participant count', async () => {
const errors = await validate(createDto(1.5));

expect(errors).toHaveLength(1);
expect(errors[0].constraints).toHaveProperty('isInt');
});
});
Loading
Loading