Prüfpunkte D1 bis D8 der Rechtsrunde umgesetzt: Kundenart im Kundenkonto (D3), Nachweis beim Einschalten einer Funktion ohne Zahlung (D1, D4), Wortlaut und Kundenart im Nachweis bei Abo, Wechsel, Zusatzspeicher (D2) und Übernahmegutschrift, Website-Analyse im Hosting- und Wartungs-Abo (D5), Ende und Löschfristen der Funktionen im Abo-Modell (D6), Vorschuss im Stundenkonto (D7). Neu Abschnitt 6e Öffnungszeiten live, auf den die Leistungsbeschreibung Fassung 6 verweist. Der Bestand einzeln gekaufter Funktionen bleibt beschrieben. PDF neu gedruckt, Pins nachgezogen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
4.1 KiB
JavaScript
46 lines
4.1 KiB
JavaScript
import { test } from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readFileSync } from 'node:fs'
|
||
|
||
// Entscheidungsliste, Kanzlei-Fragen, Ablauf nach der Freigabe und Datenschutz-Prüfpunkte der Rechtsrunde Fassung 6 (Task 11).
|
||
const lies = (rel) => readFileSync(new URL(`../${rel}`, import.meta.url), 'utf8')
|
||
const ENTWURF = false
|
||
const md = lies('docs/rechtliches/kundenansicht-entscheidungen.md'), dsg = lies('docs/rechtliches/datenschutz-kundenansicht-pruefpunkte.md')
|
||
test('Entscheidungsliste: R1 bis R18, je Punkt Vorschlag, Alternative und Kanzlei-Frage', () => {
|
||
const z = md.split('\n').filter((l) => /^\| R\d+ \|/.test(l)).map((l) => l.split('|').slice(1, -1).map((s) => s.trim()))
|
||
assert.deepEqual(z.map((r) => r[0]), Array.from({ length: 18 }, (_, i) => `R${i + 1}`))
|
||
for (const r of z) { assert.equal(r.length, 5); assert.ok(r.every(Boolean), r[0]); assert.match(r[4], /^(–|KQ\d+(, KQ\d+)*)$/, r[0]) }
|
||
const kq = [...md.matchAll(/^### (KQ\d+): .+$/gm)].map((m) => m[1])
|
||
assert.deepEqual(kq, Array.from({ length: 9 }, (_, i) => `KQ${i + 1}`))
|
||
for (const r of z) for (const id of r[4].match(/KQ\d+/g) ?? []) assert.ok(kq.includes(id), `${r[0]} nennt ${id}`)
|
||
assert.equal(md.includes('Entwurf zur Freigabe, keine Rechtsberatung'), ENTWURF)
|
||
})
|
||
test('R8 ist mit P4/P6 abgestimmt: Zeiten laufen 30 Tage weiter, die übrigen schalten am Folgetag ab, kein Behalten', () => {
|
||
const [, punkt, vorschlag, alternative] = md.split('\n').find((l) => l.startsWith('| R8 |')).split('|').slice(1, -1).map((s) => s.trim())
|
||
assert.match(punkt, /mit P4\/P6 abgestimmt/)
|
||
for (const s of ['spätestens am Folgetag', 'Öffnungszeiten live läuft nach dem Ende noch 30 Tage unverändert weiter', 'kein Behalten']) assert.ok(vorschlag.includes(s), s)
|
||
assert.doesNotMatch(vorschlag, /Karenz|entfällt/)
|
||
assert.ok(alternative.includes('Öffnungszeiten live schalten wie die übrigen spätestens am Folgetag ab'))
|
||
})
|
||
test('Kanzlei-Fragen haben vier Teile', () => {
|
||
for (const teil of md.split(/\n(?=### KQ\d+:)/).slice(1)) for (const k of ['**Frage.**', '**Fundstelle im Text.**', '**Unsere Annahme.**', '**Alternative.**']) assert.ok(teil.includes(k), `${teil.slice(0, 8)} ${k}`)
|
||
})
|
||
test('AVV-Struktur nennt A, B und C; Ablauf nach der Freigabe in fester Reihenfolge mit Schutzbefehlen', () => {
|
||
const avv = md.slice(md.indexOf('## AVV-Struktur'), md.indexOf('## Ablauf nach der Freigabe'))
|
||
for (const s of ['Option A', 'Option B', 'Option C', 'Anlage 1']) assert.ok(avv.includes(s), s)
|
||
const a = md.slice(md.indexOf('## Ablauf nach der Freigabe'))
|
||
const reihenfolge = ['Freigabe des Inhabers', 'ENTWURF = false', 'scripts/build-legal-html.mjs funktionen6', 'free -m', 'nice -n 10 scripts/build-legal-pdfs.sh abo6', 'nice -n 10 scripts/build-legal-pdfs.sh funktionen6', 'rechtliches-hochladen.mjs --probe', '--karten-anlegen', 'ein Aufruf je Dokument', '--freigabe=', '--pruefen']
|
||
const pos = reihenfolge.map((s) => { const i = a.indexOf(s); assert.ok(i >= 0, s); return i })
|
||
assert.deepEqual([...pos].sort((x, y) => x - y), pos, 'Reihenfolge')
|
||
assert.ok(a.includes('Datum der Fassungen') && a.includes('Entwurfsmarke'), 'Datum setzen und Marken entfernen')
|
||
})
|
||
test('Datenschutz-Prüfpunkte D1 bis D8 mit gültiger Fundstelle in public/datenschutz.html', () => {
|
||
assert.deepEqual([...dsg.matchAll(/^\*\*(D\d)\*\*/gm)].map((m) => m[1]), ['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8'])
|
||
const zeilen = lies('public/datenschutz.html').split('\n')
|
||
const refs = [...dsg.matchAll(/public\/datenschutz\.html:(\d+)/g)].map((m) => Number(m[1]))
|
||
assert.ok(refs.length >= 8 && refs.every((n) => n >= 1 && n <= zeilen.length))
|
||
// Die Zeilen der Prüfpunkte gelten für die Fassung vom 22.10.2026; seit der Fassung vom 29.10.2026 (Umschalten, R14) sind Absätze dazugekommen, darum sucht der Test die Stellen nach Inhalt
|
||
const zeile = (text) => zeilen.find((z) => z.includes(text)) ?? ''
|
||
assert.ok(zeile('Zahlungspflichtig bestellen').includes('Stripe-Sitzung') && zeile('Leistungsbeginn').includes('Browserkennung') && zeile('Sobald diese Funktion freigeschaltet').includes('Wartungs-Abo'), 'D1, D2, D5 zitieren die richtigen Stellen')
|
||
})
|