Shop Review B I-6, I-7: Archiv der bestaetigten Rechtstexte, G09 ohne Link-Ersatz

I-6: Neue Collection shopRechtstexteArchiv (ID r + 35 Hex aus sha256(shopId + hash)); das
Bestaetigen legt die Fassung samt Versand-/Zahlungstext und Gewaehrleistungstext ab, G09 zeigt
die Fassung zum rechtstexteHash der Bestellung (Rueckfall mit Warnung auf die aktuell
bestaetigte), loescheShopDaten loescht das Archiv mit.

I-7: Grenzen AGB 20000, Belehrung 12000, Formular 3000 plus Pruefung der maskierten Laenge beim
Speichern; G09 ersetzt die AGB nie mehr durch einen Link, sondern scheitert (Marker bleibt
offen, wird wiederholt). Test mit Texten in Hoechstlaenge gegen die Grenzen der Warteschlange.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 09:58:31 +00:00
1 parent 2f4f360a21
commit 08d837d690
17 files changed
+288 -65

No files matched your search

+11 -3
View File
@@ -15,7 +15,7 @@ const { main } = await import('../scripts/shop-setup.mjs')
const { createDocument, updateDocument, getDocument } = await import('../server/services/appwriteAdmin.js')
after(() => Promise.all([aw.close(), st.close()]))
const NAMES = ['shopConfig', 'shopProducts', 'shopOrders', 'shopWiderrufe']
const NAMES = ['shopConfig', 'shopProducts', 'shopOrders', 'shopWiderrufe', 'shopRechtstexteArchiv']
const keysOf = (name) => SHOP_COLLECTIONS[name].attributes.map((a) => a.key)
/**
@@ -127,6 +127,12 @@ test('Schema: Typen und Groessen', () => {
[36, 36, 32, 200, 320, 2000, 36],
)
for (const key of ['eingangAt', 'bestaetigungAt', 'bearbeitetAt']) assert.equal(widerrufe[key].type, 'datetime', key)
// I-6: Archiv der bestaetigten Rechtstexte
assert.deepEqual(keysOf('shopRechtstexteArchiv'), ['shopId', 'customerId', 'hash', 'texte', 'bestaetigtAt', 'bestaetigtVon'])
const archiv = byKey('shopRechtstexteArchiv')
assert.deepEqual([archiv.shopId.size, archiv.customerId.size, archiv.hash.size, archiv.texte.size, archiv.bestaetigtVon.size], [36, 36, 64, 100000, 255])
assert.equal(archiv.bestaetigtAt.type, 'datetime')
})
test('Schema: jedes Attribut ist optional, hat eine gueltige Form und einen gueltigen Schluessel (kein Feld data)', () => {
@@ -160,6 +166,7 @@ test('Schema: Indizes wie in der Spezifikation und nur auf vorhandenen Attribute
['idx_erstellt', 'shopId', 'erstelltAt'],
])
assert.deepEqual(indexes('shopWiderrufe'), [['idx_shop', 'shopId', 'eingangAt']])
assert.deepEqual(indexes('shopRechtstexteArchiv'), [['idx_shop_hash', 'shopId', 'hash']])
for (const name of NAMES) {
for (const index of SHOP_COLLECTIONS[name].indexes) {
assert.equal(index.type, 'key')
@@ -174,6 +181,7 @@ test('Schema: SHOP_DATETIMES nennt je Collection genau die datetime-Attribute',
shopProducts: [],
shopOrders: ['erstelltAt', 'ablaufAt', 'bezahltAt', 'anonymisiertAt'],
shopWiderrufe: ['eingangAt', 'bestaetigungAt', 'bearbeitetAt'],
shopRechtstexteArchiv: ['bestaetigtAt'],
})
})
@@ -215,7 +223,7 @@ test('Konfiguration: Collection-IDs der Shop-Collections', () => {
assert.deepEqual(NAMES.map((name) => config.collections[name]), NAMES)
})
test('main legt auf leerer Datenbank 4 Collections, alle Attribute und Indizes an', async () => {
test('main legt auf leerer Datenbank 5 Collections, alle Attribute und Indizes an', async () => {
const client = fakeClient()
const result = await main({ client, log: quiet })
assert.deepEqual(client.calls.collections, NAMES.map((id) => ({ id, name: id })))
@@ -248,7 +256,7 @@ test('main: legt nur fehlende Attribute und Indizes einer vorhandenen Collection
assert.ok(!client.calls.collections.some((c) => c.id === 'shopWiderrufe'))
assert.deepEqual(client.calls.attrs.filter((k) => k.startsWith('shopWiderrufe.')), ['shopWiderrufe.bearbeitetAt', 'shopWiderrufe.orderId'])
assert.deepEqual(client.calls.indexes.filter((k) => k.startsWith('shopWiderrufe.')), ['shopWiderrufe.idx_shop'])
assert.equal(client.calls.collections.length, 3)
assert.equal(client.calls.collections.length, 4)
})
test('main --check legt nichts an und meldet Fehlendes', async () => {