Skip to content

Commit

Permalink
test: ✅ scaledTeamAssignments: extend test coverage; GOLD_TEAM_CHAL…
Browse files Browse the repository at this point in the history
…LENGE scenario
  • Loading branch information
CourtHive committed Apr 12, 2024
1 parent da0a41a commit 6530f25
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 21 deletions.
6 changes: 4 additions & 2 deletions src/assemblies/generators/mocks/generateEventWithDraw.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { generateDrawDefinition } from '../drawDefinitions/generateDrawDefinition/generateDrawDefinition';
import { automatedPlayoffPositioning } from '@Mutate/drawDefinitions/automatedPlayoffPositioning';
import { setParticipantScaleItem } from '@Mutate/participants/scaleItems/addScaleItems';
import { checkRequiredParameters } from '@Helpers/parameters/checkRequiredParameters';
import { completeDrawMatchUps, completeDrawMatchUp } from './completeDrawMatchUps';
import { addPlayoffStructures } from '@Mutate/drawDefinitions/addPlayoffStructures';
import { isMatchUpEventType } from '@Helpers/matchUpEventTypes/isMatchUpEventType';
import { setParticipantScaleItem } from '@Mutate/participants/scaleItems/addScaleItems';
import { addDrawDefinition } from '@Mutate/drawDefinitions/addDrawDefinition';
import { addParticipants } from '@Mutate/participants/addParticipants';
import { allDrawMatchUps } from '@Query/matchUps/getAllDrawMatchUps';
Expand Down Expand Up @@ -76,6 +76,7 @@ export function generateEventWithDraw(params) {
drawExtensions,
completionGoal,
tieFormatName,
buildTeams,
seedsCount,
timeItems,
drawName,
Expand Down Expand Up @@ -229,11 +230,12 @@ export function generateEventWithDraw(params) {
mIndex += genders[MALE];
rIndex += mixedCount;

const individualParticipantIds = buildTeams !== false ? [...fPIDs, ...mPIDs, ...rIDs] : [];
return {
individualParticipantIds: [...fPIDs, ...mPIDs, ...rIDs],
participantOtherName: `TM${teamIndex + 1}`,
participantName: `Team ${teamIndex + 1}`,
participantRole: COMPETITOR,
individualParticipantIds,
participantType: TEAM,
participantId: UUID(),
};
Expand Down
11 changes: 6 additions & 5 deletions src/mutate/participants/scaledTeamAssignment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { participantScaleItem } from '@Query/participant/participantScaleItem';
import { getParticipantId } from '@Functions/global/extractors';
import { getFlightProfile } from '@Query/event/getFlightProfile';
import { addParticipants } from './addParticipants';
import { isConvertableInteger } from '@Tools/math';
import { generateRange } from '@Tools/arrays';
import { addParticipants } from './addParticipants';

// constants and types
import { INDIVIDUAL, TEAM_PARTICIPANT } from '@Constants/participantConstants';
import { Event, Participant, Tournament } from '@Types/tournamentTypes';
import { DIRECT_ACCEPTANCE } from '@Constants/entryStatusConstants';
import { COMPETITOR } from '@Constants/participantRoles';
Expand All @@ -20,7 +22,6 @@ import {
PARTICIPANT_NOT_FOUND,
TEAM_NOT_FOUND,
} from '@Constants/errorConditionConstants';
import { INDIVIDUAL, TEAM_PARTICIPANT } from '@Constants/participantConstants';

/*
scaledParticipants are equivalent to scaledEntries
Expand All @@ -36,13 +37,13 @@ scaleAttributes can include { accessor: 'attribute' } which will return scaleIte
*/

type ScaledTeamAssignmentArgs = {
clearExistingAssignments?: boolean;
individualParticipantIds?: string[];
clearExistingAssignments?: boolean;
reverseAssignmentOrder?: boolean;
initialTeamIndex?: number;
scaledParticipants?: any[];
teamParticipantIds?: string[];
tournamentRecord: Tournament;
scaledParticipants?: any[];
initialTeamIndex?: number;
scaleAttributes?: any;
teamNameBase?: string;
teamsCount?: number;
Expand Down
12 changes: 3 additions & 9 deletions src/tests/mutations/events/generateLineUps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ it('will assign TEAM positions based on ranking', () => {
scaleAllParticipants: true,
};
const {
tournamentRecord,
drawIds: [drawId],
} = mocksEngine.generateTournamentRecord({
tournamentName: 'Gold Team Challenge',
participantsProfile,
setState: true,
drawProfiles: [
{
category: { ageCategoryCode: categoryName },
Expand All @@ -116,9 +116,6 @@ it('will assign TEAM positions based on ranking', () => {
],
});

const result = tournamentEngine.setState(tournamentRecord);
expect(result.success).toEqual(true);

const { participants } = tournamentEngine.getParticipants({
withIndividualParticipants: true,
withScaleValues: true,
Expand Down Expand Up @@ -202,12 +199,12 @@ it('can generate lineUps for TEAM events', () => {
};
const {
eventIds: [eventId],
tournamentRecord,
drawIds,
} = mocksEngine.generateTournamentRecord({
completeAllMatchUps: true,
participantsProfile,
policyDefinitions,
setState: true,
drawProfiles: [
{
category: { ageCategoryCode: categoryName },
Expand All @@ -218,9 +215,6 @@ it('can generate lineUps for TEAM events', () => {
],
});

let result = tournamentEngine.setState(tournamentRecord);
expect(result.success).toEqual(true);

const { matchUps } = tournamentEngine.allTournamentMatchUps();
// all matchUps cannot be complelted if all participants have not been assigned propertly
expect(matchUps.every((m) => m.winningSide)).toEqual(true);
Expand All @@ -233,7 +227,7 @@ it('can generate lineUps for TEAM events', () => {

// !!!!!!!!!!!!!!!!!!!!!!!!! DELETE DRAW_DEFINITION !!!!!!!!!!!!!!!!!!!!!!!!!!
// Now delete the draw and all of the existing pairParticipants
result = tournamentEngine.deleteDrawDefinitions({ drawIds });
let result = tournamentEngine.deleteDrawDefinitions({ drawIds });
expect(result.error).toEqual(SCORES_PRESENT);

result = tournamentEngine.deleteDrawDefinitions({ drawIds, force: true });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { participantScaleItem } from '@Query/participant/participantScaleItem';
import tournamentEngine from '@Engines/syncEngine';
import mocksEngine from '@Assemblies/engines/mock';
import { expect, it } from 'vitest';

// constants
import { USTA_GOLD_TEAM_CHALLENGE } from '@Constants/tieFormatConstants';
import { SINGLES_EVENT, TEAM_EVENT } from '@Constants/eventConstants';
import { INDIVIDUAL } from '@Constants/participantConstants';
import { FEMALE, MALE } from '@Constants/genderConstants';
import { ScaleAttributes } from '@Types/factoryTypes';
import { RANKING } from '@Constants/scaleConstants';

it('can generate balanced gendered teams for Mixed Gender events', () => {
const GOLD_TEAM_SIZE = 8;
const eventId = 'eid';
const drawId = 'did';
const drawSize = 8;
const C18U = '18U';

const mockProfile = {
participantsProfile: { category: { categoryName: '18U' }, scaleAllParticipants: true },
tournamentName: 'Gold Team Challenge',
setState: true,
drawProfiles: [
{
tieFormatName: USTA_GOLD_TEAM_CHALLENGE,
category: { ageCategoryCode: C18U },
eventType: TEAM_EVENT,
buildTeams: false,
generate: false,
drawSize,
eventId,
drawId,
},
],
};

mocksEngine.generateTournamentRecord(mockProfile);

const participants = tournamentEngine.getParticipants().participants;

// expect that teams are generated but have no individualParticipantIds
const entries = tournamentEngine.getEvent({ eventId }).event.entries;
const teamParticipantIds = entries.map((entry) => entry.participantId);
const enteredTeams = participants.filter((p) => teamParticipantIds.includes(p.participantId));
expect(enteredTeams.every((team) => !team.individualParticipantIds.length)).toBe(true);

const individualParticipants = participants.filter((p) => p.participantType === INDIVIDUAL);
const individualParticipantsCount = drawSize * GOLD_TEAM_SIZE;
const femaleParticipants = individualParticipants
.filter((p) => p.person.sex === FEMALE)
.slice(0, individualParticipantsCount / 2);
const maleParticipants = individualParticipants
.filter((p) => p.person.sex === MALE)
.slice(0, individualParticipantsCount / 2);

expect(femaleParticipants.length).toBe(maleParticipants.length);
expect(femaleParticipants.length).toBe(individualParticipantsCount / 2);

const scaleAttributes: ScaleAttributes = {
eventType: SINGLES_EVENT,
scaleType: RANKING,
scaleName: C18U,
};

const scaledFemaleParticipants = femaleParticipants.map((participant) => ({
scaleValue: participantScaleItem({ participant, scaleAttributes })?.scaleItem?.scaleValue,
participantId: participant.participantId,
}));
let result = tournamentEngine.scaledTeamAssignment({
scaledParticipants: scaledFemaleParticipants,
teamParticipantIds,
});
expect(result.success).toBe(true);

const scaledMaleParticipants = maleParticipants.map((participant) => ({
scaleValue: participantScaleItem({ participant, scaleAttributes })?.scaleItem?.scaleValue,
participantId: participant.participantId,
}));
result = tournamentEngine.scaledTeamAssignment({
scaledParticipants: scaledMaleParticipants,
clearExistingAssignments: false,
teamParticipantIds,
});
expect(result.success).toBe(true);

const teamsWithIndividualParticipants = tournamentEngine.getParticipants({
participantFilters: { participantIds: teamParticipantIds },
withIndividualParticipants: true,
}).participants;
expect(teamsWithIndividualParticipants.every((team) => team.individualParticipantIds.length === GOLD_TEAM_SIZE)).toBe(
true,
);

const teamRankingProfiles = teamsWithIndividualParticipants.map((team) => {
return team.individualParticipants.map((participant) => {
const scaleItem = participantScaleItem({ participant, scaleAttributes })?.scaleItem;
return { gender: participant.person.sex, value: scaleItem?.scaleValue };
});
});

/**
* Team Males and Females have been separately waterfalled by ranking value
* This test confirms that the ranking values are in the expected order
*/
teamRankingProfiles.forEach((teamRankingProfile, i) => {
if (i) {
const previousTeamRankingProfile = teamRankingProfiles[i - 1];
teamRankingProfile.forEach((rankingProfile, j) => {
const previousRankingProfile = previousTeamRankingProfile[j];
const expectLess = j % 2;
if (expectLess) {
expect(rankingProfile.value).toBeLessThan(previousRankingProfile.value);
} else {
expect(rankingProfile.value).toBeGreaterThan(previousRankingProfile.value);
}
});
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import mocksEngine from '@Assemblies/engines/mock';
import { generateRange } from '@Tools/arrays';
import { expect, it } from 'vitest';

// constants
// constants and types
import { INVALID_PARTICIPANT_IDS, INVALID_VALUES, MISSING_VALUE } from '@Constants/errorConditionConstants';
import { TEAM_PARTICIPANT } from '@Constants/participantConstants';
import { SINGLES_EVENT, TEAM_EVENT } from '@Constants/eventConstants';
import { TEAM_PARTICIPANT } from '@Constants/participantConstants';
import { UNGROUPED } from '@Constants/entryStatusConstants';
import { COMPETITOR } from '@Constants/participantRoles';
import { ScaleAttributes } from '@Types/factoryTypes';
Expand All @@ -32,11 +32,10 @@ it('can automatically assign participants to teams using individualParticipantId
eventIds: [eventId],
} = mocksEngine.generateTournamentRecord({
participantsProfile,
setState: true,
eventProfiles,
});

tournamentEngine.setState(tournamentRecord);

const individualParticipantIds = tournamentRecord.participants.map(getParticipantId);

let result = tournamentEngine.addEventEntries({
Expand Down Expand Up @@ -174,8 +173,8 @@ it('can automatically assign participants to teams using scaledParticipants', ()
};

const scaledParticipants = individualParticipants.map((participant) => ({
participantId: participant.participantId,
scaleValue: participantScaleItem({ participant, scaleAttributes })?.scaleItem?.scaleValue,
participantId: participant.participantId,
}));

const teamParticipantIds = teamParticipants.map(getParticipantId);
Expand Down

0 comments on commit 6530f25

Please sign in to comment.