import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import { startTestDatabase, type TestDatabase } from './harness.js'; type Players = typeof import('../src/services/players.js'); type Scraper = typeof import('../src/services/scraper.js'); type Db = typeof import('../src/db.js'); let database: TestDatabase; let players: Players; let scraper: Scraper; let db: Db; let ctx: { actorId: number; actorName: string }; before(async () => { database = await startTestDatabase(54335); process.env.DATABASE_URL = database.url; process.env.SESSION_SECRET = 'test-secret-that-is-long-enough-000000'; process.env.NODE_ENV = 'test'; db = await import('../src/db.js'); players = await import('../src/services/players.js'); scraper = await import('../src/services/scraper.js'); const user = await db.prisma.user.create({ data: { username: 'pfleger', passwordHash: 'x', role: 'ADMIN' }, }); ctx = { actorId: user.id, actorName: user.username }; }); after(async () => { await db.prisma.$disconnect(); await database.stop(); }); describe('Frühere Konten', () => { it('bringt eine nachgetragene SteamID auf dieselbe Form wie die Hauptangabe', async () => { const player = await db.prisma.player.create({ data: { displayName: 'Umzügler', steamId: '76561198000001111' }, }); // In der Legacy-Schreibweise eingegeben, gespeichert wird die 64-Bit-Form. await players.addAlias(player.id, 'STEAM_ID', 'STEAM_0:1:19867635', 'Alter Account', ctx); const alias = await db.prisma.playerAlias.findFirstOrThrow({ where: { playerId: player.id } }); assert.equal(alias.value, '76561198000000999'); }); it('klappert beim Abgleich auch die früheren Konten ab', async () => { const ids = await scraper.knownSteamIds(); const fuerUmzuegler = ids.filter((e) => e.steamId.startsWith('765611980000')); assert.ok( fuerUmzuegler.some((e) => e.steamId === '76561198000001111'), 'die aktuelle Kennung', ); assert.ok( fuerUmzuegler.some((e) => e.steamId === '76561198000000999'), 'und die frühere', ); }); it('nimmt dieselbe Kennung nicht zweimal in den Lauf', async () => { const ids = await scraper.knownSteamIds(); const eindeutig = new Set(ids.map((e) => e.steamId)); assert.equal(ids.length, eindeutig.size); }); it('lässt ein Konto nicht zwei Spielern gehören', async () => { const anderer = await db.prisma.player.create({ data: { displayName: 'Fremder' } }); await assert.rejects( () => players.addAlias(anderer.id, 'STEAM_ID', '76561198000000999', undefined, ctx), (error: Error & { code?: string }) => error.code === 'ALIAS_TAKEN', ); }); it('weist die eigene Hauptangabe als Alias ab', async () => { const player = await db.prisma.player.findFirstOrThrow({ where: { displayName: 'Umzügler' } }); await assert.rejects( () => players.addAlias(player.id, 'STEAM_ID', '76561198000001111', undefined, ctx), (error: Error & { code?: string }) => error.code === 'IS_PRIMARY', ); }); it('weist Unsinn als SteamID ab', async () => { const player = await db.prisma.player.findFirstOrThrow({ where: { displayName: 'Umzügler' } }); await assert.rejects( () => players.addAlias(player.id, 'STEAM_ID', 'kein-account', undefined, ctx), (error: Error & { code?: string }) => error.code === 'INVALID_STEAMID', ); }); it('nimmt Forum-Namen ohne Umrechnung', async () => { const player = await db.prisma.player.findFirstOrThrow({ where: { displayName: 'Umzügler' } }); const alias = await players.addAlias(player.id, 'FORUM_NAME', 'AlterName2019', undefined, ctx); assert.equal(alias.value, 'AlterName2019'); }); }); describe('Eine SteamID gehört genau einem Spieler', () => { it('nennt den Spieler, bei dem sie schon liegt', async () => { await players.createPlayer( { displayName: 'Hat sie schon', steamId: '76561198000060001' }, ctx, ); await assert.rejects( () => players.createPlayer({ displayName: 'Will sie auch', steamId: '76561198000060001' }, ctx), (error: Error & { code?: string }) => { assert.equal(error.code, 'STEAMID_TAKEN'); assert.match( error.message, /Hat sie schon/, 'ohne den Namen sucht man von Hand durch den ganzen Bestand', ); return true; }, ); }); it('findet sie auch, wenn sie als früheres Konto hängt', async () => { const umzuegler = await players.createPlayer( { displayName: 'Umgezogen', steamId: '76561198000060002' }, ctx, ); await players.addAlias(umzuegler.id, 'STEAM_ID', '76561198000060003', 'Altes Konto', ctx); await assert.rejects( () => players.createPlayer({ displayName: 'Neuling', steamId: '76561198000060003' }, ctx), (error: Error & { code?: string }) => { assert.equal(error.code, 'STEAMID_TAKEN'); assert.match(error.message, /Umgezogen/); assert.match(error.message, /früheres Konto/); return true; }, ); }); it('erkennt sie auch in einer anderen Schreibweise', async () => { // STEAM_0:0:19897141 und 76561198000060010 sind dieselbe Kennung. await players.createPlayer( { displayName: 'Legacy-Schreiber', steamId: '76561198000060010' }, ctx, ); await assert.rejects( () => players.createPlayer({ displayName: 'Doppelt', steamId: 'STEAM_0:0:19897141' }, ctx), (error: Error & { code?: string }) => { assert.equal(error.code, 'STEAMID_TAKEN'); assert.match(error.message, /Legacy-Schreiber/); return true; }, ); }); it('lässt die aktuelle Kennung eines anderen nicht als früheres Konto eintragen', async () => { const einer = await players.createPlayer( { displayName: 'Aktueller Inhaber', steamId: '76561198000060004' }, ctx, ); const anderer = await players.createPlayer( { displayName: 'Möchtegern', steamId: '76561198000060005' }, ctx, ); await assert.rejects( () => players.addAlias(anderer.id, 'STEAM_ID', '76561198000060004', undefined, ctx), (error: Error & { code?: string }) => { assert.equal(error.code, 'ALIAS_TAKEN'); assert.match(error.message, /Aktueller Inhaber/); return true; }, ); assert.ok(einer.id); }); it('stört sich nicht an der eigenen Kennung beim Bearbeiten', async () => { const spieler = await players.createPlayer( { displayName: 'Bleibt sich treu', steamId: '76561198000060006' }, ctx, ); const geaendert = await players.updatePlayer( spieler.id, { displayName: 'Neuer Name', steamId: '76561198000060006' }, ctx, ); assert.equal(geaendert.displayName, 'Neuer Name'); }); });