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:
1 parent
5e48fbf264
commit
32f4f1d941
10 files changed
+262
-21
No files matched your search
@@ -385,6 +385,38 @@ test('Spur-Links: unsichere (javascript:, //host, /\\host, data:) bleiben Text;
|
||||
})
|
||||
})
|
||||
|
||||
// Stufen-Sperre (hustlerStufe.js): unterhalb der Keller-Stufe (6) führt auch kein Spur-Link in den Keller; der Eintrag bleibt als Text stehen
|
||||
test('Spur-Links in den Keller (?tab=botleads, auch über /workers und /leads) sind auf Stufe 3 Text und ab Stufe 6 Router-Links; alle anderen Links bleiben', async () => {
|
||||
const events = [
|
||||
{ id: '1', ts: '2026-10-22T09:00:00Z', text: 'Keller', link: '/hustler?tab=botleads&bot=abc123' },
|
||||
{ id: '2', ts: '2026-10-22T08:59:00Z', text: 'Alt', link: '/workers?tab=botleads&bot=abc123' },
|
||||
{ id: '3', ts: '2026-10-22T08:58:00Z', text: 'Leads', link: '/leads?tab=botleads' },
|
||||
{ id: '4', ts: '2026-10-22T08:57:00Z', text: 'Pult', link: '/hustler?tab=freigabe' },
|
||||
{ id: '5', ts: '2026-10-22T08:56:00Z', text: 'Ticket', link: '/tickets/100001' },
|
||||
{ id: '6', ts: '2026-10-22T08:55:00Z', text: 'Extern', link: 'https://example.org/hustler?tab=botleads' },
|
||||
]
|
||||
const ziele = (li) => nodes(li, (n) => n.tag === 'a' || n.tag === 'router-link')
|
||||
for (const stufe of [1, 3, 5]) {
|
||||
await lauf({ props: { workerId: 'lea', stufe }, trace: { trace: { events }, loading: false, error: null } }, (ui) => {
|
||||
const zeilen = ui.spurZeilen(); const byText = (t) => zeilen.find((z) => z.text === t)
|
||||
assert.equal(zeilen.length, 6)
|
||||
for (const t of ['Keller', 'Alt', 'Leads']) assert.equal(ziele(byText(t).li).length, 0, `Stufe ${stufe}: ${t} bleibt Text`)
|
||||
assert.deepEqual(ziele(byText('Pult').li).map((n) => n.props.to), ['/hustler?tab=freigabe'])
|
||||
assert.deepEqual(ziele(byText('Ticket').li).map((n) => n.props.to), ['/tickets/100001'])
|
||||
assert.deepEqual(ziele(byText('Extern').li).map((n) => n.props.href), ['https://example.org/hustler?tab=botleads'])
|
||||
assert.ok(!JSON.stringify(ui.find((x) => x.tag === 'a' || x.tag === 'router-link').map((n) => n.props)).includes('botleads&bot'))
|
||||
})
|
||||
}
|
||||
for (const stufe of [6, 9]) {
|
||||
await lauf({ props: { workerId: 'lea', stufe }, trace: { trace: { events }, loading: false, error: null } }, (ui) => {
|
||||
const zeilen = ui.spurZeilen(); const byText = (t) => zeilen.find((z) => z.text === t)
|
||||
assert.deepEqual(ziele(byText('Keller').li).map((n) => n.props.to), ['/hustler?tab=botleads&bot=abc123'])
|
||||
assert.deepEqual(ziele(byText('Alt').li).map((n) => n.props.to), ['/workers?tab=botleads&bot=abc123'])
|
||||
assert.deepEqual(ziele(byText('Leads').li).map((n) => n.props.to), ['/leads?tab=botleads'])
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
// Tasten, Blättern, Hintergrund
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url'
|
||||
import esbuild from 'esbuild'
|
||||
import { fakeReact } from './helpers/fakeReact.mjs'
|
||||
import { ev, makeState } from './helpers/workersFixtures.mjs'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
// Das Gerüst der Hustler-Pixelwelt (T3) läuft wirklich: im Mini-Läufer anstelle von React (Muster botleadList.test.mjs, Baustein helpers/fakeReact.mjs).
|
||||
// 1. Hochhaus.jsx: Laden, Dienst nicht erreichbar („Neu laden“), geladen -> Welt, Kopfzeile, Detailansicht auf Klick.
|
||||
@@ -14,6 +15,7 @@ import { ev, makeState } from './helpers/workersFixtures.mjs'
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
||||
const importBundle = (out) => import(`data:text/javascript;base64,${Buffer.from(out.outputFiles[0].text).toString('base64')}`)
|
||||
const settle = () => new Promise((resolve) => setImmediate(resolve))
|
||||
const { HUSTLER_STUFE } = await loadModule('src/lib/hustlerStufe.js')
|
||||
|
||||
const nodes = (node, match, out = []) => {
|
||||
if (node === null || typeof node === 'string') return out
|
||||
@@ -85,6 +87,26 @@ test('Hochhaus: solange nichts geladen ist, steht „Wird geladen …“ mit rol
|
||||
} finally { view.end() }
|
||||
})
|
||||
|
||||
test('Hochhaus: die Stufe (Stufen-Sperre) geht an die Welt und an die Detailansicht; ohne Angabe gilt HUSTLER_STUFE', async () => {
|
||||
const feed = { state: makeState(), error: null, loaded: true, refresh() {} }
|
||||
for (const stufe of [3, 6]) {
|
||||
const view = await hochhaus(feed, { stufe })
|
||||
try {
|
||||
assert.equal(view.hh.welt.stufe, stufe)
|
||||
view.hh.welt.onZeige('arne')
|
||||
await settle()
|
||||
assert.equal(view.hh.dialog.stufe, stufe); assert.equal(view.hh.dialog.workerId, 'arne')
|
||||
} finally { view.end() }
|
||||
}
|
||||
const ohne = await hochhaus(feed)
|
||||
try {
|
||||
assert.equal(ohne.hh.welt.stufe, HUSTLER_STUFE)
|
||||
ohne.hh.welt.onZeige('arne')
|
||||
await settle()
|
||||
assert.equal(ohne.hh.dialog.stufe, HUSTLER_STUFE)
|
||||
} finally { ohne.end() }
|
||||
})
|
||||
|
||||
test('Hochhaus: Dienst nie erreicht -> Pixel-Leerzustand mit Titel, Fehlertext als Text und „Neu laden“, das refresh ruft', async () => {
|
||||
const c = counting()
|
||||
const view = await hochhaus({ state: null, error: '<b>Der Dienst antwortet nicht.</b>', loaded: false, refresh: c.refresh })
|
||||
@@ -246,7 +268,9 @@ const loadSeite = () => (seiteBundle ??= esbuild.build({
|
||||
}).then(importBundle))
|
||||
|
||||
// Ein Lauf der Seite. query ist der Teil nach dem ?, feed wird vom Test zwischendurch geändert (setFeed) und die Seite neu gerendert.
|
||||
async function seite(query, { admin = false, feed } = {}) {
|
||||
// stufe (Stufen-Sperre, hustlerStufe.js): die Zusicherungen dieser Datei gelten für die volle Seite (Stufe 6, Keller offen, Verhalten wie vor der Sperre);
|
||||
// die Tests „Stufe 3“ weiter unten bauen die Seite mit stufe: 3 (Stand der Produktion).
|
||||
async function seite(query, { admin = false, feed, stufe = 6 } = {}) {
|
||||
const { __mount, jsx, WorkersPage } = await loadSeite()
|
||||
const setParamsCalls = []
|
||||
const hk = {
|
||||
@@ -263,7 +287,7 @@ async function seite(query, { admin = false, feed } = {}) {
|
||||
const savedDocument = globalThis.document
|
||||
globalThis.__hk = hk
|
||||
globalThis.document = { title: 'Vorher' }
|
||||
const mounted = __mount(jsx(WorkersPage, {}))
|
||||
const mounted = __mount(jsx(WorkersPage, { stufe }))
|
||||
await settle()
|
||||
const view = {
|
||||
hk, setParamsCalls,
|
||||
@@ -306,6 +330,66 @@ test('Seite: ?tab=freigabe zeigt das Pult, ?tab=botleads den Keller, beide direk
|
||||
} finally { keller.end() }
|
||||
})
|
||||
|
||||
// ---------- Stufen-Sperre (Stufe 3 = Stand der Produktion: Dienst P3, ohne Keller) ----------
|
||||
|
||||
// Adressen, die auf Stufe 3 in den Keller führen würden: der Reiter, mit Einzelfall, mit Ballast, andere Schreibweisen und erfundene Parameter
|
||||
const KELLER_ADRESSEN = ['tab=botleads', 'tab=botleads&bot=abc123', 'bot=abc123&tab=botleads', 'tab=botleads&bot=', 'tab=BotLeads', 'ansicht=keller', 'tab=keller', 'tab=botleads&ansicht=keller']
|
||||
|
||||
test('Stufe 3: jede Adresse in den Keller fällt auf das Hochhaus zurück; der Keller wird nie eingehängt, Hochhaus und Seite bleiben ganz', async () => {
|
||||
for (const stufe of [1, 3, 5]) {
|
||||
for (const query of KELLER_ADRESSEN) {
|
||||
const ui = await seite(query, { stufe, feed: { state: makeState(), error: null, loaded: true, refresh() {} } })
|
||||
try {
|
||||
assert.equal(ui.root().props.className, 'hk-seite', `${stufe} ${query}`)
|
||||
assert.equal(ui.root().props['data-tab'], 'hochhaus', `${stufe} ${query}`)
|
||||
assert.deepEqual(ui.screen(), ['hochhaus'], `${stufe} ${query}`)
|
||||
assert.equal(ui.hk.renders.keller.length, 0, `${stufe} ${query}: BotLeadList wurde nie gezeichnet`)
|
||||
assert.equal(ui.hk.props.keller, undefined, `${stufe} ${query}`)
|
||||
assert.equal(ui.hk.props.hochhaus.stufe, stufe)
|
||||
} finally { ui.end() }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Stufe 3: der Wechsel der Adresse zu ?tab=botleads zeigt das Hochhaus, Freigabe bleibt erreichbar; der Rückweg aus dem Pult funktioniert wie sonst', async () => {
|
||||
const ui = await seite('tab=freigabe', { stufe: 3, feed: { state: makeState(), error: null, loaded: true, refresh() {} } })
|
||||
try {
|
||||
assert.deepEqual(ui.screen(), ['pult'])
|
||||
ui.go('tab=botleads&bot=x'); assert.deepEqual(ui.screen(), ['hochhaus']); assert.equal(ui.hk.props.hochhaus.vonTab, 'freigabe')
|
||||
ui.go('tab=freigabe'); assert.deepEqual(ui.screen(), ['pult'])
|
||||
ui.go('tab=hochhaus'); assert.deepEqual(ui.screen(), ['hochhaus'])
|
||||
assert.equal(ui.hk.renders.keller.length, 0); assert.equal(ui.hk.props.keller, undefined)
|
||||
} finally { ui.end() }
|
||||
})
|
||||
|
||||
test('Stufe 3: das Hochhaus öffnet nur noch die Freigabe (onOpen(\'botleads\') tut nichts); Hochhaus und Pult bekommen die Stufe', async () => {
|
||||
const ui = await seite('tab=hochhaus', { stufe: 3, feed: { state: makeState(), error: null, loaded: true, refresh() {} } })
|
||||
try {
|
||||
const p = ui.hk.props.hochhaus
|
||||
p.onOpen('botleads'); p.onOpen('freigabe')
|
||||
assert.deepEqual(ui.setParamsCalls, [{ tab: 'freigabe' }])
|
||||
ui.go('tab=freigabe')
|
||||
assert.equal(ui.hk.props.pult.stufe, 3)
|
||||
ui.hk.props.pult.onBack()
|
||||
assert.deepEqual(ui.setParamsCalls, [{ tab: 'freigabe' }, { tab: 'hochhaus' }])
|
||||
} finally { ui.end() }
|
||||
})
|
||||
|
||||
test('Stufe 6 und höher: ?tab=botleads zeigt den Keller samt Einzelfall (bot), onOpen(\'botleads\') wechselt; Stufe 4 und 5 haben den Keller noch nicht', async () => {
|
||||
for (const stufe of [6, 8, 9]) {
|
||||
const ui = await seite('tab=botleads&bot=abc123', { stufe, feed: { state: makeState(), error: null, loaded: true, refresh() {} } })
|
||||
try {
|
||||
assert.deepEqual(ui.screen(), ['keller'], `Stufe ${stufe}`); assert.equal(ui.hk.props.keller.bot, 'abc123')
|
||||
ui.go('tab=hochhaus'); ui.hk.props.hochhaus.onOpen('botleads')
|
||||
assert.deepEqual(ui.setParamsCalls, [{ tab: 'botleads' }], `Stufe ${stufe}`)
|
||||
} finally { ui.end() }
|
||||
}
|
||||
for (const stufe of [4, 5]) {
|
||||
const ui = await seite('tab=botleads', { stufe })
|
||||
try { assert.deepEqual(ui.screen(), ['hochhaus'], `Stufe ${stufe}`) } finally { ui.end() }
|
||||
}
|
||||
})
|
||||
|
||||
test('Seite: keine Seitenüberschrift, keine Reiterleiste', async () => {
|
||||
for (const query of ['', 'tab=freigabe', 'tab=botleads']) {
|
||||
const ui = await seite(query)
|
||||
|
||||
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
// API-Client der Hustler-Seite: URLs, Methoden, Header, deutsche Fehlertexte, JWT-Wiederholung, Pult-Prüfungen
|
||||
const { createWorkersApi, REQUEST_TIMEOUT_MS, AUTH_COOLDOWN_MS, ACTION_TIMEOUT_MS, SLOW_PULT_ACTIONS, UNCERTAIN_STATUS } = await loadModule('src/lib/workersApi.js')
|
||||
const { createWorkersApi, REQUEST_TIMEOUT_MS, AUTH_COOLDOWN_MS, ACTION_TIMEOUT_MS, SLOW_PULT_ACTIONS, UNCERTAIN_STATUS, KELLER_GESPERRT_TEXT } = await loadModule('src/lib/workersApi.js')
|
||||
const { actionErrorText, UNCERTAIN_TEXT } = await loadModule('src/lib/workersPult.js')
|
||||
const { createJwtCache } = await loadModule('src/lib/serverpulsAuth.js')
|
||||
|
||||
@@ -36,7 +36,7 @@ const okReplies = (n) => Array.from({ length: n }, () => ({ status: 200, body: {
|
||||
|
||||
test('URLs, Methoden, Header, Body', async () => {
|
||||
const f = fakeFetch(okReplies(12))
|
||||
const api = createWorkersApi({ getJwt, fetchImpl: f })
|
||||
const api = createWorkersApi({ getJwt, fetchImpl: f, stufe: 6 }) // Stufe 6: der Keller (botleads) ist offen; darunter ruft der Client /botleads nie ab (hustlerStufe.test.mjs)
|
||||
await api.state()
|
||||
await api.events('2026-10-17T20:00:00.000+00:00')
|
||||
await api.events(null, 500)
|
||||
@@ -706,3 +706,27 @@ test('createJWT: Übertragungsfehler beim frischen JWT nach einer 401 sperrt nic
|
||||
assert.deepEqual(await api.state(), { ok: 1 }) // 401 mit dem gespeicherten JWT, die Wiederholung mit frischem JWT darf wieder erfolgen und klappt
|
||||
assert.deepEqual(mints, [false, true, false, true]) // keine Sperre: weder für frische JWTs noch für createJWT überhaupt
|
||||
})
|
||||
|
||||
// ---------- Stufen-Sperre (hustlerStufe.js): kein Abruf des Kellers unterhalb von Stufe 6 ----------
|
||||
|
||||
|
||||
test('API: auf Stufe 3 geht kein Abruf von /api/workers/botleads hinaus (auch kein JWT), auf Stufe 6 wie bisher', async () => {
|
||||
for (const s of [1, 3, 5]) {
|
||||
const f = fakeFetch(okReplies(8)); let jwtGeholt = 0
|
||||
const api = createWorkersApi({ getJwt: async () => { jwtGeholt += 1; return 'jwt' }, fetchImpl: f, stufe: s })
|
||||
for (const params of [undefined, {}, { room: 'handwerk' }, { q: 'Bäcker', page: 2 }, { id: 'abc' }]) {
|
||||
await assert.rejects(api.botleads(params), (err) => err.status === 404 && err.message === KELLER_GESPERRT_TEXT, `Stufe ${s}`)
|
||||
}
|
||||
assert.equal(f.calls.length, 0, `Stufe ${s}`); assert.equal(jwtGeholt, 0, `Stufe ${s}`)
|
||||
// die übrigen Abrufe der Stufe 3 laufen
|
||||
await api.state(); await api.pult(); await api.pultAction('p1', 'claim'); await api.prospect('p1')
|
||||
assert.deepEqual(f.calls.map((c) => c.url), ['/api/workers/state', '/api/workers/pult?status=offen', '/api/workers/pult/p1/claim', '/api/workers/prospect/p1'])
|
||||
}
|
||||
for (const s of [6, 9]) {
|
||||
const f = fakeFetch(okReplies(1))
|
||||
const api = createWorkersApi({ getJwt: async () => 'jwt', fetchImpl: f, stufe: s })
|
||||
await api.botleads({ room: 'handwerk', page: 2 })
|
||||
assert.deepEqual(f.calls.map((c) => [c.init.method || 'GET', c.url]), [['GET', '/api/workers/botleads?room=handwerk&page=2']])
|
||||
}
|
||||
assert.match(KELLER_GESPERRT_TEXT, /Keller/)
|
||||
})
|
||||
@@ -19,7 +19,7 @@ test('WorkersPage: Tab-Titel Hustler, drei Bildschirme in fester Reihenfolge, ke
|
||||
assert.match(s, /id: 'hochhaus', label: 'Hochhaus'/); assert.match(s, /id: 'freigabe', label: 'Freigabe'/); assert.match(s, /id: 'botleads', label: 'Bot-Leads'/)
|
||||
assert.ok(s.indexOf("id: 'hochhaus'") < s.indexOf("id: 'freigabe'") && s.indexOf("id: 'freigabe'") < s.indexOf("id: 'botleads'"))
|
||||
assert.doesNotMatch(s, /title="Hustler"/); assert.doesNotMatch(s, /PageHeader/); assert.doesNotMatch(s, /<Tabs\b/); assert.doesNotMatch(s, /WORKERS_TABS\.length > 1/)
|
||||
assert.match(s, /const api = workersApi/); assert.match(s, /pickTab\(WORKERS_TABS, params\.get\('tab'\)\)/); assert.match(s, /useAuth\(\)/)
|
||||
assert.match(s, /const api = workersApi/); assert.match(s, /pickTab\(WORKERS_TABS\.filter\(\(t\) => tabErlaubt\(t\.id, stufe\)\), params\.get\('tab'\)\)/) // Stufen-Sperre: der Keller ist nur ab Stufe 6 ein Bildschirm (hustlerStufe.test.mjs); assert.match(s, /useAuth\(\)/)
|
||||
assert.match(s, /<Hochhaus[^>]*\bapi=\{api\}/); assert.match(s, /<Hochhaus[^>]*isAdmin=\{isAdmin\}/)
|
||||
assert.match(s, /<div className="hk-seite" data-tab=\{active\.id\}>/) // Vollhöhen-Rahmen, data-tab schaltet den Übergang für Pult und Keller
|
||||
assert.match(s, /import Hochhaus from '\.\.\/components\/workers\/hochhaus\/Hochhaus'/)
|
||||
@@ -40,7 +40,7 @@ test('WorkersPage: freigabe zeigt die PultList, botleads die BotLeadList (api, b
|
||||
assert.match(s, /active\.id === 'freigabe' && \([\s\S]*?<PultList[^>]*\bapi=\{api\}/); assert.match(s, /<PultList[^>]*me=\{\{ id: user\?\.\$id, name: user\?\.name \}\}/)
|
||||
assert.match(s, /active\.id === 'botleads' && \([\s\S]*?<BotLeadList[^>]*\bapi=\{api\}/)
|
||||
assert.match(s, /params\.get\('bot'\)/); assert.match(s, /<BotLeadList[^>]*\bbot=\{bot\}/); assert.match(s, /<BotLeadList[^>]*onClearBot=\{\(\) => setParams\(\{ tab: 'botleads' \}\)\}/)
|
||||
assert.match(s, /onOpen=\{\(tab\) => setParams\(\{ tab \}\)\}/) // setParams ersetzt alle Parameter: bot fällt beim Wechsel weg
|
||||
assert.match(s, /onOpen=\{\(tab\) => \{ if \(tabErlaubt\(tab, stufe\)\) setParams\(\{ tab \}\) \}\}/) // setParams ersetzt alle Parameter: bot fällt beim Wechsel weg; ein gesperrter Bildschirm öffnet sich nie
|
||||
assert.equal(s.match(/onBack=\{\(\) => setParams\(\{ tab: 'hochhaus' \}\)\}/g).length, 2) // „◂ Hochhaus“ in Pult und Keller
|
||||
for (const name of ['PultList', 'BotLeadList']) assert.match(s, new RegExp(`<${name}[\\s\\S]*?kpis=\\{state\\?\\.kpis\\}[\\s\\S]*?workers=\\{workers\\}[\\s\\S]*?paused=\\{paused\\}[\\s\\S]*?/>`)) // Pause (R3) geht an Pult und Keller
|
||||
assert.match(s, /const paused = state\?\.paused === true/)
|
||||
|
||||
Reference in new issue
Block a user