Öffnungszeiten: Hinweis-Leiste, Kontakt-Leiste und JSON-LD im Website-Skript
zeiten.js zeichnet mit denselben Daten wie die Platzhalter eine Hinweis-Leiste (Shadow DOM, erstes Kind von body, rückt feste und klebende Köpfe, scroll-padding-top), eine Kontakt-Leiste nur auf schmalen Schirmen (Abstandhalter, scroll-padding-bottom, entfällt bei eigener Anruf-Leiste) und ergänzt das JSON-LD der Seite (nur die beiden Zeiten-Felder, sonst eigener Block). Alle Adressen aus der Schnittstelle werden im Browser erneut geprüft. Ruling R29: tick mit try/finally, sofort werfender fetch, erst zeichnen dann laden beim Zurückkehren in den Tab. Tests: statische Funktionstests der reinen Funktionen und eine Playwright-Prüfung gegen den UI-Testserver (echte öffentliche Schnittstelle, Nachbau von Appwrite). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a6a4eae294
commit
ed99234ae4
4 files changed
+1542
-8
No files matched your search
@@ -401,3 +401,246 @@ test('Demo-Seite: noindex, Skript per defer mit data-site, alle drei Platzhalter
|
||||
assert.match(demo, /\d\d:\d\d\s*(?:–|–)\s*\d\d:\d\d/, 'Ersatz-HTML mit Zeiten fehlt')
|
||||
assert.match(demo, /<table>[\s\S]*<caption>[\s\S]*Montag[\s\S]*Sonntag/, 'Ersatz-Tabelle fehlt')
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- Task 26: Hinweis-Leiste, Kontakt-Leiste, JSON-LD
|
||||
|
||||
/** Die reinen Funktionen der Leisten und des JSON-LD (zwischen den Marken) samt telefonLink (eigene Marke), einzeln in einem leeren Kontext. */
|
||||
function leisten() {
|
||||
const rein = /\/\/ @rein-anfang[^\n]*\n([\s\S]*?)\/\/ @rein-ende/.exec(QUELLE)
|
||||
const tel = /\/\/ @telefon-anfang[^\n]*\n([\s\S]*?)\/\/ @telefon-ende/.exec(QUELLE)
|
||||
assert.ok(rein && tel, 'Marken fehlen')
|
||||
return vm.runInNewContext(
|
||||
`${tel[1]}; ${rein[1]}; ({ jsonLdEinbauen, kontaktKnoepfe, istEigeneAnrufLeiste, hinweisKnopf, HINWEIS_FARBEN })`,
|
||||
{},
|
||||
)
|
||||
}
|
||||
|
||||
const WOCHE_LD = [
|
||||
{ '@type': 'OpeningHoursSpecification', dayOfWeek: 'Monday', opens: '09:00', closes: '18:00' },
|
||||
{ '@type': 'OpeningHoursSpecification', dayOfWeek: 'Saturday', opens: '09:00', closes: '12:00' },
|
||||
]
|
||||
const SONDER_LD = [{ '@type': 'OpeningHoursSpecification', validFrom: '2026-10-12', validThrough: '2026-10-16', opens: '00:00', closes: '00:00' }]
|
||||
const jsonldVomServer = () => ({
|
||||
openingHoursSpecification: WOCHE_LD,
|
||||
specialOpeningHoursSpecification: SONDER_LD,
|
||||
neuerBlock: { '@context': 'https://schema.org', '@type': 'LocalBusiness', openingHoursSpecification: WOCHE_LD, specialOpeningHoursSpecification: SONDER_LD },
|
||||
})
|
||||
const SEITE = { name: 'Bäckerei Sonnenschein', adresse: 'Hauptstraße 1, 67722 Winnweiler', url: 'https://baeckerei.example/' }
|
||||
|
||||
test('JSON-LD: vorhandener Restaurant-Knoten wird ergänzt, kein zweiter Block', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
const bloecke = [
|
||||
{ '@context': 'https://schema.org', '@type': 'WebSite', name: 'Zum Löwen', url: 'https://loewen.example/' },
|
||||
{
|
||||
'@context': 'https://schema.org', '@type': 'Restaurant', name: 'Zum Löwen', telephone: '+49 6301 1234', servesCuisine: 'Deutsch',
|
||||
address: { '@type': 'PostalAddress', streetAddress: 'Hauptstr. 1' },
|
||||
openingHoursSpecification: [{ '@type': 'OpeningHoursSpecification', dayOfWeek: 'Sunday', opens: '11:00', closes: '14:00' }],
|
||||
specialOpeningHoursSpecification: [{ '@type': 'OpeningHoursSpecification', validFrom: '2020-01-01', validThrough: '2020-01-02', opens: '00:00', closes: '00:00' }],
|
||||
},
|
||||
]
|
||||
const erg = norm(jsonLdEinbauen(bloecke, jsonldVomServer(), SEITE))
|
||||
assert.deepEqual(erg, { geaendert: [1], neu: null }, 'nur der Restaurant-Block ändert sich, es kommt kein zweiter Block dazu')
|
||||
assert.deepEqual(norm(bloecke[1].openingHoursSpecification), WOCHE_LD)
|
||||
assert.deepEqual(norm(bloecke[1].specialOpeningHoursSpecification), SONDER_LD)
|
||||
// alles andere bleibt, wie es war
|
||||
assert.equal(bloecke[1]['@type'], 'Restaurant')
|
||||
assert.equal(bloecke[1].name, 'Zum Löwen')
|
||||
assert.equal(bloecke[1].telephone, '+49 6301 1234')
|
||||
assert.equal(bloecke[1].servesCuisine, 'Deutsch')
|
||||
assert.deepEqual(norm(bloecke[1].address), { '@type': 'PostalAddress', streetAddress: 'Hauptstr. 1' })
|
||||
assert.deepEqual(norm(bloecke[0]), { '@context': 'https://schema.org', '@type': 'WebSite', name: 'Zum Löwen', url: 'https://loewen.example/' })
|
||||
// zweiter Durchlauf mit denselben Daten: nichts mehr zu schreiben
|
||||
assert.deepEqual(norm(jsonLdEinbauen(bloecke, jsonldVomServer(), SEITE)), { geaendert: [], neu: null })
|
||||
})
|
||||
|
||||
test('JSON-LD: @graph mit HairSalon wird ergänzt (nur dieser Knoten), auch @type als Liste', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
const bloecke = [{
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{ '@type': 'WebSite', '@id': '#web', name: 'Salon' },
|
||||
{ '@type': 'Organization', '@id': '#org', name: 'Salon GmbH', openingHoursSpecification: 'unberührt' },
|
||||
{ '@type': ['Organization', 'HairSalon'], '@id': '#salon', name: 'Salon Müller', openingHours: 'Mo-Fr 09:00-18:00' },
|
||||
{ '@type': 'BreadcrumbList', itemListElement: [] },
|
||||
],
|
||||
}]
|
||||
const erg = norm(jsonLdEinbauen(bloecke, jsonldVomServer(), SEITE))
|
||||
assert.deepEqual(erg, { geaendert: [0], neu: null })
|
||||
const graph = bloecke[0]['@graph']
|
||||
assert.deepEqual(norm(graph[2].openingHoursSpecification), WOCHE_LD)
|
||||
assert.deepEqual(norm(graph[2].specialOpeningHoursSpecification), SONDER_LD)
|
||||
assert.equal(graph[2].openingHours, 'Mo-Fr 09:00-18:00', 'nur die beiden Specification-Felder werden ersetzt')
|
||||
assert.equal(graph[1].openingHoursSpecification, 'unberührt', 'Organization ist kein Unternehmen vor Ort')
|
||||
assert.ok(!('openingHoursSpecification' in graph[0]) && !('openingHoursSpecification' in graph[3]))
|
||||
})
|
||||
|
||||
test('JSON-LD: Typen aus der Liste der Unterarten, auch als Adresse oder mit Präfix; Felder-Listen oben (Array) und andere Typen zählen nicht', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
for (const typ of ['LocalBusiness', 'Bakery', 'CafeOrCoffeeShop', 'Dentist', 'AutoRepair', 'Store', 'Physician', 'Hotel', 'BeautySalon', 'schema:Florist', 'Restaurant']) {
|
||||
const b = [[{ '@type': typ, name: 'X' }]] // Block, der selbst eine Liste ist
|
||||
assert.deepEqual(norm(jsonLdEinbauen(b, jsonldVomServer(), SEITE)).geaendert, [0], typ)
|
||||
assert.deepEqual(norm(b[0][0].openingHoursSpecification), WOCHE_LD, typ)
|
||||
}
|
||||
for (const typ of ['Person', 'Organization', 'WebSite', 'WebPage', 'BreadcrumbList', 'Product', 'Event', 'Article', 'Dummy', '', undefined, 5]) {
|
||||
const b = [{ '@type': typ, name: 'X' }]
|
||||
const erg = norm(jsonLdEinbauen(b, jsonldVomServer(), SEITE))
|
||||
assert.deepEqual(erg.geaendert, [], String(typ))
|
||||
assert.ok(erg.neu, `${String(typ)}: kein Unternehmen vor Ort gefunden, also ein neuer Block`)
|
||||
assert.ok(!('openingHoursSpecification' in b[0]), String(typ))
|
||||
}
|
||||
})
|
||||
|
||||
test('JSON-LD: unparsbarer Block bleibt unberührt, neuer Block kommt dazu', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
const bloecke = [null, { '@context': 'https://schema.org', '@type': 'Organization', name: 'Sonnenschein GmbH' }, null]
|
||||
const vorher = JSON.stringify(bloecke)
|
||||
const erg = norm(jsonLdEinbauen(bloecke, jsonldVomServer(), SEITE))
|
||||
assert.deepEqual(erg.geaendert, [])
|
||||
assert.ok(erg.neu && erg.neu['@type'] === 'LocalBusiness')
|
||||
assert.equal(JSON.stringify(bloecke), vorher, 'die vorhandenen Blöcke bleiben, wie sie waren')
|
||||
// ein unparsbarer Block neben einem Unternehmen: der parsbare Block wird ergänzt, der unparsbare bleibt (null) unberührt
|
||||
const b2 = [null, { '@type': 'HairSalon', name: 'S' }]
|
||||
assert.deepEqual(norm(jsonLdEinbauen(b2, jsonldVomServer(), SEITE)), { geaendert: [1], neu: null })
|
||||
assert.equal(b2[0], null)
|
||||
})
|
||||
|
||||
test('JSON-LD: ohne LocalBusiness ⇒ neuerBlock mit name/url/address, die Zeiten kommen vom Server', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
const erg = norm(jsonLdEinbauen([], jsonldVomServer(), SEITE))
|
||||
assert.deepEqual(erg.geaendert, [])
|
||||
assert.deepEqual(erg.neu, {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'LocalBusiness',
|
||||
name: 'Bäckerei Sonnenschein',
|
||||
address: 'Hauptstraße 1, 67722 Winnweiler',
|
||||
url: 'https://baeckerei.example/',
|
||||
openingHoursSpecification: WOCHE_LD,
|
||||
specialOpeningHoursSpecification: SONDER_LD,
|
||||
})
|
||||
// ohne Adresse kein address-Feld; ohne Seiten-Adresse kein url-Feld
|
||||
const ohne = norm(jsonLdEinbauen([], jsonldVomServer(), { name: 'Nur Name', adresse: null, url: '' })).neu
|
||||
assert.equal(ohne.name, 'Nur Name')
|
||||
assert.ok(!('address' in ohne) && !('url' in ohne))
|
||||
// ohne Namen (kein Firmenname, kein Projektname): kein Block (ein LocalBusiness ohne name ist für Suchmaschinen wertlos)
|
||||
assert.equal(norm(jsonLdEinbauen([], jsonldVomServer(), { name: '', adresse: 'x', url: 'y' })).neu, null)
|
||||
// der Block ist eine Kopie: Änderungen daran berühren die Antwort des Servers nicht
|
||||
const jd = jsonldVomServer()
|
||||
const neu = jsonLdEinbauen([], jd, SEITE).neu
|
||||
neu.openingHoursSpecification[0].opens = '03:00'
|
||||
assert.equal(jd.neuerBlock.openingHoursSpecification[0].opens, '09:00')
|
||||
assert.equal(jd.openingHoursSpecification[0].opens, '09:00')
|
||||
})
|
||||
|
||||
test('JSON-LD: jsonld null (keine Zeiten gespeichert) lässt alles unberührt; leere Listen entfernen die alten Felder', () => {
|
||||
const { jsonLdEinbauen } = leisten()
|
||||
for (const jd of [null, undefined, 'x', 5, []]) {
|
||||
const b = [{ '@type': 'Restaurant', openingHoursSpecification: [{ x: 1 }] }]
|
||||
const vorher = JSON.stringify(b)
|
||||
assert.deepEqual(norm(jsonLdEinbauen(b, jd, SEITE)), { geaendert: [], neu: null }, JSON.stringify(jd))
|
||||
assert.equal(JSON.stringify(b), vorher)
|
||||
assert.deepEqual(norm(jsonLdEinbauen([], jd, SEITE)), { geaendert: [], neu: null })
|
||||
}
|
||||
// nach Vereinbarung / immer zu: nichts mehr zu sagen; die alten Zeiten dürfen nicht stehen bleiben
|
||||
const b = [{ '@type': 'Bakery', name: 'B', openingHoursSpecification: [{ x: 1 }], specialOpeningHoursSpecification: [{ y: 2 }] }]
|
||||
const erg = norm(jsonLdEinbauen(b, { openingHoursSpecification: [], specialOpeningHoursSpecification: [], neuerBlock: {} }, SEITE))
|
||||
assert.deepEqual(erg.geaendert, [0])
|
||||
assert.ok(!('openingHoursSpecification' in b[0]) && !('specialOpeningHoursSpecification' in b[0]))
|
||||
// kaputte Eingaben für bloecke: kein Fehler
|
||||
for (const kaputt of [undefined, null, 'x', {}, [undefined, 5, 'x', [], [null]]]) {
|
||||
assert.doesNotThrow(() => jsonLdEinbauen(kaputt, jsonldVomServer(), SEITE))
|
||||
}
|
||||
assert.doesNotThrow(() => jsonLdEinbauen([], jsonldVomServer(), null))
|
||||
})
|
||||
|
||||
test('Kontakt-Knöpfe aus Teildaten', () => {
|
||||
const { kontaktKnoepfe } = leisten()
|
||||
const route = 'https://www.google.com/maps/dir/?api=1&destination=Hauptstra%C3%9Fe%201'
|
||||
const wa = 'https://wa.me/491711234567?text=Hallo'
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: '491711234567', routeUrl: null, whatsappUrl: null })), [{ art: 'anruf', href: 'tel:+491711234567', text: 'Anrufen' }])
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: null, routeUrl: route, whatsappUrl: null })), [{ art: 'route', href: route, text: 'Route' }])
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: null, routeUrl: null, whatsappUrl: wa })), [{ art: 'whatsapp', href: wa, text: 'WhatsApp' }])
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: '491711234567', routeUrl: route, whatsappUrl: wa })).map((k) => k.art), ['anruf', 'route', 'whatsapp'])
|
||||
for (const leer of [null, undefined, {}, { telefon: null, routeUrl: null, whatsappUrl: null }, 'x', 5, []]) assert.deepEqual(norm(kontaktKnoepfe(leer)), [], JSON.stringify(leer))
|
||||
// Browser prüft erneut: fremde Schemata, http, Leerzeichen und keine Ziffernfolge fallen weg
|
||||
const k = norm(kontaktKnoepfe({ telefon: '0171 123', routeUrl: 'javascript:alert(1)', whatsappUrl: 'http://wa.me/491711234567' }))
|
||||
assert.deepEqual(k, [])
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: '+491711234567', routeUrl: 'https://x.example/a b', whatsappUrl: 'data:text/html,x' })), [], '"+" gehört nicht in die Ziffernfolge des Servers')
|
||||
assert.deepEqual(norm(kontaktKnoepfe({ telefon: '12345', routeUrl: 5, whatsappUrl: {} })), [], 'zu kurz / kein Text')
|
||||
})
|
||||
|
||||
test('Links aus der API werden erneut geprüft (https:, tel: nur über telefonLink)', () => {
|
||||
const { hinweisKnopf } = leisten()
|
||||
assert.equal(hinweisKnopf({ art: 'link', ziel: 'javascript:alert(1)', text: 'Los' }), null, 'javascript: ist kein Link')
|
||||
for (const bose of ['JaVaScRiPt:alert(1)', 'data:text/html,<b>x</b>', 'vbscript:x', 'http://x.example/', '//x.example/', '/aktion', 'x.example', ' https://x.example/', 'https://x.example/a b', 'https://', 'https:x', '', 'tel:+4963011234', 'https://x.example/\n', 5, null, {}]) {
|
||||
assert.equal(hinweisKnopf({ art: 'link', ziel: bose, text: 'Los' }), null, JSON.stringify(bose))
|
||||
}
|
||||
assert.deepEqual(norm(hinweisKnopf({ art: 'link', ziel: 'https://baeckerei.example/aktion?x=1#a', text: 'Zur Aktion' })), { art: 'link', href: 'https://baeckerei.example/aktion?x=1#a', text: 'Zur Aktion' })
|
||||
assert.deepEqual(norm(hinweisKnopf({ art: 'anruf', ziel: '06301 1234', text: 'Jetzt anrufen' })), { art: 'anruf', href: 'tel:063011234', text: 'Jetzt anrufen' })
|
||||
assert.deepEqual(norm(hinweisKnopf({ art: 'anruf', ziel: '+49 6301 1234', text: '' })), { art: 'anruf', href: 'tel:+4963011234', text: 'Anrufen' }, 'ohne Beschriftung eine Vorgabe')
|
||||
assert.equal(hinweisKnopf({ art: 'anruf', ziel: 'ruf mich an', text: 'Anrufen' }), null, 'freier Text ist keine Nummer')
|
||||
assert.equal(hinweisKnopf({ art: 'anruf', ziel: 'javascript:alert(1)', text: 'x' }), null)
|
||||
assert.equal(hinweisKnopf({ art: 'mail', ziel: 'mailto:a@b.de', text: 'x' }), null, 'unbekannte Art')
|
||||
for (const leer of [null, undefined, {}, 'x', 5, []]) assert.equal(hinweisKnopf(leer), null, JSON.stringify(leer))
|
||||
})
|
||||
|
||||
test('istEigeneAnrufLeiste: festes oder klebendes Element unten mit tel:-Link; oben, ausgeblendet oder bildschirmhoch zählt nicht', () => {
|
||||
const { istEigeneAnrufLeiste } = leisten()
|
||||
const fenster = 844
|
||||
const unten = { position: 'fixed', bottom: '0px', oben: fenster - 56, unten: fenster, fenster, sichtbar: true }
|
||||
assert.equal(istEigeneAnrufLeiste([unten]), true, 'feste Leiste am unteren Rand')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, position: 'sticky' }]), true, 'klebende Leiste unten (bottom gesetzt)')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, oben: fenster - 70, unten: fenster - 20 }]), true, 'schwebender Anruf-Knopf knapp über dem Rand')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, position: 'sticky', bottom: 'auto' }]), false, 'klebender Kopf (top) ist keine untere Leiste')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, oben: 0, unten: 60 }]), false, 'fester Kopf oben')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, oben: 0, unten: fenster }]), false, 'bildschirmhohe Seitenleiste')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, sichtbar: false }]), false, 'ausgeblendet')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, position: 'absolute' }]), false, 'nicht fest')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, position: 'static' }]), false)
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, oben: fenster + 100, unten: fenster + 156 }]), false, 'außerhalb des Bildschirms')
|
||||
assert.equal(istEigeneAnrufLeiste([{ ...unten, sichtbar: false }, unten]), true, 'ein Treffer genügt')
|
||||
for (const leer of [[], undefined, null, 'x', [null, undefined, 5]]) assert.equal(istEigeneAnrufLeiste(leer), false, JSON.stringify(leer))
|
||||
})
|
||||
|
||||
test('Farben der Hinweis-Leiste: je Art Hintergrund und Schrift mit Kontrast ≥ 4,5:1', () => {
|
||||
const { HINWEIS_FARBEN } = leisten()
|
||||
const farben = norm(HINWEIS_FARBEN)
|
||||
assert.deepEqual(Object.keys(farben).sort(), ['aktion', 'info', 'urlaub', 'wichtig'])
|
||||
const lum = (hex) => {
|
||||
const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4))
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
||||
}
|
||||
for (const [art, f] of Object.entries(farben)) {
|
||||
assert.match(f.bg, /^#[0-9a-f]{6}$/, `${art}: bg`)
|
||||
assert.match(f.fg, /^#[0-9a-f]{6}$/, `${art}: fg`)
|
||||
const [hell, dunkel] = [lum(f.bg), lum(f.fg)].sort((a, b) => b - a)
|
||||
assert.ok((hell + 0.05) / (dunkel + 0.05) >= 4.5, `${art}: Kontrast ${((hell + 0.05) / (dunkel + 0.05)).toFixed(2)}`)
|
||||
}
|
||||
})
|
||||
|
||||
test('Leisten im Quelltext: Shadow DOM, Rolle und Name, Handy-Abfrage, z-index 40, Abstandhalter, scroll-padding, rAF-Scroll, reduzierte Bewegung', () => {
|
||||
for (const noetig of [
|
||||
'attachShadow', "'region'", "'Hinweis'", 'aria-label', 'role',
|
||||
'(max-width: 768px)', 'matchMedia', 'z-index:40', 'position:fixed', 'bottom:0', 'noopener noreferrer',
|
||||
'scroll-padding-top', 'scroll-padding-bottom', 'prefers-reduced-motion', 'requestAnimationFrame', 'passive',
|
||||
'a[href^="tel:"]', 'application/ld+json', 'JSON.stringify', 'data-wkz-abstand', 'firstChild',
|
||||
]) {
|
||||
assert.ok(OHNE_KOMMENTARE.includes(noetig), `${noetig} fehlt im Skript`)
|
||||
}
|
||||
assert.doesNotMatch(OHNE_KOMMENTARE, /aria-live/)
|
||||
assert.ok(!OHNE_KOMMENTARE.includes('close') && !/Schlie(ss|ß)en/.test(OHNE_KOMMENTARE), 'keine Schließen-Schaltfläche')
|
||||
// JSON-LD wird über textContent geschrieben (nie innerHTML), der Selektor des Teams nur in try/catch
|
||||
assert.match(OHNE_KOMMENTARE, /\.textContent = JSON\.stringify\(/)
|
||||
assert.match(OHNE_KOMMENTARE, /try \{[^}]*querySelectorAll\(nav\)[^}]*\} catch/, 'navSelektor nur in try/catch')
|
||||
// Linkziele nie per String in HTML, sondern per setAttribute; jeder Link bekommt rel
|
||||
assert.ok(OHNE_KOMMENTARE.includes("'rel', 'noopener noreferrer'"))
|
||||
})
|
||||
|
||||
test('Ruling R29: tick zeichnet mit try/finally, ein sofort werfender fetch beendet den Abruf, beim Zurückkehren in den Tab erst zeichnen, dann laden', () => {
|
||||
assert.match(OHNE_KOMMENTARE, /function tick \(\) \{[\s\S]*?try \{ render\(\) \} finally \{ plane\(\) \}[\s\S]*?\n \}/)
|
||||
const lade = /function lade \(\) \{([\s\S]*?)\n \}\n/.exec(OHNE_KOMMENTARE)
|
||||
assert.ok(lade, 'lade fehlt')
|
||||
assert.match(lade[1], /try \{[^}]*fetch\([\s\S]*?\} catch[\s\S]*?fertig\(\)/, 'ein synchroner Fehler von fetch führt zu fertig()')
|
||||
const sicht = /addEventListener\('visibilitychange', function \(\) \{([\s\S]*?)\n \}\)/.exec(OHNE_KOMMENTARE)
|
||||
assert.ok(sicht, 'visibilitychange fehlt')
|
||||
assert.ok(sicht[1].indexOf('render()') >= 0 && sicht[1].indexOf('render()') < sicht[1].indexOf('lade()'), 'erst render(), dann lade()')
|
||||
})
|
||||
Reference in new issue
Block a user