Files
CC-Manager/server/test/forum.test.ts
T
Harlekin 6c50d32d2b Rollen neu geschnitten, Seitenzahl korrigiert, frühere Konten
Der Forums-Abgleich las von 25 Archivseiten nur zwei. WoltLab verlinkt in der
Blätterleiste nur die Nachbarseiten und führt die Gesamtzahl in einem eigenen
Element; ausgewertet wurden aber die Links. Alles jenseits von Seite zwei war
damit unsichtbar - etwa ein Antrag auf Seite vier, der deshalb nie ankam.

Die Rollen verlaufen jetzt zwischen erfassen und gewähren statt zwischen
Alltag und Verwaltung: Editoren erfassen Käufe und führen Datei-Import,
GExtension- und Forums-Abgleich samt Entscheidung über Anträge durch. Kulanz
zu vergeben bleibt Administratoren, ebenso das Auflösen unklarer Pakete, weil
dabei Kulanz entstehen kann.

Dazu lassen sich frühere Steam- und Forumskonten am Spieler hinterlegen.
Abgleich und Import prüfen sie mit, sodass ein Kontowechsel die Zuordnung
nicht abreißen lässt. Steam-Kennungen werden dabei auf dieselbe Form gebracht
wie die Hauptangabe, und eine Kennung kann nicht zwei Spielern gehören.
2026-09-18 20:07:56 +02:00

102 lines
3.7 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 { hasIgnoredLabel, parseBoard, parsePageCount, parseThreadId } from '../src/lib/forum.js';
const here = dirname(fileURLToPath(import.meta.url));
const BOARD = readFileSync(join(here, 'fixtures', 'board.html'), 'utf8');
describe('Board-Übersicht lesen', () => {
const threads = parseBoard(BOARD);
it('liest die Threads der Liste', () => {
assert.equal(threads.length, 5);
assert.deepEqual(
threads.map((t) => t.threadId),
[7001, 7002, 7004, 7005, 7003],
);
});
it('nimmt den Ersteller aus der Übersicht, nicht den letzten Antwortenden', () => {
const first = threads.find((t) => t.threadId === 7001);
assert.equal(first?.authorName, 'Antragsteller');
assert.equal(first?.authorForumId, 501, 'die Forum-ID überlebt Namensänderungen');
});
it('löst Umlaut- und Anführungszeichen-Entities auf', () => {
const second = threads.find((t) => t.threadId === 7002);
assert.equal(second?.title, 'Custom Character Redesign | Alt zu Neu');
});
it('erkennt einen zurückgelassenen Verweis als solchen', () => {
const stub = threads.find((t) => t.threadId === 7003);
assert.equal(stub?.isMovedStub, true);
});
it('ignoriert Unterforen und deren letzte Beiträge', () => {
// 9999 steht im wbbBoardNode-Kasten, gehoert aber nicht in dieses Board.
assert.equal(threads.some((t) => t.threadId === 9999), false);
});
it('liest die Gesamtzahl der Seiten, nicht nur die verlinkten', () => {
// Die Blätterleiste verlinkt hier nur Seite 2 und 3, das Board hat aber 25.
// Wer die Links auswertet, liest den grössten Teil des Archivs nie.
assert.equal(parsePageCount(BOARD), 25);
});
it('fällt ohne das Element auf die Links zurück', () => {
assert.equal(parsePageCount('<a href="x&pageNo=7">7</a>'), 7);
assert.equal(parsePageCount('<html>ohne Blaetterleiste</html>'), 1);
});
it('kommt mit einer leeren Seite klar', () => {
assert.deepEqual(parseBoard('<html><body>nichts</body></html>'), []);
});
});
describe('Ankündigungen aussortieren', () => {
const threads = parseBoard(BOARD);
it('liest die Labels eines Threads', () => {
const regelwerk = threads.find((t) => t.threadId === 7004);
assert.deepEqual(regelwerk?.labels, ['Wichtig', 'Global']);
});
it('erkennt Wichtig und Information als Ausschluss', () => {
assert.equal(hasIgnoredLabel(threads.find((t) => t.threadId === 7004)!), true);
assert.equal(hasIgnoredLabel(threads.find((t) => t.threadId === 7005)!), true);
});
it('lässt echte Anträge durch, auch mit anderen Labels', () => {
assert.equal(hasIgnoredLabel(threads.find((t) => t.threadId === 7001)!), false);
});
it('wertet den Titel nicht aus', () => {
// "The Duke Rang Update" war ein echter Antrag, "Regelwerk" keiner. Am Titel
// ist das nicht zu erkennen - deshalb entscheidet allein das Label.
const ohneStichwort = parseBoard(BOARD).find((t) => t.threadId === 7005);
assert.ok(ohneStichwort, 'auch ein Thread ohne CC im Titel wird gelesen');
});
});
describe('Thread-Verweis lesen', () => {
it('nimmt den vollen Link', () => {
assert.equal(
parseThreadId('https://senseigaming.de/forum/index.php?thread/8041-cc-antrag-feldagent/'),
8041,
);
});
it('nimmt auch nur den Pfad oder die blanke Nummer', () => {
assert.equal(parseThreadId('index.php?thread/7001-irgendwas/'), 7001);
assert.equal(parseThreadId('7001'), 7001);
});
it('weist Unbrauchbares ab', () => {
assert.equal(parseThreadId(''), null);
assert.equal(parseThreadId('kein link'), null);
});
});