Fix nuScore double lineup synchronization
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m0s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m0s
This commit is contained in:
146
frontend/tests/lineupResolver.test.mjs
Normal file
146
frontend/tests/lineupResolver.test.mjs
Normal file
@@ -0,0 +1,146 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import vm from 'node:vm';
|
||||
import { resolveLineupToken } from '../src/services/lineupResolver.mjs';
|
||||
|
||||
// Exercise the actual dialog methods without mounting its network/UI lifecycle.
|
||||
const source = readFileSync(new URL('../src/components/MatchReportApiDialog.vue', import.meta.url), 'utf8');
|
||||
const script = source.match(/<script>([\s\S]*?)<\/script>/)[1]
|
||||
.replace(/^import .*;\n/gm, '')
|
||||
.replace('export default', 'globalThis.component =');
|
||||
const context = vm.createContext({ resolveLineupToken, console });
|
||||
vm.runInContext(script, context);
|
||||
const methods = context.component.methods;
|
||||
const player = (id, name, single, double, selected = true) => ({
|
||||
nuLigaPersonId: id, firstname: name, isSelected: selected,
|
||||
positionSingle: single, positionDouble: double,
|
||||
});
|
||||
const home = [
|
||||
player(1, 'Fred Swyter', null, null, false),
|
||||
player(2, 'Lukas Wypior', 1, 1),
|
||||
player(3, 'Magdalena Schwalbach', 2, 1),
|
||||
player(4, 'Timo Wolf', 3, 2),
|
||||
player(5, 'Joshua Koch', 4, 2),
|
||||
];
|
||||
const guest = [
|
||||
player(11, 'Anton Schottdorf', 1, 1),
|
||||
player(12, 'Anna Wolf', 2, 2),
|
||||
player(13, 'Raffaele Garofano', 3, 2),
|
||||
player(14, 'Edis Toprak Basaraner', 4, 1),
|
||||
];
|
||||
function dialog(players = structuredClone(home)) {
|
||||
return Object.assign({}, methods, {
|
||||
meetingDetails: {
|
||||
teamLineupHomePlayers: players,
|
||||
teamLineupGuestPlayers: structuredClone(guest),
|
||||
meetingPlayMode: { matchFormations: [
|
||||
{ matchNr: 1, homeLineupPosition: 'D1', guestLineupPosition: 'D1' },
|
||||
{ matchNr: 2, homeLineupPosition: 'D2', guestLineupPosition: 'D2' },
|
||||
{ matchNr: 3, homeLineupPosition: 'E1', guestLineupPosition: 'E2' },
|
||||
] },
|
||||
},
|
||||
currentPlayModeMatrix: [],
|
||||
});
|
||||
}
|
||||
|
||||
test('screenshot lineup resolves both explicit doubles, including the crossed guest pairs', () => {
|
||||
const report = dialog();
|
||||
assert.equal(report.resolveMatchSide({}, 0, 'home'), 'Lukas Wypior / Magdalena Schwalbach');
|
||||
assert.equal(report.resolveMatchSide({}, 0, 'guest'), 'Anton Schottdorf / Edis Toprak Basaraner');
|
||||
assert.equal(report.resolveMatchSide({}, 1, 'home'), 'Timo Wolf / Joshua Koch');
|
||||
assert.equal(report.resolveMatchSide({}, 1, 'guest'), 'Anna Wolf / Raffaele Garofano');
|
||||
});
|
||||
|
||||
test('current positions override obsolete match names and unselected singles', () => {
|
||||
const report = dialog();
|
||||
const stale = { playerA1: { firstname: 'Fred Swyter' }, homePlayer: 'Fred Swyter' };
|
||||
assert.equal(report.resolveMatchSide(stale, 2, 'home'), 'Lukas Wypior');
|
||||
assert.equal(report.resolveMatchSide(stale, 0, 'home'), 'Lukas Wypior / Magdalena Schwalbach');
|
||||
assert.equal(report.resolveSide('A4 – B4', 'home'), 'Joshua Koch');
|
||||
});
|
||||
|
||||
test('clearing a double does not resurrect server names or invent a pair from rank', () => {
|
||||
const report = dialog();
|
||||
for (const p of report.meetingDetails.teamLineupHomePlayers) p.positionDouble = null;
|
||||
assert.equal(report.resolveMatchSide({ homePlayer: 'Old / Pair' }, 0, 'home'), '');
|
||||
assert.equal(report.resolveSide('DA1 – DB1', 'home'), '');
|
||||
assert.equal(dialog([{ nuLigaPersonId: 1, firstname: 'One', isSelected: true },
|
||||
{ nuLigaPersonId: 2, firstname: 'Two', isSelected: true }]).resolveSide('DA1 – DB1', 'home'), '');
|
||||
});
|
||||
|
||||
test('nuScore participants remain available when lineup positions are absent', () => {
|
||||
const report = dialog([]);
|
||||
assert.equal(report.resolveMatchSide({ playerA1: { firstname: 'One' }, playerA2: { firstname: 'Two' } }, 0, 'home'), 'One / Two');
|
||||
assert.equal(report.resolveMatchSide({ homePlayer: 'One / Two' }, 0, 'home'), 'One / Two');
|
||||
assert.equal(report.resolveMatchSide({ homePlayer: 'nicht angegeben' }, 0, 'home'), '');
|
||||
});
|
||||
|
||||
test('numeric strings and legacy positions work; double-only players stay out of singles', () => {
|
||||
const players = [player(1, 'One', '1', '2'), player(2, 'Two', null, '2', false)];
|
||||
assert.equal(resolveLineupToken(players, 'DA2'), 'One / Two');
|
||||
assert.equal(resolveLineupToken(players, 'A2'), '');
|
||||
assert.equal(resolveLineupToken([{ nuLigaPersonId: 1, firstname: 'Legacy', isSelected: true, positions: ['E1', 'D2'] }], 'DB2'), 'Legacy');
|
||||
assert.equal(resolveLineupToken([{ ...players[0], positionDouble: null, positions: ['D2'] }], 'DA2'), '');
|
||||
});
|
||||
|
||||
test('formation lookup uses match number rather than array order', () => {
|
||||
assert.equal(dialog().resolveMatchSide({ matchNr: 2 }, 0, 'guest'), 'Anna Wolf / Raffaele Garofano');
|
||||
});
|
||||
|
||||
test('a stale three-player matrix gains D2 for four against four without moving singles scores into it', () => {
|
||||
const report = dialog();
|
||||
report.getPlayMode = () => 'braunschweiger system';
|
||||
report.currentPlayModeMatrix = [
|
||||
'DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3',
|
||||
'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3',
|
||||
];
|
||||
report.meetingDetails.meetingPlayMode.matchFormations = [
|
||||
{ matchNr: 1, homeLineupPosition: 'D1', guestLineupPosition: 'D1' },
|
||||
{ matchNr: 2, homeLineupPosition: 'E1', guestLineupPosition: 'E2' },
|
||||
];
|
||||
report.meetingDetails.matches = [
|
||||
{ matchNr: 1, set1A: 11, set1B: 5 },
|
||||
{ matchNr: 2, set1A: 11, set1B: 8, playerA1: { firstname: 'Fred Swyter' } },
|
||||
];
|
||||
report.ensureTtrSnapshots = () => {};
|
||||
report.prepareResults();
|
||||
assert.equal(report.results.length, 10);
|
||||
assert.equal(report.results[1].homeName, 'Timo Wolf / Joshua Koch');
|
||||
assert.equal(report.results[1].guestName, 'Anna Wolf / Raffaele Garofano');
|
||||
assert.equal(report.meetingDetails.matches[1].set1A, 0);
|
||||
assert.equal(report.meetingDetails.matches[6].set1B, 8);
|
||||
assert.equal(report.meetingDetails.matches[6].matchNr, 7);
|
||||
assert.equal(report.meetingDetails.matches[0].set1B, 5);
|
||||
});
|
||||
|
||||
test('an extra double-only player does not change the Braunschweig team-size matrix', () => {
|
||||
const report = dialog([...structuredClone(home), player(100, 'Reserve', null, 2)]);
|
||||
report.getPlayMode = () => 'braunschweiger system';
|
||||
assert.equal(report.getEffectivePlayerCount('home'), 4);
|
||||
});
|
||||
|
||||
test('a player may move between doubles without having to be the final selection', () => {
|
||||
const report = dialog();
|
||||
const lukas = report.meetingDetails.teamLineupHomePlayers[1];
|
||||
const timo = report.meetingDetails.teamLineupHomePlayers[3];
|
||||
// D2 contains Timo and Joshua, so it is full; after freeing one place,
|
||||
// Lukas can be moved directly from D1 to D2.
|
||||
timo.positionDouble = null;
|
||||
report.persistLocalDraftDebounced = () => {};
|
||||
report.broadcastDraftDebounced = () => {};
|
||||
report.syncDraftToServerDebounced = () => {};
|
||||
assert.equal(report.canSelectDoublePosition(lukas, 'home', 2), true);
|
||||
report.toggleDoublePosition(lukas, 'home', 2);
|
||||
assert.equal(lukas.positionDouble, 2);
|
||||
assert.deepEqual(Array.from(lukas.positions), ['E1', 'D2']);
|
||||
});
|
||||
|
||||
test('position arrays retain both doubles after any single-position recalculation', () => {
|
||||
const report = dialog();
|
||||
report.recalculatePositions('teamLineupHomePlayers');
|
||||
assert.deepEqual(Array.from(report.meetingDetails.teamLineupHomePlayers[1].positions), ['E1', 'D1']);
|
||||
assert.deepEqual(Array.from(report.meetingDetails.teamLineupHomePlayers[2].positions), ['E2', 'D1']);
|
||||
assert.deepEqual(Array.from(report.meetingDetails.teamLineupHomePlayers[3].positions), ['E3', 'D2']);
|
||||
assert.deepEqual(Array.from(report.meetingDetails.teamLineupHomePlayers[4].positions), ['E4', 'D2']);
|
||||
});
|
||||
Reference in New Issue
Block a user