Hustler-Stufe: Keller und Bot-Leads erst ab Stufe 6 (Seite, Keller-Etage, Spur-Links, Abruf von /botleads)

WorkersPage: ?tab=botleads (auch mit &bot=) und unbekannte Werte fallen unterhalb von Stufe 6 auf das Hochhaus zurück, BotLeadList wird nie eingehängt; die Weiterleitungen /leads und /workers bleiben.
HochhausWelt: die Keller-Etage ist dann ein Knopf wie jede andere (zoomt heran) statt eines Links; Arne bleibt klickbar, die Zahl Bot-Leads in der Kopfzeile bleibt Text.
HustlerDialog: Spur-Links in den Keller bleiben Text. workersApi.botleads ruft unterhalb von Stufe 6 nichts ab (kein JWT, keine Anfrage), sondern liefert 404 mit deutschem Satz.
Bestehende Keller-Tests laufen ausdrücklich auf Stufe 6; neue Tests prüfen Stufe 1, 3 und 5 (gesperrt) und 6 bis 9 (offen).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-22 10:36:52 +00:00
1 parent 5e48fbf264
commit 32f4f1d941
10 files changed
+262 -21

No files matched your search

+74 -1
View File
@@ -120,7 +120,9 @@ async function start(initial = {}) {
const { __mount, jsx, HochhausWelt, indexWorkers } = await laden()
const state = initial.state === undefined ? makeState() : initial.state
const handle = { current: null }
let props = { state, workers: state ? indexWorkers(state) : {}, onZeige() {}, onOpen() {}, ...initial }
// Stufen-Sperre (hustlerStufe.js): die Zusicherungen dieser Datei gelten für das volle Haus (Stufe 6, Keller offen, Verhalten wie vor der Sperre);
// stufe: 3 (Keller gesperrt) steht in den eigenen Tests am Ende des Abschnitts „Etagen“
let props = { state, workers: state ? indexWorkers(state) : {}, onZeige() {}, onOpen() {}, stufe: 6, ...initial }
const mounted = __mount(jsx(() => jsx(HochhausWelt, { ...props, ref: handle }), {}))
await settle()
const view = {
@@ -478,6 +480,77 @@ test('Etagen: ein Etagen-Knopf zoomt heran (Kamera wie kameraEtage), ohne onOpen
} finally { ui.end(); restore() }
})
// Stufen-Sperre: unterhalb der Keller-Stufe (6) gibt es keinen Weg in den Keller; die Etage verhält sich wie jede andere (zoomt heran), Arne bleibt klickbar
test('Etagen bei Stufe 3 und 5: nur Freigabe ist ein Link, die Keller-Etage ist ein Knopf wie die anderen (Beschriftung, Text, kein href)', async () => {
const { ETAGEN } = await laden()
for (const stufe of [1, 3, 5]) {
const ui = await start({ stufe })
try {
const etagen = byClass(ui.tree(), 'hk-etage')
assert.equal(etagen.length, 10, `Stufe ${stufe}`)
assert.deepEqual(etagen.map((n) => n.tag), ['button', 'button', 'button', 'button', 'button', 'button', 'button', 'a', 'button', 'button'], `Stufe ${stufe}`)
assert.deepEqual(etagen.map((n) => n.props['aria-label']), [
'Kommandobrücke heranzoomen', 'Anfragen heranzoomen', 'Ohne Website heranzoomen', 'Bewertung heranzoomen', 'Gespräche heranzoomen',
'Werkstatt heranzoomen', 'Prüfung heranzoomen', 'Freigabe: Freigabe-Pult öffnen', 'Tresor heranzoomen', 'Keller heranzoomen',
], `Stufe ${stufe}`)
assert.deepEqual(etagen.map((n) => textOf(n)).slice(7), ['Freigabe ▸', 'Tresor', 'Keller'], `Stufe ${stufe}`)
const keller = etagen[9]
assert.equal(keller.props.type, 'button'); assert.equal(keller.props.href, undefined); assert.equal(keller.props['data-hk-etage'], 'keller')
// dieselbe Lage wie vorher, kein Loch im Haus
const e = ETAGEN.find((x) => x.id === 'keller')
assert.deepEqual(keller.props.style, { left: 960, top: e.oben, width: 512, height: e.unten - e.oben })
// im ganzen Baum führt nichts mehr in den Keller: kein Link, kein Text „Bot-Leads ▸“, kein tab=botleads
assert.deepEqual(nodes(ui.tree(), (n) => n.tag === 'a').map((n) => n.props.href), ['/hustler?tab=freigabe'])
assert.ok(!textOf(ui.tree()).includes('Bot-Leads ▸'))
assert.ok(!JSON.stringify(nodes(ui.tree(), (n) => n.tag === 'a').map((n) => n.props)).includes('botleads'))
} finally { ui.end() }
}
})
test('Stufe 3: Klick auf die Keller-Etage zoomt heran und öffnet keinen Bildschirm; die Freigabe-Etage öffnet weiter das Pult', async () => {
const { kameraEtage, ETAGEN } = await laden()
const geoeffnet = []
const restore = fensterAttrappe()
const ui = await start({ stufe: 3, onOpen: (tab) => geoeffnet.push(tab) })
try {
ui.anhaengen()
const keller = ETAGEN.find((e) => e.id === 'keller')
ui.etage('Keller').props.onClick(ereignis())
nearKamera(ui.kamera(), kameraEtage(keller.oben, keller.unten, STANDARD_GROESSE), 'Keller')
assert.ok(hasClass(ui.buehne(), 'hk-gleitet'))
assert.deepEqual(geoeffnet, [])
await wait(650)
const e = ereignis(); ui.etage('Freigabe ▸').props.onClick(e)
assert.equal(e.defaultPrevented, true); assert.deepEqual(geoeffnet, ['freigabe'])
} finally { ui.end(); restore() }
})
test('Stufe 3: Arne bleibt im Haus sichtbar und klickbar (Detail-Dialog), auch die Keller-Zahl am Schild bleibt Text', async () => {
const gezeigt = []
const ui = await start({ stufe: 3, onZeige: (id) => gezeigt.push(id), state: makeState({ kpis: { pultOpen: 2, dealsMonth: 1, botLeads: 112 } }) })
try {
const arne = ui.hustler('arne')
assert.ok(arne, 'Arne steht im Haus')
assert.match(arne.props['aria-label'], /^Arne, /)
arne.props.onClick(ereignis())
assert.deepEqual(gezeigt, ['arne'])
const schild = byClass(ui.tree(), 'hk-schildtext-keller')
assert.equal(schild.length, 1); assert.equal(textOf(schild[0]), '112 Bot-Leads')
assert.equal(schild[0].tag === 'a' || schild[0].tag === 'button', false)
} finally { ui.end() }
})
test('Stufe 6 und höher: die Keller-Etage bleibt der Link auf die Bot-Leads (wie vor der Sperre)', async () => {
for (const stufe of [6, 7, 9]) {
const ui = await start({ stufe })
try {
const keller = ui.etage('Keller · Bot-Leads ▸')
assert.equal(keller.tag, 'a', `Stufe ${stufe}`); assert.equal(keller.props.href, '/hustler?tab=botleads')
assert.equal(keller.props['aria-label'], 'Keller · Bot-Leads: Bot-Leads öffnen')
} finally { ui.end() }
}
})
// ---------- Klicks, Pause, gesperrt ----------
test('Figur-Klick ruft onZeige(id), jeder Hustler mit seiner Kennung', async () => {