Workers P4 Endprüfung W2: „Vorschau bauen“ fragt vor dem Start nach und fehlt bei toten Interessenten

Der Knopf startete einen Opus-Lauf mit einem einzigen Klick (Handy: voll breit zwischen anderen Knöpfen),
ohne dass sich der Bau in der Oberfläche zurücknehmen lässt. Wie Freigeben und Verwerfen fragt er jetzt
zuerst nach („Wirklich bauen?“, 4 s) und zeigt dabei, dass ein Opus-Lauf startet und die Vorschau gebaut
wird, als hätte der Interessent Ja gesagt (ohne „nur wenn Ja“: der Knopf gilt gerade für unklare Antworten).
rowModel blendet den Knopf bei gesperrtem, verlorenem oder abgeschlossenem Interessenten (gesperrt,
verloren, deal) aus; ohne Kurzfassung entscheidet weiter der Dienst. Prüfstand: die Fehler- und Fokus-Läufe
klicken zweimal, Szenario bauen prüft Frage, Hinweis und Verfall. Doppeltipp-Schutz und Dienst-Härtung
(bauLauf nur nach Ja) bleiben offen, siehe final-fix-report-woms.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-18 23:09:42 +00:00
1 parent 1536a3bbc1
commit 871b87fac0
5 files changed
+99 -19

No files matched your search

