Öffnungszeiten: Fixrunde Website-Skript und Editor (JSON-LD, Kopf beim Scrollen, späte Platzhalter, Links, Bestätigung)
- JSON-LD wird ohne "<" geschrieben (<), ein </script> im Firmennamen bricht keinen Block mehr - verschiebe(): ist die Hinweis-Leiste weggescrollt, bekommen feste Elemente ihren eigenen Inline-top zurück (Köpfe, die per Klasse beim Scrollen wegfahren, funktionieren wieder) - Späte Platzhalter (Einzelseiten-Apps): entprellter MutationObserver auf body zeichnet neue oder wieder eingehängte Platzhalter nach - sichererLink lehnt Zugangsdaten in der Adresse ab; die Adresse der Schnittstelle bestimmt nur das eigene Script-Tag, kein Platzhalter mehr (der siteKey am Platzhalter bleibt laut Spec 4.2) - Editor: die Bestätigung klebt unter der Kopfleiste und bleibt nach dem Speichern eines unteren Abschnitts sichtbar Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ecf67d6978
commit
aa9ee35ab6
6 files changed
+221
-12
No files matched your search
@@ -211,6 +211,25 @@ async function pruefungen() {
|
||||
await page.waitForFunction(([erwartet]) => Math.abs(document.getElementById('kopf').getBoundingClientRect().top - erwartet) < 1, [h])
|
||||
}, { eingabe: zeitenEingabe({ hinweise: [INFO] }) })
|
||||
|
||||
await check('fester_header_versteckt_beim_scrollen', async (page) => {
|
||||
// Kopf, der per Klasse beim Scrollen wegfaehrt (top: -100px), mit dem eigenen Scroll-Skript der Seite. Solange die Hinweis-Leiste sichtbar ist,
|
||||
// rueckt das Skript ihn; ist sie weggescrollt, muss die Klasse der Seite wieder gelten (kein dauerhaftes top: 0 !important).
|
||||
const kopf = '<header id="kopf" style="position:fixed;left:0;right:0;height:60px;background:#222;color:#fff;z-index:100;padding:0 16px;line-height:60px">Bäckerei Sonnenschein</header>'
|
||||
+ '<script>addEventListener("scroll",function(){document.getElementById("kopf").classList.toggle("weg",scrollY>300)},{passive:true})</script>'
|
||||
await page.goto(srv.seite('kopf-weg.html', seitenHtml({ anfang: kopf, stil: '#kopf{top:0}#kopf.weg{top:-100px}' })))
|
||||
await warteBereit(page)
|
||||
await page.locator(HOST('hinweis')).waitFor({ state: 'attached' })
|
||||
const h = await hoehe(page, HOST('hinweis'))
|
||||
assert(nahe(await oben(page, '#kopf'), h, 1), `Kopf steht bei ${fmt(await oben(page, '#kopf'))} statt unter der Leiste (${fmt(h)})`)
|
||||
// weit gescrollt: die Seite blendet den Kopf aus, das Skript haelt ihn nicht fest
|
||||
await scrolle(page, 700)
|
||||
await page.waitForFunction(() => document.getElementById('kopf').getBoundingClientRect().top < -99)
|
||||
eq(await page.evaluate(() => document.getElementById('kopf').style.getPropertyValue('top')), '', 'Inline-top des Kopfes nach dem Wegscrollen der Leiste')
|
||||
// zurueck nach oben: die Klasse faellt ab, der Kopf steht wieder unter der Leiste
|
||||
await scrolle(page, 0)
|
||||
await page.waitForFunction(([erwartet]) => Math.abs(document.getElementById('kopf').getBoundingClientRect().top - erwartet) < 1, [h])
|
||||
}, { eingabe: zeitenEingabe({ hinweise: [INFO] }) })
|
||||
|
||||
await check('team_navselektor', async (page) => {
|
||||
// der Schwebende hat top: 10px (nicht top: 0): nur der Selektor des Teams findet ihn
|
||||
const seite = seitenHtml({
|
||||
@@ -420,6 +439,56 @@ async function pruefungen() {
|
||||
eq(await anzahl(page, 'script[type="application/ld+json"]'), 1, 'neuer JSON-LD-Block trotz aktiv: false')
|
||||
}, { eingabe: zeitenEingabe({ hinweise: [INFO] }) })
|
||||
|
||||
await check('spaeter_platzhalter_wird_gefuellt', async (page) => {
|
||||
// Einzelseiten-App: der Platzhalter kommt erst nach einem Seitenwechsel auf die Seite (der erste Abruf ist dann laengst durch)
|
||||
const html = seitenHtml({ inhalt: `<div id="spa"></div>${lang(5)}`, skript: SKRIPT })
|
||||
await page.goto(srv.seite('spa.html', html))
|
||||
await page.locator(HOST('hinweis')).waitFor({ state: 'attached' }) // das Skript hat gelaufen, es gibt keinen Platzhalter
|
||||
await page.evaluate(() => {
|
||||
const d = document.createElement('div')
|
||||
d.id = 'neu'
|
||||
d.setAttribute('data-webklar-zeiten', '')
|
||||
d.setAttribute('data-modus', 'status')
|
||||
d.textContent = 'Ersatz-Status'
|
||||
document.getElementById('spa').appendChild(d)
|
||||
})
|
||||
await page.waitForFunction(() => { const s = document.getElementById('neu'); return s && !s.textContent.includes('Ersatz') }, null, { timeout: 3000 })
|
||||
assert((await page.locator('#neu').innerText()).includes('geöffnet'), `Status: ${await page.locator('#neu').innerText()}`)
|
||||
// ein zweiter Seitenwechsel: der alte Knoten geht, ein neuer kommt
|
||||
await page.evaluate(() => {
|
||||
document.getElementById('neu').remove()
|
||||
const d = document.createElement('span')
|
||||
d.id = 'neu2'
|
||||
d.setAttribute('data-webklar-zeiten', '')
|
||||
d.setAttribute('data-modus', 'badge')
|
||||
d.textContent = 'Ersatz-Badge'
|
||||
document.getElementById('spa').appendChild(d)
|
||||
})
|
||||
await page.waitForFunction(() => { const s = document.getElementById('neu2'); return s && !s.textContent.includes('Ersatz') }, null, { timeout: 3000 })
|
||||
eq(await page.locator('#neu2').innerText(), 'Geöffnet', 'Badge')
|
||||
eq(await anzahl(page, 'style#wkz-style'), 1, 'Stile')
|
||||
}, { eingabe: zeitenEingabe({ hinweise: [INFO] }) })
|
||||
|
||||
await check('wieder_eingehaengter_platzhalter_wird_neu_gezeichnet', async (page) => {
|
||||
await page.goto(srv.seite('spa-zurueck.html', seitenHtml({ inhalt: `<div id="spa"></div>${STATUS}${lang(5)}` })))
|
||||
await warteBereit(page)
|
||||
// der Knoten verlaesst die Seite, ein anderer Platzhalter loest ein Zeichnen aus (der alte wird dabei vergessen) ...
|
||||
await page.evaluate(() => { window.__alt = document.getElementById('status'); window.__alt.remove() })
|
||||
await page.evaluate(() => {
|
||||
const d = document.createElement('div')
|
||||
d.id = 'anderer'
|
||||
d.setAttribute('data-webklar-zeiten', '')
|
||||
d.setAttribute('data-modus', 'status')
|
||||
d.textContent = 'Ersatz-Status'
|
||||
document.getElementById('spa').appendChild(d)
|
||||
})
|
||||
await page.waitForFunction(() => { const s = document.getElementById('anderer'); return s && !s.textContent.includes('Ersatz') }, null, { timeout: 3000 })
|
||||
// ... und kommt zurueck, mit dem Inhalt, den die App ihm gegeben hat
|
||||
await page.evaluate(() => { window.__alt.textContent = 'Ersatz-Status'; document.getElementById('spa').appendChild(window.__alt) })
|
||||
await page.waitForFunction(() => !document.getElementById('status').textContent.includes('Ersatz'), null, { timeout: 3000 })
|
||||
assert((await statusText(page)).includes('geöffnet'), `Status: ${await statusText(page)}`)
|
||||
}, { eingabe: zeitenEingabe({ hinweise: [INFO] }) })
|
||||
|
||||
await check('unbekannter_plan', async (page) => {
|
||||
const meldungen = []
|
||||
page.on('console', (m) => { if (m.type() === 'warning') meldungen.push(m.text()) })
|
||||
|
||||
@@ -357,6 +357,30 @@ async function pruefungen() {
|
||||
eq(puts, [3, 4], 'zweites PUT mit der neuen Version')
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- Bestätigung bleibt sichtbar
|
||||
// Die Meldung ist das erste Kind des Editors; nach dem Speichern eines unteren Abschnitts (Kontakt) springt der Fokus auf den Knopf. Ohne
|
||||
// klebende Meldung stünde „gespeichert“ dann ausserhalb des Fensters.
|
||||
await check('fx_meldung_bleibt_sichtbar', async (page) => {
|
||||
await oeffneEditor(page)
|
||||
const form = page.locator('form[aria-label="Kontakt-Leiste"]')
|
||||
await form.scrollIntoViewIfNeeded()
|
||||
await form.locator('input[type="tel"]').first().fill('06301 999888')
|
||||
await knopf(form, 'Kontakt-Leiste speichern').click()
|
||||
await meldung(page).filter({ hasText: 'Kontakt-Leiste gespeichert' }).waitFor()
|
||||
await page.waitForTimeout(150)
|
||||
const lage = await meldung(page).evaluate((e) => {
|
||||
const r = e.getBoundingClientRect()
|
||||
return { oben: r.top, unten: r.bottom, hoehe: r.height, fenster: window.innerHeight, pos: getComputedStyle(e).position, scroll: window.scrollY }
|
||||
})
|
||||
assert(lage.scroll > 300, `die Prüfung braucht eine gescrollte Seite (scrollY ${lage.scroll})`)
|
||||
assert(lage.hoehe > 0 && lage.oben >= -0.5 && lage.unten <= lage.fenster + 0.5, `Meldung liegt ausserhalb des Fensters: ${JSON.stringify(lage)}`)
|
||||
eq(lage.pos, 'sticky', 'Meldung klebt unter der Kopfleiste')
|
||||
// leer klebt sie nicht (kein leerer Streifen)
|
||||
await meldung(page).evaluate((e) => { e.textContent = '' })
|
||||
eq(await meldung(page).evaluate((e) => getComputedStyle(e).position), 'static', 'leere Meldung')
|
||||
await shot(page, 'meldung-sichtbar')
|
||||
}, { context: { viewport: { width: 1280, height: 600 } } })
|
||||
|
||||
// ---------------------------------------------------------------- Urlaub ⇒ Hinweis-Vorschlag, „Hinweis-Leiste anlegen“
|
||||
await check('fx_hinweis_vorschlag', async (page, _ctx, fx) => {
|
||||
await oeffneEditor(page)
|
||||
|
||||
Reference in new issue
Block a user