Files
CC-Manager/server/test/scraper.test.ts
T
Harlekin 724f68644b Umlaute statt Umschreibungen
Oberflaeche, Fehlermeldungen und Kommentare schrieben durchgehend ae, oe, ue
und ss. Dafuer gab es keinen Grund - die Anwendung ist deutschsprachig und
laeuft durchgehend in UTF-8.

Betroffen waren 55 Dateien, darunter alle sichtbaren Texte: Guthaben-Zaehler,
Import, Nutzerverwaltung, Passwortwechsel und die Zwei-Faktor-Einrichtung.

Der Name einer Migration bleibt im README-Beispiel bewusst bei ASCII, weil
daraus ein Verzeichnisname wird.
2026-09-18 16:57:39 +02:00

143 lines
4.8 KiB
TypeScript

import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, it } from 'node:test';
import { classifyPackage, parseProfile, type ScrapedPackage } from '../src/lib/gextension.js';
import { looksLikeSteamId, normalizeSteamId, toLegacySteamId } from '../src/lib/steamid.js';
const here = dirname(fileURLToPath(import.meta.url));
const FIXTURE = readFileSync(join(here, 'fixtures', 'profil.html'), 'utf8');
function pkg(overrides: Partial<ScrapedPackage>): ScrapedPackage {
return {
packageBoughtId: 1,
packageName: 'Custom Character',
serverBundle: 'SCP-RP',
purchasedAt: null,
amount: '0.00 EUR',
gateway: '',
revoked: false,
...overrides,
};
}
describe('Profil auslesen', () => {
const profile = parseProfile(FIXTURE, '76561198000000999');
it('findet alle Pakete', () => {
assert.equal(profile.packages.length, 8);
});
it('liest Titel, Bereich und Kaufdatum', () => {
const cc = profile.packages.find((p) => p.packageBoughtId === 9001);
assert.ok(cc);
assert.equal(cc.packageName, 'Custom Character');
assert.equal(cc.serverBundle, 'SCP-RP');
assert.equal(cc.purchasedAt?.getFullYear(), 2025);
assert.equal(cc.purchasedAt?.getMonth(), 9, 'Oktober');
assert.equal(cc.purchasedAt?.getDate(), 6);
});
it('erkennt stornierte Käufe', () => {
const revoked = profile.packages.find((p) => p.packageBoughtId === 9007);
assert.equal(revoked?.revoked, true);
});
it('liest den Nicknamen aus der Allgemein-Box', () => {
assert.equal(profile.nickname, 'Testspieler');
});
it('kommt mit kaputtem HTML klar, ohne alles zu verlieren', () => {
const broken = FIXTURE.replace(
'donations_data[9004] = {"id"',
'donations_data[9004] = {kaputt"id"',
);
const result = parseProfile(broken, '76561198000000999');
assert.equal(result.packages.length, 7, 'nur die kaputte Zeile fällt weg');
});
});
describe('Pakete zuordnen', () => {
it('erkennt ein CC-Paket', () => {
assert.deepEqual(classifyPackage(pkg({ packageName: 'Custom Character' })), {
kind: 'package',
target: 'CC_PACKAGE',
});
});
it('erkennt die Schreibweise mit K', () => {
assert.deepEqual(classifyPackage(pkg({ packageName: 'Custom Charakter-Beantragung' })), {
kind: 'package',
target: 'CC_PACKAGE',
});
});
it('zählt "Custom Character Redesign" als Redesign, nicht als CC', () => {
assert.deepEqual(classifyPackage(pkg({ packageName: 'Custom Character Redesign' })), {
kind: 'package',
target: 'REDESIGN_PACKAGE',
});
});
it('liest den Verbrauchszähler samt Anzahl', () => {
const result = classifyPackage(
pkg({ packageName: 'CC-Paket oder Redesign genutzt | 3 Mal' }),
);
assert.deepEqual(result, { kind: 'usage_counter', times: 3 });
});
it('ignoriert Merch und Ränge trotz SCP-RP-Tag', () => {
assert.equal(classifyPackage(pkg({ packageName: 'FG-Tasse | Merch' })).kind, 'ignore');
assert.equal(classifyPackage(pkg({ packageName: '25 Ingame-Level' })).kind, 'ignore');
assert.equal(classifyPackage(pkg({ packageName: 'VIP (12 Monate)' })).kind, 'ignore');
});
it('ignoriert alles aus dem Web-Bereich', () => {
const result = classifyPackage(
pkg({ packageName: 'Ablassbrief (01.04.2026)', serverBundle: 'Web' }),
);
assert.equal(result.kind, 'ignore');
});
it('bucht ein storniertes Paket nicht', () => {
const result = classifyPackage(pkg({ packageName: 'Custom Character', revoked: true }));
assert.equal(result.kind, 'ignore');
});
it('schiebt unklare CC-Titel in die Handprüfung statt zu raten', () => {
assert.equal(classifyPackage(pkg({ packageName: 'CC Sonderaktion Winter' })).kind, 'unclear');
});
});
describe('SteamID-Schreibweisen', () => {
// Dieselbe (erfundene) Kennung in drei Formaten.
const legacy = 'STEAM_0:1:19867635';
const modern = '[U:1:39735271]';
const sixtyFour = '76561198000000999';
it('führt alle drei Formate auf dieselbe ID zusammen', () => {
assert.equal(normalizeSteamId(legacy), sixtyFour);
assert.equal(normalizeSteamId(modern), sixtyFour);
assert.equal(normalizeSteamId(sixtyFour), sixtyFour);
});
it('rechnet zurück in die Legacy-Form', () => {
assert.equal(toLegacySteamId(sixtyFour), legacy);
});
it('beherrscht auch das ungerade Bit', () => {
const odd = 'STEAM_0:1:12345678';
const asNumber = normalizeSteamId(odd);
assert.ok(asNumber);
assert.equal(toLegacySteamId(asNumber), odd);
});
it('weist Unsinn ab', () => {
assert.equal(normalizeSteamId('Darkbrine44'), null);
assert.equal(normalizeSteamId(''), null);
assert.equal(normalizeSteamId('12345'), null);
assert.equal(looksLikeSteamId('Darkbrine44'), false);
});
});