Files
tickte-system/tests/unit/eigeneAnalyseView.test.mjs
ClaudeandClaude Opus 5.5 f9b0cbc855 Website-Statistik: eigene Seite für die Analyse von webklar.com
Neue Mitarbeiterseite /statistik (für alle Mitarbeiter, Eintrag nach "Rechtliches"):
Kennzahlen mit Vergleich zur Vorperiode, Verlauf pro Tag (uPlot), Ranglisten für
Seiten, Herkunft, Länder, Geräte und Kontakt-Klicks, Banner-Zahlen und Heatmap-Link
(neuer Tab über openInNewTab). Anzeige-Logik als reine Helfer mit Tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 18:34:17 +00:00

149 lines
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test'
import assert from 'node:assert/strict'
import { loadModule } from './load.mjs'
// Website-Statistik (webklar.com): reine Anzeige-Helfer
const v = await loadModule('src/lib/eigeneAnalyseView.js')
test('Zahlen: Tausenderpunkt, Prozent, fehlender Wert', () => {
assert.equal(v.formatInt(1234567), '1.234.567')
assert.equal(v.formatInt(0), '0')
assert.equal(v.formatInt(null), '–')
assert.equal(v.formatInt(undefined), '–')
assert.equal(v.formatPercent(0.63), '63 %')
assert.equal(v.formatPercent(0.625), '63 %')
assert.equal(v.formatPercent(0), '0 %')
assert.equal(v.formatPercent(1), '100 %')
assert.equal(v.formatPercent(null), '–')
})
test('Dauer: Sekunden, Minuten mit zweistelligen Sekunden, null', () => {
assert.equal(v.formatDuration(42), '42 s')
assert.equal(v.formatDuration(0), '0 s')
assert.equal(v.formatDuration(65), '1 Min. 05 s')
assert.equal(v.formatDuration(60), '1 Min. 00 s')
assert.equal(v.formatDuration(59.6), '1 Min. 00 s', 'gerundet, nie "60 s"')
assert.equal(v.formatDuration(754.2), '12 Min. 34 s')
assert.equal(v.formatDuration(null), '–')
assert.equal(v.formatDuration(undefined), '–')
})
test('Aenderung in Prozent: plus, minus (U+2212), null, neu, kein Vergleich', () => {
assert.deepEqual(v.changeVsPrevious(112, 100), { text: '+12 %', dir: 'up' })
assert.deepEqual(v.changeVsPrevious(95, 100), { text: '−5 %', dir: 'down' })
assert.deepEqual(v.changeVsPrevious(100, 100), { text: '0 %', dir: 'flat' })
assert.deepEqual(v.changeVsPrevious(1001, 1000), { text: '0 %', dir: 'flat' }, 'unter 0,5 % gilt als unveraendert')
assert.deepEqual(v.changeVsPrevious(5, 0), { text: 'neu', dir: 'up' })
assert.deepEqual(v.changeVsPrevious(0, 0), { text: '0 %', dir: 'flat' })
assert.deepEqual(v.changeVsPrevious(0, 40), { text: '−100 %', dir: 'down' })
assert.deepEqual(v.changeVsPrevious(13000, 1000), { text: '+1.200 %', dir: 'up' })
assert.equal(v.changeVsPrevious(null, 10), null)
assert.equal(v.changeVsPrevious(10, null), null)
assert.equal(v.changeVsPrevious(10, undefined), null)
})
test('Aenderung der Zustimmungsquote in Prozentpunkten', () => {
assert.deepEqual(v.changeInPoints(0.63, 0.59), { text: '+4 Pkt.', dir: 'up' })
assert.deepEqual(v.changeInPoints(0.5, 0.52), { text: '−2 Pkt.', dir: 'down' })
assert.deepEqual(v.changeInPoints(0.5, 0.5), { text: '0 Pkt.', dir: 'flat' })
assert.equal(v.changeInPoints(0.5, null), null)
})
test('kpiChange: ohne vollstaendige Vorperiode kein Vergleich', () => {
const stats = {
totals: { pv: 120, visitors: 40, contacts: 3, consentRate: 0.63, avgSec: 65 },
previous: { complete: true, totals: { pv: 100, visitors: 50, contacts: 0, consentRate: 0.59, avgSec: null } },
}
assert.equal(v.kpiChange(stats, 'pv').text, '+20 %')
assert.equal(v.kpiChange(stats, 'visitors').text, '−20 %')
assert.equal(v.kpiChange(stats, 'contacts').text, 'neu')
assert.equal(v.kpiChange(stats, 'consentRate').text, '+4 Pkt.')
assert.equal(v.kpiChange(stats, 'avgSec'), null, 'Vorperiode ohne Dauer')
assert.equal(v.kpiChange({ ...stats, previous: { ...stats.previous, complete: false } }, 'pv'), null)
assert.equal(v.kpiChange({ totals: stats.totals }, 'pv'), null)
assert.equal(v.kpiChange(null, 'pv'), null)
})
test('Beschriftungen: Geraete, Kontakte, Herkunft, Seiten', () => {
assert.equal(v.deviceLabel('m'), 'Handy')
assert.equal(v.deviceLabel('t'), 'Tablet')
assert.equal(v.deviceLabel('d'), 'Computer')
assert.equal(v.deviceLabel(''), 'unbekannt')
assert.equal(v.deviceLabel('x'), 'x')
assert.equal(v.contactLabel('tel'), 'Telefon')
assert.equal(v.contactLabel('mail'), 'E-Mail')
assert.equal(v.contactLabel('wa'), 'WhatsApp')
assert.equal(v.contactLabel('out'), 'Link zu anderer Website')
assert.equal(v.contactLabel('zzz'), 'zzz')
assert.equal(v.refLabel(''), 'direkt / unbekannt')
assert.equal(v.refLabel('google.com'), 'google.com')
assert.equal(v.pageLabel('/'), '/ (Startseite)')
assert.equal(v.pageLabel('/preise'), '/preise')
})
test('Laender: deutsche Namen, unbekannt, ungueltiger Code bleibt Code', () => {
assert.equal(v.countryLabel('DE'), 'Deutschland')
assert.equal(v.countryLabel('AT'), 'Österreich')
assert.equal(v.countryLabel('CH'), 'Schweiz')
assert.equal(v.countryLabel(''), 'unbekannt')
assert.equal(v.countryLabel('T1'), 'T1', 'kein gueltiger Regionscode')
})
test('Datum: Tag, Kurzform, Zeitraum (gleiches Jahr, Jahreswechsel, ein Tag)', () => {
assert.equal(v.formatDay('2026-10-17'), '17.10.2026')
assert.equal(v.formatDay(''), '–')
assert.equal(v.formatDay('17.10.2026'), '–')
assert.equal(v.formatDayShort('2026-10-07'), '07.10.')
assert.equal(v.periodText('2026-09-10', '2026-10-16'), '10.09.–16.10.2026')
assert.equal(v.periodText('2025-12-30', '2026-01-05'), '30.12.2025–05.01.2026')
assert.equal(v.periodText('2026-10-16', '2026-10-16'), '16.10.2026')
assert.equal(v.periodText('', '2026-10-16'), '')
})
test('Verlauf: jeder Tag einmal, fehlende Tage 0, Tage vor der Messung null, ueber Monatsgrenze', () => {
const stats = {
from: '2026-09-29', to: '2026-10-03', firstDay: '2026-09-30',
series: [
{ day: '2026-09-30', pv: 4, visitors: 2 },
{ day: '2026-10-02', pv: 9, visitors: 5 },
],
}
const c = v.chartDays(stats)
assert.deepEqual(c.days, ['2026-09-29', '2026-09-30', '2026-10-01', '2026-10-02', '2026-10-03'])
assert.deepEqual(c.pv, [null, 4, 0, 9, 0])
assert.deepEqual(c.visitors, [null, 2, 0, 5, 0])
assert.deepEqual(v.chartDays({ from: '2026-10-03', to: '2026-10-01', series: [] }).days, [])
assert.deepEqual(v.chartDays({ from: '2026-10-01', to: '2026-10-02', firstDay: '', series: [] }).pv, [0, 0])
})
test('Rangliste: sortiert, Balken relativ zum groessten, Anteil nur auf Wunsch, Nullen raus', () => {
const items = [{ key: 'm', count: 30 }, { key: 'd', count: 60 }, { key: 't', count: 10 }, { key: '', count: 0 }]
const rows = v.rankRows(items, v.deviceLabel, { percent: true })
assert.deepEqual(rows.map((r) => [r.key, r.label, r.count, r.bar, r.percent]), [
['d', 'Computer', 60, 1, '60'],
['m', 'Handy', 30, 0.5, '30'],
['t', 'Tablet', 10, 10 / 60, '10'],
])
assert.equal(v.rankRows([{ key: 'a', count: 1000 }, { key: 'b', count: 1 }], String, { percent: true })[1].percent, '<1', 'unter einem halben Prozent')
assert.equal(v.rankRows(items, v.deviceLabel)[0].percent, null)
assert.deepEqual(v.rankRows(null, String), [])
})
test('Texte: Heute-Zeile mit Einzahl, Leerzustand, Hinweis auf spaeten Messbeginn', () => {
assert.equal(
v.todayText({ pv: 12, visitors: 3, contacts: 1 }),
'Heute bis jetzt: 12 Aufrufe · 3 Besucher · 1 Kontakt-Klick'
)
assert.equal(
v.todayText({ pv: 1, visitors: 1, contacts: 0 }),
'Heute bis jetzt: 1 Aufruf · 1 Besucher · 0 Kontakt-Klicks'
)
assert.equal(v.todayText({ pv: 1500, visitors: 0, contacts: 2 }), 'Heute bis jetzt: 1.500 Aufrufe · 0 Besucher · 2 Kontakt-Klicks')
assert.equal(v.hasNoData({ totals: { pv: 0 }, today: { pv: 0 } }), true)
assert.equal(v.hasNoData({ totals: { pv: 0 }, today: { pv: 2 } }), false)
assert.equal(v.hasNoData({ totals: { pv: 5 }, today: { pv: 0 } }), false)
assert.equal(v.sinceHint({ from: '2026-09-17', firstDay: '2026-10-05' }), 'Messung seit 05.10.2026')
assert.equal(v.sinceHint({ from: '2026-09-17', firstDay: '2026-09-17' }), '')
assert.equal(v.sinceHint({ from: '2026-09-17', firstDay: '' }), '')
})