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.
143 lines
4.8 KiB
TypeScript
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);
|
|
});
|
|
});
|