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.
This commit is contained in:
@@ -13,7 +13,7 @@ export interface TestDatabase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet eine Postgres-Instanz im Speicher und stellt sie ueber einen lokalen
|
||||
* Startet eine Postgres-Instanz im Speicher und stellt sie über einen lokalen
|
||||
* Port bereit, damit Prisma sich wie an eine echte Datenbank verbindet.
|
||||
* So laufen die Tests ohne Docker oder installiertes Postgres.
|
||||
*/
|
||||
@@ -26,7 +26,7 @@ export async function startTestDatabase(port: number): Promise<TestDatabase> {
|
||||
|
||||
return {
|
||||
// connection_limit=1, weil die Testinstanz immer nur eine Verbindung
|
||||
// gleichzeitig bedient. Echtes Postgres braucht die Einschraenkung nicht.
|
||||
// gleichzeitig bedient. Echtes Postgres braucht die Einschränkung nicht.
|
||||
url: `postgresql://postgres:postgres@127.0.0.1:${port}/postgres?connection_limit=1`,
|
||||
stop: async () => {
|
||||
await server.stop();
|
||||
|
||||
+12
-12
@@ -81,7 +81,7 @@ describe('Anmeldung', () => {
|
||||
assert.equal(response.statusCode, 401);
|
||||
});
|
||||
|
||||
it('verraet nicht, ob es den Benutzernamen gibt', async () => {
|
||||
it('verrät nicht, ob es den Benutzernamen gibt', async () => {
|
||||
const unknownUser = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/auth/login',
|
||||
@@ -97,7 +97,7 @@ describe('Anmeldung', () => {
|
||||
assert.equal(unknownUser.json().message, wrongPassword.json().message);
|
||||
});
|
||||
|
||||
it('laesst ein gesperrtes Konto nicht herein', async () => {
|
||||
it('lässt ein gesperrtes Konto nicht herein', async () => {
|
||||
const response = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/auth/login',
|
||||
@@ -129,7 +129,7 @@ describe('CSRF-Schutz', () => {
|
||||
assert.equal(response.json().error, 'FORBIDDEN');
|
||||
});
|
||||
|
||||
it('blockt einen gefaelschten Token', async () => {
|
||||
it('blockt einen gefälschten Token', async () => {
|
||||
const credentials = await login('team');
|
||||
|
||||
const response = await app.inject({
|
||||
@@ -142,7 +142,7 @@ describe('CSRF-Schutz', () => {
|
||||
assert.equal(response.statusCode, 403);
|
||||
});
|
||||
|
||||
it('laesst die Anfrage mit passendem Token durch', async () => {
|
||||
it('lässt die Anfrage mit passendem Token durch', async () => {
|
||||
const credentials = await login('team');
|
||||
|
||||
const response = await app.inject({
|
||||
@@ -155,7 +155,7 @@ describe('CSRF-Schutz', () => {
|
||||
assert.equal(response.statusCode, 201);
|
||||
});
|
||||
|
||||
it('laesst lesende Anfragen ohne Token zu', async () => {
|
||||
it('lässt lesende Anfragen ohne Token zu', async () => {
|
||||
const credentials = await login('gast');
|
||||
|
||||
const response = await app.inject({
|
||||
@@ -227,7 +227,7 @@ describe('Erstpasswort', () => {
|
||||
method: 'POST',
|
||||
url: '/api/players',
|
||||
headers: authHeaders(credentials),
|
||||
payload: { displayName: 'Zu frueh' },
|
||||
payload: { displayName: 'Zu früh' },
|
||||
});
|
||||
|
||||
assert.equal(response.statusCode, 403);
|
||||
@@ -251,8 +251,8 @@ describe('Erstpasswort', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Guthaben ueber die API', () => {
|
||||
it('ein CC-Paket schlaegt in beiden Toepfen auf', async () => {
|
||||
describe('Guthaben über die API', () => {
|
||||
it('ein CC-Paket schlägt in beiden Töpfen auf', async () => {
|
||||
const credentials = await login('team');
|
||||
|
||||
const created = await app.inject({
|
||||
@@ -287,11 +287,11 @@ describe('Guthaben ueber die API', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Auslieferung der Oberflaeche', () => {
|
||||
describe('Auslieferung der Oberfläche', () => {
|
||||
// Diese Header sind der Grund, warum ein Update beim Nutzer ankommt. Wird die
|
||||
// index.html cachebar ausgeliefert, sieht er nach einem Deploy weiter die
|
||||
// alte Oberflaeche - ohne dass irgendwo ein Fehler auftaucht.
|
||||
it('laesst die index.html nicht zwischenspeichern', async () => {
|
||||
// alte Oberfläche - ohne dass irgendwo ein Fehler auftaucht.
|
||||
it('lässt die index.html nicht zwischenspeichern', async () => {
|
||||
const response = await app.inject({ method: 'GET', url: '/' });
|
||||
|
||||
assert.equal(response.statusCode, 200);
|
||||
@@ -309,7 +309,7 @@ describe('Auslieferung der Oberflaeche', () => {
|
||||
assert.match(response.headers['cache-control'] as string, /no-cache/);
|
||||
});
|
||||
|
||||
it('laesst gehashte Assets lange liegen', async () => {
|
||||
it('lässt gehashte Assets lange liegen', async () => {
|
||||
const page = await app.inject({ method: 'GET', url: '/' });
|
||||
const asset = /\/assets\/[^"]+\.js/.exec(page.body)?.[0];
|
||||
assert.ok(asset, 'die Seite verweist auf ein Asset');
|
||||
|
||||
@@ -14,7 +14,7 @@ let ctx: { actorId: number; actorName: string };
|
||||
|
||||
const CSV = [
|
||||
'Bestellnummer;Steam-ID;Spielername;Produkt;Kaufdatum',
|
||||
'A-1001;76561198000000001;Rabe;CC-Paket Gross;2025-01-15',
|
||||
'A-1001;76561198000000001;Rabe;CC-Paket Groß;2025-01-15',
|
||||
'A-1002;76561198000000002;Fuchs;Redesign Gutschein;2025-01-16',
|
||||
'A-1003;76561198000000001;Rabe;Spielerfarbe Blau;2025-01-17',
|
||||
'A-1004;76561198000000003;Dachs;CC-Paket Klein;2025-01-18',
|
||||
@@ -92,7 +92,7 @@ describe('Vorschau und Buchung', () => {
|
||||
|
||||
const summary = await imports.applyMapping(importId, MAPPING, ctx);
|
||||
|
||||
assert.equal(summary.CREATE_PLAYER_AND_BOOK, 3, 'drei neue Spieler mit gueltigem Produkt');
|
||||
assert.equal(summary.CREATE_PLAYER_AND_BOOK, 3, 'drei neue Spieler mit gültigem Produkt');
|
||||
assert.equal(summary.SKIP_IGNORED, 1, 'die Spielerfarbe wird ignoriert');
|
||||
assert.equal(summary.SKIP_DUPLICATE, 0);
|
||||
});
|
||||
@@ -165,7 +165,7 @@ describe('Vorschau und Buchung', () => {
|
||||
assert.equal(summary.SKIP_DUPLICATE, 1);
|
||||
});
|
||||
|
||||
it('ueberspringt unbekannte Spieler, wenn sie nicht angelegt werden sollen', async () => {
|
||||
it('überspringt unbekannte Spieler, wenn sie nicht angelegt werden sollen', async () => {
|
||||
const csv = ['Bestellnummer;Steam-ID;Produkt', 'D-1;76561198000009999;CC-Paket'].join('\n');
|
||||
const parsed = imports.parseUpload('fremd.csv', Buffer.from(csv, 'utf8'));
|
||||
const importId = await imports.createImport('fremd.csv', parsed, ctx);
|
||||
@@ -184,7 +184,7 @@ describe('Vorschau und Buchung', () => {
|
||||
assert.equal(summary.SKIP_NO_PLAYER, 1);
|
||||
});
|
||||
|
||||
it('ein abgeschlossener Import laesst sich nicht erneut buchen', async () => {
|
||||
it('ein abgeschlossener Import lässt sich nicht erneut buchen', async () => {
|
||||
const csv = ['Bestellnummer;Steam-ID;Produkt', 'E-1;76561198000000001;CC-Paket'].join('\n');
|
||||
const parsed = imports.parseUpload('nochmal.csv', Buffer.from(csv, 'utf8'));
|
||||
const importId = await imports.createImport('nochmal.csv', parsed, ctx);
|
||||
|
||||
@@ -18,7 +18,7 @@ let audit: Audit;
|
||||
let db: Db;
|
||||
let ctx: { actorId: number; actorName: string };
|
||||
|
||||
// Ein Export, wie ihn ein Shop liefern koennte: mehr Spalten als die App braucht.
|
||||
// Ein Export, wie ihn ein Shop liefern könnte: mehr Spalten als die App braucht.
|
||||
const CSV = [
|
||||
'Bestellnummer;Steam-ID;Produkt;Email;Rechnungsadresse;Zahlungsart',
|
||||
'P-1;76561198000000501;CC-Paket;spieler@example.com;Musterweg 1, 12345 Musterstadt;PayPal',
|
||||
@@ -45,7 +45,7 @@ before(async () => {
|
||||
audit = await import('../src/services/audit.js');
|
||||
|
||||
const user = await db.prisma.user.create({
|
||||
data: { username: 'datenschuetzer', passwordHash: 'x', role: 'ADMIN' },
|
||||
data: { username: 'datenschützer', passwordHash: 'x', role: 'ADMIN' },
|
||||
});
|
||||
ctx = { actorId: user.id, actorName: user.username };
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('Datenminimierung beim Import', () => {
|
||||
assert.equal(rawAfter['Steam-ID'], '76561198000000501', 'die zugeordnete Spalte bleibt');
|
||||
});
|
||||
|
||||
it('raeumt auch einen verworfenen Import auf', async () => {
|
||||
it('räumt auch einen verworfenen Import auf', async () => {
|
||||
const parsed = imports.parseUpload('shop2.csv', Buffer.from(CSV, 'utf8'));
|
||||
const importId = await imports.createImport('shop2.csv', parsed, ctx);
|
||||
await imports.applyMapping(importId, MAPPING, ctx);
|
||||
@@ -116,7 +116,7 @@ describe('Fehlgeschlagene Anmeldung', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Loeschung eines Spielers', () => {
|
||||
describe('Löschung eines Spielers', () => {
|
||||
it('entfernt auch Spuren in Import-Zeilen und Audit-Details', async () => {
|
||||
// Eigene Bestellnummer, sonst greift zu Recht die Dedup-Logik.
|
||||
const csv = [
|
||||
@@ -152,7 +152,7 @@ describe('Loeschung eines Spielers', () => {
|
||||
const auditEntries = await db.prisma.auditLog.findMany({
|
||||
where: { targetType: 'player', targetId: String(player.id) },
|
||||
});
|
||||
assert.ok(auditEntries.length > 0, 'die Vorgaenge selbst bleiben nachvollziehbar');
|
||||
assert.ok(auditEntries.length > 0, 'die Vorgänge selbst bleiben nachvollziehbar');
|
||||
for (const entry of auditEntries) {
|
||||
const details = JSON.stringify(entry.details ?? {});
|
||||
assert.ok(
|
||||
@@ -164,7 +164,7 @@ describe('Loeschung eines Spielers', () => {
|
||||
});
|
||||
|
||||
describe('Aufbewahrung des Audit-Logs', () => {
|
||||
it('loescht Eintraege jenseits der Frist, neuere bleiben', async () => {
|
||||
it('löscht Einträge jenseits der Frist, neuere bleiben', async () => {
|
||||
const alt = new Date(Date.now() - 400 * 24 * 3600 * 1000);
|
||||
|
||||
const veraltet = await db.prisma.auditLog.create({
|
||||
|
||||
+17
-17
@@ -40,7 +40,7 @@ after(async () => {
|
||||
await database.stop();
|
||||
});
|
||||
|
||||
describe('Guthaben-Toepfe', () => {
|
||||
describe('Guthaben-Töpfe', () => {
|
||||
it('ein CC-Paket erzeugt CC UND bezahltes Redesign', async () => {
|
||||
const playerId = await freshPlayer('Paket-Spieler');
|
||||
const { balances } = await credits.bookCcPackage(playerId, ctx);
|
||||
@@ -58,7 +58,7 @@ describe('Guthaben-Toepfe', () => {
|
||||
assert.equal(balances.REDESIGN_PAID, 1);
|
||||
});
|
||||
|
||||
it('Kulanz landet im eigenen Topf und zaehlt zur Redesign-Summe', async () => {
|
||||
it('Kulanz landet im eigenen Topf und zählt zur Redesign-Summe', async () => {
|
||||
const playerId = await freshPlayer('Kulanz-Spieler');
|
||||
const { balances } = await credits.bookKulanz(playerId, ctx);
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('Guthaben-Toepfe', () => {
|
||||
assert.equal(balances.redesignTotal, 1);
|
||||
});
|
||||
|
||||
it('ein ueberzogenes Konto wird zugelassen, nicht blockiert', async () => {
|
||||
it('ein überzogenes Konto wird zugelassen, nicht blockiert', async () => {
|
||||
const playerId = await freshPlayer('Minus-Spieler');
|
||||
const result = await characters.createCharacter(playerId, { name: 'Vorab-CC' }, ctx);
|
||||
|
||||
@@ -107,7 +107,7 @@ describe('CC-Lebenszyklus', () => {
|
||||
assert.equal(
|
||||
result.character.lineageId,
|
||||
first.character.lineageId,
|
||||
'die Kette behaelt ihre lineageId',
|
||||
'die Kette behält ihre lineageId',
|
||||
);
|
||||
assert.equal(result.balances.REDESIGN_PAID, 0);
|
||||
});
|
||||
@@ -130,7 +130,7 @@ describe('CC-Lebenszyklus', () => {
|
||||
});
|
||||
|
||||
describe('Reaktivierung', () => {
|
||||
it('ein wegen Inaktivitaet entfernter CC kommt gratis zurueck', async () => {
|
||||
it('ein wegen Inaktivität entfernter CC kommt gratis zurück', async () => {
|
||||
const playerId = await freshPlayer('Inaktiver');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
const created = await characters.createCharacter(playerId, { name: 'Geputzt' }, ctx);
|
||||
@@ -144,7 +144,7 @@ describe('Reaktivierung', () => {
|
||||
assert.deepEqual(result.balances, before, 'kein Guthaben wurde bewegt');
|
||||
});
|
||||
|
||||
it('ein reworkter CC kommt NICHT gratis zurueck', async () => {
|
||||
it('ein reworkter CC kommt NICHT gratis zurück', async () => {
|
||||
const playerId = await freshPlayer('Rework-Spieler');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
const first = await characters.createCharacter(playerId, { name: 'Alt' }, ctx);
|
||||
@@ -160,7 +160,7 @@ describe('Reaktivierung', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('ein reworkter CC kommt gegen CC-Guthaben zurueck', async () => {
|
||||
it('ein reworkter CC kommt gegen CC-Guthaben zurück', async () => {
|
||||
const playerId = await freshPlayer('Wiederbeleber');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
@@ -178,7 +178,7 @@ describe('Reaktivierung', () => {
|
||||
assert.equal(result.balances.CC, before.CC - 1);
|
||||
});
|
||||
|
||||
it('auch ein aus anderem Grund entfernter CC kommt gratis zurueck', async () => {
|
||||
it('auch ein aus anderem Grund entfernter CC kommt gratis zurück', async () => {
|
||||
const playerId = await freshPlayer('Einheit-weg');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
const created = await characters.createCharacter(playerId, { name: 'MTF-Operativer' }, ctx);
|
||||
@@ -187,19 +187,19 @@ describe('Reaktivierung', () => {
|
||||
created.character.id,
|
||||
'OTHER',
|
||||
ctx,
|
||||
'Einheit bis Maerz entfernt',
|
||||
'Einheit bis März entfernt',
|
||||
);
|
||||
|
||||
const deactivated = await db.prisma.character.findUniqueOrThrow({
|
||||
where: { id: created.character.id },
|
||||
});
|
||||
assert.equal(deactivated.inactiveNote, 'Einheit bis Maerz entfernt', 'der Grund bleibt lesbar');
|
||||
assert.equal(deactivated.inactiveNote, 'Einheit bis März entfernt', 'der Grund bleibt lesbar');
|
||||
|
||||
const before = await credits.getBalances(playerId);
|
||||
const result = await characters.reactivateFree(created.character.id, ctx);
|
||||
|
||||
assert.equal(result.character.status, 'ACTIVE');
|
||||
assert.equal(result.character.inactiveNote, null, 'die Notiz wird beim Zurueckholen geloescht');
|
||||
assert.equal(result.character.inactiveNote, null, 'die Notiz wird beim Zurückholen gelöscht');
|
||||
assert.deepEqual(result.balances, before, 'kein Guthaben wurde bewegt');
|
||||
});
|
||||
|
||||
@@ -222,7 +222,7 @@ describe('Reaktivierung', () => {
|
||||
});
|
||||
|
||||
describe('Korrekturen', () => {
|
||||
it('ein Paket-Storno nimmt beide Zeilen gemeinsam zurueck', async () => {
|
||||
it('ein Paket-Storno nimmt beide Zeilen gemeinsam zurück', async () => {
|
||||
const playerId = await freshPlayer('Storno-Spieler');
|
||||
const booked = await credits.bookCcPackage(playerId, ctx);
|
||||
|
||||
@@ -236,7 +236,7 @@ describe('Korrekturen', () => {
|
||||
assert.equal(result.balances.REDESIGN_PAID, 0);
|
||||
});
|
||||
|
||||
it('dieselbe Buchung laesst sich kein zweites Mal stornieren', async () => {
|
||||
it('dieselbe Buchung lässt sich kein zweites Mal stornieren', async () => {
|
||||
const playerId = await freshPlayer('Doppel-Storno');
|
||||
const booked = await credits.bookKulanz(playerId, ctx);
|
||||
const entry = await db.prisma.creditLedger.findFirstOrThrow({
|
||||
@@ -266,8 +266,8 @@ describe('Korrekturen', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('eine Ruecknahme bucht das Guthaben zurueck und reaktiviert den Vorgaenger', async () => {
|
||||
const playerId = await freshPlayer('Ruecknehmer');
|
||||
it('eine Rücknahme bucht das Guthaben zurück und reaktiviert den Vorgänger', async () => {
|
||||
const playerId = await freshPlayer('Rücknehmer');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
const first = await characters.createCharacter(playerId, { name: 'Original' }, ctx);
|
||||
const redesigned = await characters.redesignCharacter(
|
||||
@@ -292,7 +292,7 @@ describe('Korrekturen', () => {
|
||||
assert.equal(restored.inactiveReason, null);
|
||||
});
|
||||
|
||||
it('eine Ruecknahme mitten in der Kette wird abgelehnt', async () => {
|
||||
it('eine Rücknahme mitten in der Kette wird abgelehnt', async () => {
|
||||
const playerId = await freshPlayer('Ketten-Spieler');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
await credits.bookRedesignPackage(playerId, ctx);
|
||||
@@ -309,7 +309,7 @@ describe('Korrekturen', () => {
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
() => characters.revertCharacter(second.character.id, 'Zu spaet', ctx),
|
||||
() => characters.revertCharacter(second.character.id, 'Zu spät', ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'HAS_SUCCESSORS',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('Profil auslesen', () => {
|
||||
assert.equal(cc.purchasedAt?.getDate(), 6);
|
||||
});
|
||||
|
||||
it('erkennt stornierte Kaeufe', () => {
|
||||
it('erkennt stornierte Käufe', () => {
|
||||
const revoked = profile.packages.find((p) => p.packageBoughtId === 9007);
|
||||
assert.equal(revoked?.revoked, true);
|
||||
});
|
||||
@@ -54,7 +54,7 @@ describe('Profil auslesen', () => {
|
||||
'donations_data[9004] = {kaputt"id"',
|
||||
);
|
||||
const result = parseProfile(broken, '76561198000000999');
|
||||
assert.equal(result.packages.length, 7, 'nur die kaputte Zeile faellt weg');
|
||||
assert.equal(result.packages.length, 7, 'nur die kaputte Zeile fällt weg');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,21 +73,21 @@ describe('Pakete zuordnen', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('zaehlt "Custom Character Redesign" als Redesign, nicht als CC', () => {
|
||||
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 Verbrauchszaehler samt Anzahl', () => {
|
||||
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 Raenge trotz SCP-RP-Tag', () => {
|
||||
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');
|
||||
@@ -105,7 +105,7 @@ describe('Pakete zuordnen', () => {
|
||||
assert.equal(result.kind, 'ignore');
|
||||
});
|
||||
|
||||
it('schiebt unklare CC-Titel in die Handpruefung statt zu raten', () => {
|
||||
it('schiebt unklare CC-Titel in die Handprüfung statt zu raten', () => {
|
||||
assert.equal(classifyPackage(pkg({ packageName: 'CC Sonderaktion Winter' })).kind, 'unclear');
|
||||
});
|
||||
});
|
||||
@@ -116,13 +116,13 @@ describe('SteamID-Schreibweisen', () => {
|
||||
const modern = '[U:1:39735271]';
|
||||
const sixtyFour = '76561198000000999';
|
||||
|
||||
it('fuehrt alle drei Formate auf dieselbe ID zusammen', () => {
|
||||
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 zurueck in die Legacy-Form', () => {
|
||||
it('rechnet zurück in die Legacy-Form', () => {
|
||||
assert.equal(toLegacySteamId(sixtyFour), legacy);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user