Workers P3-Endprüfung W8: wiederkehrende Bedienelemente im Pult mit eindeutigem Namen

"Details", "Anzeige öffnen", das Entwurfsfeld und die Aktionsgruppe tragen den Titel der Zeile im
zugänglichen Namen ("Details zu <Titel>"), das sichtbare Wort steht vorn (WCAG 2.5.3); ohne
Titel gilt der schlichte Name. Der Prüfstand sucht die Knöpfe unter den neuen Namen und prüft
zusätzlich die Eindeutigkeit der Namen (W8) und die Abschlusszeile im Reiter Erledigt (W5).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-18 10:46:20 +00:00
1 parent 4ec3022df4
commit 17fb02150e
3 files changed
+70 -10

No files matched your search

+34 -1
View File
@@ -317,7 +317,7 @@ test('PultList (gerendert): Aktionen je Art und Status, Fremdtext nur als Text,
let html = show([{ ...base, originalText: 'Original <img src=x onerror=alert(1)>', draft: 'Hallo <script>alert(1)</script>', title: 'T <b>x</b>' }])
for (const t of ['Kopieren &amp; öffnen', 'Ich kümmere mich', 'Als gesendet markieren', 'Verwerfen', 'Details', '66640 Namborn · Score 72', 'vor 3 Std.']) assert.ok(html.includes(t), t)
const erledigt = '<button class="btn" type="button">Erledigt</button>' // der Filter „Erledigt“ steht ebenfalls auf der Seite: nur den Knopf der Zeile meinen
assert.ok(!html.includes(erledigt)); assert.match(html, /<a class="link" href="https:\/\/www\.kleinanzeigen\.de\/s-anzeige\/x\/1-2-3" target="_blank" rel="noopener noreferrer">/)
assert.ok(!html.includes(erledigt)); assert.match(html, /<a class="link" href="https:\/\/www\.kleinanzeigen\.de\/s-anzeige\/x\/1-2-3" target="_blank" rel="noopener noreferrer" aria-label="Anzeige öffnen: T &lt;b&gt;x&lt;\/b&gt;">/)
assert.match(html, /<textarea class="textarea wk-pult-draft"[^>]*>Hallo &lt;script&gt;alert\(1\)&lt;\/script&gt;<\/textarea>/)
// Fremdtext erscheint nie als Markup
assert.ok(!html.includes('<script>') && !html.includes('<img') && !html.includes('<b>x</b>')); assert.ok(html.includes('Original &lt;img src=x onerror=alert(1)&gt;'))
@@ -386,3 +386,36 @@ test('PultList (gerendert): abgeschlossene Einträge zeigen Ergebnis, Person und
assert.ok(open.includes('<span>vor 4 Tagen</span>')); assert.ok(!open.includes('Gesendet')); assert.ok(!open.includes('badge green'))
} finally { delete globalThis.__pultFeed; delete globalThis.__pultEmployees }
})
// Endprüfung P3 (W8): „Details“, „Anzeige öffnen“, Entwurfsfeld und Aktionsgruppe tragen den Titel der Zeile im zugänglichen Namen
test('PultList (gerendert): wiederkehrende Bedienelemente haben je Zeile einen eigenen zugänglichen Namen, sichtbares Wort vorn (W8)', async () => {
const { render } = await loadList()
const show = (items) => {
globalThis.__pultFeed = { items, loading: false, error: null, refresh: async () => {} }
globalThis.__pultEmployees = []
return render({ api: {}, me: { id: 'u1', name: 'Justin' } })
}
const base = { kind: 'plattform_antwort', status: 'offen', draft: 'Hallo', createdAt: new Date().toISOString(), sourceUrl: 'https://www.kleinanzeigen.de/s-anzeige/x/1-2-3', prospect: { $id: 'p1', name: 'Verein' } }
try {
const html = show([{ ...base, $id: 'a', title: 'Suche Webdesigner' }, { ...base, $id: 'b', title: 'Homepage für Handwerker <b>x</b> & "Co"' }])
for (const name of ['Details zu Suche Webdesigner', 'Anzeige öffnen: Suche Webdesigner', 'Entwurf der Antwort: Suche Webdesigner', 'Aktionen: Suche Webdesigner']) {
assert.ok(html.includes(`aria-label="${name}"`), name)
}
// zwei Zeilen ⇒ zwei verschiedene Namen; Fremdtext im Namen ist als Attribut kodiert
const names = [...html.matchAll(/aria-label="(Details zu [^"]*)"/g)].map((m) => m[1])
assert.equal(names.length, 2); assert.equal(new Set(names).size, 2)
assert.ok(html.includes('aria-label="Details zu Homepage für Handwerker &lt;b&gt;x&lt;/b&gt; &amp; &quot;Co&quot;"'))
assert.ok(!html.includes('<b>x</b>'))
// das sichtbare Wort bleibt (WCAG 2.5.3) und steht im Namen vorn
assert.match(html, /aria-label="Details zu Suche Webdesigner">Details<\/button>/)
assert.match(html, /aria-label="Anzeige öffnen: Suche Webdesigner">Anzeige öffnen<\/a>/)
// leerer oder fehlender Titel: schlichter Name, nie „zu undefined“
for (const title of ['', ' ', undefined]) {
const bare = show([{ ...base, $id: 'c', title }])
assert.ok(!bare.includes('undefined'), String(title))
assert.ok(!bare.includes('Details zu'), String(title)); assert.ok(!bare.includes('Anzeige öffnen:'), String(title))
assert.ok(bare.includes('aria-label="Entwurf der Antwort"'), String(title)); assert.ok(bare.includes('aria-label="Aktionen"'), String(title))
assert.match(bare, />Details<\/button>/)
}
} finally { delete globalThis.__pultFeed; delete globalThis.__pultEmployees }
})