Die Öffnungszeiten stehen jetzt hinter dem Webshop (news, termine, shop, zeiten): Register, FEATURE_KEYS und ticketFreischaltungKeys in zeitenRegister, die drei Listen in app.js (VIEW_HASHES, APP_PARENT, FEATURE_LABELS) in zeitenBestellen und shopWiring (APP_PARENT endet mit webshop, zeiten). funktionenZeitenTile prüft die Importe von funktionen.js gegen den Stand von main (fn-util.js und analyse-view.js); die Kachel der Öffnungszeiten bringt weiterhin keinen neuen Import mit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
3.2 KiB
JavaScript
52 lines
3.2 KiB
JavaScript
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
// Task G1: der Webshop ist im Kundenbereich verdrahtet (dashboard.html, app.js, funktionen.js, shop.css, shop.js). Rein statisch, ohne DOM.
|
|
const lies = (pfad) => readFileSync(new URL(`../${pfad}`, import.meta.url), 'utf8')
|
|
|
|
test('dashboard.html: shop.css nach termine.css, Abschnitt #view-webshop mit Kopf „Webshop“ und #webshop-body', () => {
|
|
const html = lies('public/dashboard.html')
|
|
assert.match(html, /<link rel="stylesheet" href="\/termine\.css">\s*<link rel="stylesheet" href="\/shop\.css">/)
|
|
assert.match(html, /<section class="kb-view" id="view-webshop">[\s\S]*?<h1>Webshop<\/h1>[\s\S]*?<div id="webshop-body">[\s\S]*?<\/section>/)
|
|
assert.equal([...html.matchAll(/id="view-webshop"/g)].length, 1)
|
|
assert.doesNotMatch(html, /data-view="webshop"/, 'kein eigener Navigationseintrag: Unterseite von Funktionen')
|
|
})
|
|
|
|
test('app.js: VIEW_HASHES, viewRefreshers, FEATURE_LABELS und APP_PARENT kennen den Webshop', () => {
|
|
const app = lies('public/app.js')
|
|
assert.match(app, /VIEW_HASHES = \{[^}]*webshop: 'webshop'/)
|
|
assert.match(app, /FEATURE_LABELS = \{[^}]*shop: 'Webshop'/)
|
|
assert.match(app, /webshop: \(\) => import\('\/shop\.js'\)\.then\(\(m\) => m\.initShop\(document\.getElementById\('webshop-body'\)\)\)/)
|
|
// APP_PARENT: die Reihenfolge der bisherigen Einträge bleibt (termineView.test.js), webshop folgt, zeiten (Öffnungszeiten live) steht am Ende
|
|
assert.match(app, /APP_PARENT = \{ news: 'funktionen', analyse: 'funktionen', termine: 'funktionen', /)
|
|
assert.match(app, /APP_PARENT = \{[^}]*projekt: 'projects', webshop: 'funktionen', zeiten: 'funktionen' \}/)
|
|
// die Ansicht ist vom Hash aus erreichbar: kein zweiter Schlüssel mit demselben Hash
|
|
const hashes = app.match(/VIEW_HASHES = \{([^}]*)\}/)[1]
|
|
assert.equal([...hashes.matchAll(/'webshop'/g)].length, 1)
|
|
})
|
|
|
|
test('shop.js und shop.css: die Hülle exportiert initShop, die Styles hängen an #view-webshop und sh-', () => {
|
|
const js = lies('public/shop.js')
|
|
assert.match(js, /export function initShop\(root, \{ projectId \} = \{\}\)/)
|
|
assert.doesNotMatch(js.replace(/\/\*[\s\S]*?\*\//g, ''), /innerHTML|insertAdjacentHTML|outerHTML|document\.write/, 'Text nie als HTML')
|
|
const css = lies('public/shop.css')
|
|
assert.match(css, /#view-webshop/)
|
|
assert.doesNotMatch(css, /(^|[}\s,])\.tm-/m, 'keine Klassen des Terminplaners neu definieren')
|
|
})
|
|
|
|
test('funktionen.js: Webshop-Kachel inline, die erlaubten Importe bleiben (zwei absolute, ein relativer, kein dynamischer)', () => {
|
|
const fn = lies('public/funktionen.js')
|
|
assert.deepEqual(fn.match(/from '\/[^']+'/g), ["from '/fn-util.js'", "from '/analyse-view.js'"])
|
|
assert.deepEqual(fn.match(/from '\.[^']+'/g), ["from './vertraege-link.js'"])
|
|
assert.doesNotMatch(fn, /import\s*\(/)
|
|
assert.match(fn, /data-fn-tile="shop"/)
|
|
assert.match(fn, /getElementById\('webshop-body'\)/)
|
|
})
|
|
|
|
test('Dateinamen: Webshop-Dateien beginnen nie mit termine (eigene Regeln der termine*.js-Tests)', async () => {
|
|
const { readdirSync } = await import('node:fs')
|
|
const dateien = readdirSync(new URL('../public/', import.meta.url)).filter((f) => /^shop.*\.(js|css)$/.test(f))
|
|
assert.ok(dateien.includes('shop.js') && dateien.includes('shop.css'))
|
|
})
|