+45 -5
View File
@@ -484,7 +484,7 @@ test('PultList (P4-T32): Quelltext – Aktionen über pultAction, Prüfung mit v
for (const t of [
"'reply'", "'approve-preview'", "'paste'", "'start-build'", 'validateReplyText', 'canReply', 'canApprovePreview', 'canStartBuild', 'canPaste', 'previewHref',
'actionErrorText', 'pasteDoneText', 'rel="noopener noreferrer"', 'target="_blank"',
'Als Mensch antworten', 'Jetzt senden', 'Vorschau ansehen', 'Freigeben & senden', 'Wirklich freigeben?', 'Vorschau bauen',
'Als Mensch antworten', 'Jetzt senden', 'Vorschau ansehen', 'Freigeben & senden', 'Wirklich freigeben?', 'Vorschau bauen', 'Wirklich bauen?',
'Antwort des Kunden einfügen', 'Einfügen', 'wk-pult-reply', 'wk-pult-paste',
'Kopiere die Antwort aus der Plattform hierher. Nora sortiert sie ein; bei einer Frage schreibt Clara den nächsten Entwurf.',
]) assert.ok(s.includes(t), t)
@@ -546,6 +546,12 @@ test('PultList (gerendert, P4-T32): Aktionen je Art – Antworten, Freigeben, Ba
// Interessent ohne Adresse (Plattform): kein Mail-Kanal ⇒ nicht antworten, aber bauen
html = show([{ ...base, prospect: { $id: 'p1', name: 'Verein' } }])
assert.ok(!html.includes('Als Mensch antworten')); assert.ok(html.includes('Vorschau bauen'))
// Endprüfung P4 (W2): ein toter Interessent (gesperrt, verloren, Deal) bekommt keinen Knopf zum Bauen, ein lebender behält ihn
for (const status of ['gesperrt', 'verloren', 'deal']) {
html = show([{ ...base, prospect: { ...base.prospect, status } }])
assert.ok(!html.includes('Vorschau bauen'), status); assert.ok(buttonOf(html, 'Als Mensch antworten'), status); assert.ok(buttonOf(html, 'Erledigt'), status)
}
assert.ok(buttonOf(show([{ ...base, prospect: { ...base.prospect, status: 'gespraech' } }]), 'Vorschau bauen'))
// von einem Kollegen übernommen: weder antworten noch bauen, der Rest bleibt wie bisher
html = show([{ ...base, status: 'in_arbeit', claimedBy: 'mensch:u2' }])
assert.ok(html.includes('übernommen von Kenso')); assert.ok(!html.includes('Als Mensch antworten')); assert.ok(!html.includes('Vorschau bauen')); assert.ok(buttonOf(html, 'Erledigt'))
@@ -752,22 +758,56 @@ test('PultList (bedient, P4-T32): während einer Anfrage sind alle Knöpfe der Z
} finally { ui.end() }
})
test('PultList (bedient, P4-T32): ein „unsicher“-Eintrag ohne Entwurf öffnet „Als Mensch antworten“ mit leerem Feld; „Vorschau bauen“ startet den Bau', async () => {
const api = scriptedApi(failure('Für diesen Interessenten gibt es schon eine Vorschau.', 409), Promise.resolve({ item: { $id: 'e1' } }))
test('PultList (bedient, P4-T32): ein „unsicher“-Eintrag ohne Entwurf öffnet „Als Mensch antworten“ mit leerem Feld', async () => {
const api = scriptedApi()
const ui = await startList([{ ...unsicher, draft: undefined }], api)
try {
await ui.click('Als Mensch antworten')
assert.deepEqual(ui.value('Text der Antwort'), ['']); assert.ok(ui.text().includes('0 / 8000'))
// Bau starten: ohne Body, Fehler des Dienstes als Satz, Erfolg oben bei der Liste
assert.equal(api.calls.length, 0)
} finally { ui.end() }
})
// Endprüfung P4 (W2): „Vorschau bauen“ startet einen Opus-Lauf und lässt sich in der Oberfläche nicht zurücknehmen: wie Freigeben und Verwerfen
// fragt der Knopf zuerst nach (4 s). Ein Fehlklick (Handy: der Knopf liegt in voller Breite zwischen anderen) startet keinen Bau mehr.
test('PultList (bedient, W2): „Vorschau bauen“ – erster Klick fragt nach (4 s, Hinweis), zweiter startet den Bau; Fehler und Erfolg wie bisher', async () => {
const api = scriptedApi(failure('Für diesen Interessenten gibt es schon eine Vorschau.', 409), Promise.resolve({ item: { $id: 'e1' } }))
const ui = await startList([{ ...unsicher, draft: undefined }], api)
try {
// erster Klick: Rückfrage und Hinweis zu Kosten und Wirkung, nichts geht hinaus; die Rückfrage verfällt nach 4 s
assert.ok(!ui.text().includes('Opus'))
await ui.click('Vorschau bauen')
assert.equal(api.calls.length, 0); assert.ok(ui.has('Wirklich bauen?')); assert.ok(!ui.has('Vorschau bauen'))
assert.ok(ui.text().includes('Startet einen Opus-Lauf')); assert.ok(ui.text().includes('als hätte der Interessent Ja gesagt'))
assert.ok(!ui.text().includes('nur wenn')) // kein „nur wenn der Interessent Ja gesagt hat“: der Knopf gilt gerade für unklare Antworten
assert.deepEqual([...ui.timers.values()].map((t) => t.ms), [4000])
ui.fireTimers(); await settle()
assert.ok(ui.has('Vorschau bauen')); assert.ok(!ui.has('Wirklich bauen?')); assert.ok(!ui.text().includes('Opus')); assert.equal(api.calls.length, 0)
// Rückfrage und zweiter Klick ⇒ Aktion ohne Body; der Dienst lehnt ab: sein Satz erscheint, die Rückfrage beginnt von vorn
await ui.click('Vorschau bauen'); await ui.click('Wirklich bauen?')
assert.deepEqual(api.calls, [['e1', 'start-build']])
assert.deepEqual(ui.messages(), [{ kind: 'err', text: 'Für diesen Interessenten gibt es schon eine Vorschau.', role: 'alert' }])
await ui.click('Vorschau bauen')
assert.ok(ui.has('Vorschau bauen')); assert.ok(!ui.text().includes('Opus'))
// Erfolg oben bei der Liste
await ui.click('Vorschau bauen'); await ui.click('Wirklich bauen?')
assert.deepEqual(ui.messages(), [{ kind: 'ok', text: '„Unklare Antwort“ wird gebaut.', role: 'status' }])
assert.equal(api.calls.length, 2)
} finally { ui.end() }
})
test('PultList (bedient, W2): die Rückfragen vor Bauen, Verwerfen und Freigeben lösen einander ab; Verwerfen sendet nichts ohne zweiten Klick', async () => {
const api = scriptedApi()
const ui = await startList([unsicher], api)
try {
await ui.click('Vorschau bauen'); assert.ok(ui.has('Wirklich bauen?'))
await ui.click('Verwerfen'); assert.ok(ui.has('Wirklich verwerfen?')); assert.ok(ui.has('Vorschau bauen')); assert.ok(!ui.text().includes('Opus'))
await ui.click('Vorschau bauen'); assert.ok(ui.has('Wirklich bauen?')); assert.ok(ui.has('Verwerfen'))
assert.equal(api.calls.length, 0)
await ui.click('Wirklich bauen?')
assert.deepEqual(api.calls, [['e1', 'start-build']])
} finally { ui.end() }
})
test('PultList (bedient, P4-T32): Vorschau freigeben – erster Klick fragt nach (4 s), zweiter sendet; keine Antwort heißt „Kann gesendet sein“', async () => {
const freigabe = { ...unsicher, $id: 'f1', kind: 'vorschau_freigabe', title: 'Vorschau prüfen', draft: 'Hier ist Ihre Vorschau.', sourceUrl: 'https://entwurf.project.webklar.com/AAA/' }
const api = scriptedApi(failure('Die Vorschau ist nicht freigabebereit.', 409), failure('Der Hustler-Dienst ist gerade nicht erreichbar.', 0), Promise.resolve({ item: { $id: 'f1' }, previewUrl: freigabe.sourceUrl }))