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
114 changes: 114 additions & 0 deletions __tests__/csvAlgorithm.tableAssignment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { validateCsvBlob } from '@utils/csv-ingestion/csvAlgorithm';

type TeamRow = {
tableNumber: number;
projectTitle: string;
status: string;
primaryTrack: string;
};

function buildCsv(rows: TeamRow[]): string {
const header = [
'Table Number',
'Project Status',
'Project Title',
'Track #1 (Primary Track)',
'Track #2',
'Track #3',
'Opt-In Prizes',
].join(',');

const lines = rows.map((row) =>
[
String(row.tableNumber),
row.status,
row.projectTitle,
row.primaryTrack,
'',
'',
'',
].join(',')
);

return `${header}\n${lines.join('\n')}`;
}

describe('csvAlgorithm table assignment', () => {
it('assigns the first hardware team to A1', async () => {
const csv = buildCsv([
{
tableNumber: 1,
status: 'Submitted',
projectTitle: 'Hardware Team',
primaryTrack: 'Best Hardware Hack',
},
{
tableNumber: 2,
status: 'Submitted',
projectTitle: 'Other Team',
primaryTrack: 'Best AI/ML Hack',
},
]);

const res = await validateCsvBlob(new Blob([csv], { type: 'text/csv' }));

expect(res.ok).toBe(true);
expect(res.body).not.toBeNull();

const hardwareTeam = res.body?.find((t) => t.name === 'Hardware Team');
expect(hardwareTeam?.tableNumber).toBe('A1');
});

it('starts floor 2 at I1 after floor 1 capacity is filled', async () => {
// Floor 1: 8 rows * 13 seats = 104. Floor 2 starts at 105th team
const rows: TeamRow[] = Array.from({ length: 105 }, (_, i) => ({
tableNumber: i + 1,
status: 'Submitted',
projectTitle: `Team ${i + 1}`,
primaryTrack: 'Best AI/ML Hack',
}));

const csv = buildCsv(rows);
const res = await validateCsvBlob(new Blob([csv], { type: 'text/csv' }));

if (!res.ok) {
console.error('Unexpected error:', res.error);
}
expect(res.ok).toBe(true);
expect(res.body).not.toBeNull();
expect(res.body?.length).toBe(105);
// Last team on floor 1
expect(res.body?.[103].tableNumber).toBe('H13');
// First team on floor 2
expect(res.body?.[104].tableNumber).toBe('I1');
});

it('returns a global warning when team count exceeds venue capacity', async () => {
// Total capacity: 104 (F1) + 60 (F2) = 164
// We provide 167 teams to trigger WAIT-n overflow labels.
const rows: TeamRow[] = Array.from({ length: 167 }, (_, i) => ({
tableNumber: i + 1,
status: 'Submitted',
projectTitle: `Team ${i + 1}`,
primaryTrack: 'Best AI/ML Hack',
}));

const csv = buildCsv(rows);
const res = await validateCsvBlob(new Blob([csv], { type: 'text/csv' }));

// Capacity overflow is non-blocking and surfaced as a global warning.
expect(res.ok).toBe(true);
expect(res.error).toBeNull();
expect(res.report.errorRows).toBe(0);
expect(res.report.warningRows).toBe(0);
expect(res.report.globalWarnings).toBeDefined();
expect(res.report.globalWarnings?.[0]).toContain('Capacity Exceeded');

// Verify that even with overflow, data was processed.
expect(res.body).toHaveLength(167);

// Verify the last team got a WAIT label.
const lastTeam = res.body?.[166];
expect(lastTeam?.tableNumber).toBe('WAIT-3');
});
});
14 changes: 7 additions & 7 deletions __tests__/logic/ingestTeams.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ describe('ingestTeams', () => {
{
name: 'Team 1',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
{
name: 'Team 2',
teamNumber: 2,
tableNumber: 2,
tableNumber: 'A2',
tracks: ['Track B'],
active: true,
},
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('ingestTeams', () => {
{
name: 'Invalid Team',
teamNumber: 999,
tableNumber: 999,
tableNumber: '999',
tracks: ['Invalid Track'],
active: true,
},
Expand All @@ -99,14 +99,14 @@ describe('ingestTeams', () => {
{
name: 'Team 1',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
{
name: 'Team 1 Duplicate',
teamNumber: 1,
tableNumber: 2,
tableNumber: 'A2',
tracks: ['Track B'],
active: true,
},
Expand All @@ -131,7 +131,7 @@ describe('ingestTeams', () => {
{
name: 'Solo Team',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A', 'Track B'],
active: true,
},
Expand All @@ -157,7 +157,7 @@ describe('ingestTeams', () => {
{
name: 'Complete Team',
teamNumber: 42,
tableNumber: 10,
tableNumber: 'A10',
tracks: ['Track A', 'Track B', 'Track C'],
active: false,
},
Expand Down
12 changes: 6 additions & 6 deletions __tests__/logic/validateCSV.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('validateCSV', () => {
{
name: 'Test Project',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
Expand Down Expand Up @@ -134,7 +134,7 @@ describe('validateCSV', () => {
{
name: 'Test',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
Expand Down Expand Up @@ -178,7 +178,7 @@ describe('validateCSV', () => {
{
name: 'Test',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
Expand Down Expand Up @@ -218,14 +218,14 @@ describe('validateCSV', () => {
{
name: 'Valid Team',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
{
name: 'Invalid Team',
teamNumber: NaN,
tableNumber: 2,
tableNumber: 'A2',
tracks: ['Track B'],
active: true,
},
Expand All @@ -235,7 +235,7 @@ describe('validateCSV', () => {
{
name: 'Valid Team',
teamNumber: 1,
tableNumber: 1,
tableNumber: 'A1',
tracks: ['Track A'],
active: true,
},
Expand Down
6 changes: 2 additions & 4 deletions __tests__/parseInviteCSV.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ describe('parseInviteCSV', () => {
});

it('detects header with "first" keyword', () => {
const csv =
'First,Last,Contact\nAlice,Smith,alice@example.com\n';
const csv = 'First,Last,Contact\nAlice,Smith,alice@example.com\n';

const result = parseInviteCSV(csv);
expect(result.ok).toBe(true);
Expand Down Expand Up @@ -165,8 +164,7 @@ describe('parseInviteCSV', () => {

it('handles quoted fields with commas', () => {
const csv =
'First Name,Last Name,Email\n' +
'"Alice, Jr.",Smith,alice@example.com\n';
'First Name,Last Name,Email\n' + '"Alice, Jr.",Smith,alice@example.com\n';

const result = parseInviteCSV(csv);
expect(result.ok).toBe(true);
Expand Down
10 changes: 6 additions & 4 deletions __tests__/processBulkInvites.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,12 @@ describe('processBulkInvites', () => {
it('uses preprocess to filter items and include early results', async () => {
mockParseCSV.mockReturnValue({ ok: true, body: [ALICE, BOB, CHARLIE] });

const processOne = jest.fn(async (item: InviteData): Promise<InviteResult> => ({
email: item.email,
success: true,
}));
const processOne = jest.fn(
async (item: InviteData): Promise<InviteResult> => ({
email: item.email,
success: true,
})
);

const result = await processBulkInvites('csv', {
label: 'Test',
Expand Down
Loading
Loading