madden-fantasy-extractor 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { extractTransactions } from '../src/extract/transactions.js';
4
+ import { fakeTable, fakeRecord, fakeFranchise } from './helpers/fake-franchise.js';
5
+
6
+ // classify() isn't exported (internal to transactions.js) — driven through the
7
+ // public extractTransactions path instead, against fakes shaped like the real
8
+ // madden-franchise API, so these exercise the actual resolveFieldRef code path.
9
+
10
+ test('trade: OldTeam != NewTeam, Signed->Signed', async () => {
11
+ const player = fakeRecord({ PresentationId: 100 });
12
+ const playerTable = fakeTable('Player', [player]);
13
+ const teamA = fakeRecord({ TeamIndex: 0 });
14
+ const teamB = fakeRecord({ TeamIndex: 1 });
15
+ const teamTable = fakeTable('Team', [teamA, teamB]);
16
+
17
+ const tx = fakeRecord(
18
+ { SeasonYear: 0, SeasonStage: 'NFLSeason', SeasonWeek: 0, ContractStatus: 'Signed', OldContractStatus: 'Signed' },
19
+ {
20
+ Player: { tableId: playerTable._id, rowNumber: 0 },
21
+ OldTeam: { tableId: teamTable._id, rowNumber: 0 },
22
+ NewTeam: { tableId: teamTable._id, rowNumber: 1 },
23
+ },
24
+ );
25
+ const txTable = fakeTable('PlayerTransactionHistoryEntry', [tx]);
26
+
27
+ const franchise = fakeFranchise([playerTable, teamTable, txTable]);
28
+ const indexTeamsByTeamIndex = new Map([
29
+ [0, { externalTeamId: 10, teamIndex: 0 }],
30
+ [1, { externalTeamId: 20, teamIndex: 1 }],
31
+ ]);
32
+
33
+ const rows = await extractTransactions(franchise, { indexTeamsByTeamIndex });
34
+ assert.equal(rows.length, 1);
35
+ assert.equal(rows[0].classifiedType, 'trade');
36
+ assert.equal(rows[0].oldExternalTeamId, 10);
37
+ assert.equal(rows[0].newExternalTeamId, 20);
38
+ });
39
+
40
+ test('ps_sign: null -> real team, FreeAgent->PracticeSquad (not in the original findings.md table)', async () => {
41
+ const player = fakeRecord({ PresentationId: 200 });
42
+ const playerTable = fakeTable('Player', [player]);
43
+ const teamB = fakeRecord({ TeamIndex: 1 });
44
+ const teamTable = fakeTable('Team', [teamB]);
45
+
46
+ const tx = fakeRecord(
47
+ { SeasonYear: 0, SeasonStage: 'PreSeason', SeasonWeek: 0, ContractStatus: 'PracticeSquad', OldContractStatus: 'FreeAgent' },
48
+ {
49
+ Player: { tableId: playerTable._id, rowNumber: 0 },
50
+ OldTeam: { tableId: 0, rowNumber: 0 }, // tableId 0 = unresolvable/no team (findings-confirmed sentinel)
51
+ NewTeam: { tableId: teamTable._id, rowNumber: 0 },
52
+ },
53
+ );
54
+ const txTable = fakeTable('PlayerTransactionHistoryEntry', [tx]);
55
+
56
+ const franchise = fakeFranchise([playerTable, teamTable, txTable]);
57
+ const indexTeamsByTeamIndex = new Map([[1, { externalTeamId: 20, teamIndex: 1 }]]);
58
+
59
+ const rows = await extractTransactions(franchise, { indexTeamsByTeamIndex });
60
+ assert.equal(rows.length, 1);
61
+ assert.equal(rows[0].classifiedType, 'ps_sign');
62
+ assert.equal(rows[0].oldExternalTeamId, null);
63
+ });
64
+
65
+ test('cut: real team -> null, Signed->FreeAgent', async () => {
66
+ const player = fakeRecord({ PresentationId: 300 });
67
+ const playerTable = fakeTable('Player', [player]);
68
+ const teamA = fakeRecord({ TeamIndex: 0 });
69
+ const teamTable = fakeTable('Team', [teamA]);
70
+
71
+ const tx = fakeRecord(
72
+ { SeasonYear: 0, SeasonStage: 'NFLSeason', SeasonWeek: 5, ContractStatus: 'FreeAgent', OldContractStatus: 'Signed' },
73
+ {
74
+ Player: { tableId: playerTable._id, rowNumber: 0 },
75
+ OldTeam: { tableId: teamTable._id, rowNumber: 0 },
76
+ NewTeam: { tableId: 0, rowNumber: 0 },
77
+ },
78
+ );
79
+ const txTable = fakeTable('PlayerTransactionHistoryEntry', [tx]);
80
+
81
+ const franchise = fakeFranchise([playerTable, teamTable, txTable]);
82
+ const indexTeamsByTeamIndex = new Map([[0, { externalTeamId: 10, teamIndex: 0 }]]);
83
+
84
+ const rows = await extractTransactions(franchise, { indexTeamsByTeamIndex });
85
+ assert.equal(rows[0].classifiedType, 'cut');
86
+ });
87
+
88
+ test('dedupeKey is stable for identical content and differs for different content', async () => {
89
+ const player = fakeRecord({ PresentationId: 400 });
90
+ const playerTable = fakeTable('Player', [player]);
91
+ const teamA = fakeRecord({ TeamIndex: 0 });
92
+ const teamTable = fakeTable('Team', [teamA]);
93
+
94
+ function makeTxTable(newStatus) {
95
+ const tx = fakeRecord(
96
+ { SeasonYear: 0, SeasonStage: 'NFLSeason', SeasonWeek: 0, ContractStatus: newStatus, OldContractStatus: 'FreeAgent' },
97
+ {
98
+ Player: { tableId: playerTable._id, rowNumber: 0 },
99
+ OldTeam: { tableId: 0, rowNumber: 0 },
100
+ NewTeam: { tableId: teamTable._id, rowNumber: 0 },
101
+ },
102
+ );
103
+ return fakeTable('PlayerTransactionHistoryEntry', [tx]);
104
+ }
105
+
106
+ const indexTeamsByTeamIndex = new Map([[0, { externalTeamId: 10, teamIndex: 0 }]]);
107
+
108
+ const franchiseA = fakeFranchise([playerTable, teamTable, makeTxTable('Signed')]);
109
+ const franchiseA2 = fakeFranchise([playerTable, teamTable, makeTxTable('Signed')]);
110
+ const franchiseB = fakeFranchise([playerTable, teamTable, makeTxTable('PracticeSquad')]);
111
+
112
+ const [rowsA] = await Promise.all([extractTransactions(franchiseA, { indexTeamsByTeamIndex })]);
113
+ const [rowsA2] = await Promise.all([extractTransactions(franchiseA2, { indexTeamsByTeamIndex })]);
114
+ const [rowsB] = await Promise.all([extractTransactions(franchiseB, { indexTeamsByTeamIndex })]);
115
+
116
+ assert.equal(rowsA[0].dedupeKey, rowsA2[0].dedupeKey);
117
+ assert.notEqual(rowsA[0].dedupeKey, rowsB[0].dedupeKey);
118
+ });