Files
tickte-system/tests/unit/workersRooms.test.mjs
T

241 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test'
import assert from 'node:assert/strict'
import { loadModule } from './load.mjs'
import { makeCtx } from './helpers/fakeCtx.mjs'
// Räume nach kind, Pokal-Seiten, graue Räume und Gebäudehülle (Quelle: entwuerfe/scene-turm.js Z. 99-314)
const R = await loadModule('src/components/workers/engine/rooms.js')
const B = await loadModule('src/components/workers/engine/building.js')
const { buildLayout, ROOM_META } = await loadModule('src/components/workers/engine/layout.js')
const { PAL, TEAM } = await loadModule('src/components/workers/engine/sprites.js')
const { FLOOR_TITLES, ROOM_TITLES } = await loadModule('src/lib/workersRoster.js')
const layout = buildLayout()
const draw = (look, t = 1) => {
const m = makeCtx()
R.drawRooms(m.ctx, layout, t, look)
return m
}
const SIGN = 'noch nicht angeschlossen'
const looks = (patch = {}) => Object.assign(R.createLook(), patch)
const count = (rects, fill) => rects.filter((r) => r.fill === fill).length
// Pokale sind die 7 × 3 großen Goldflächen (k = 3: 21 × 9 Geräte-Pixel)
const trophies = (look) => draw(look).rects.filter((r) => r.fill === PAL.gold && r.w === 21 && r.h === 9).length
test('trophyPaging: 8 je Seite, Seite wird geklemmt', () => {
assert.deepEqual(R.trophyPaging(0, 0), { shown: 0, page: 0, pages: 1, from: 0 })
assert.deepEqual(R.trophyPaging(8, 0), { shown: 8, page: 0, pages: 1, from: 0 })
assert.deepEqual(R.trophyPaging(9, 1), { shown: 1, page: 1, pages: 2, from: 8 })
assert.deepEqual(R.trophyPaging(9, 5), { shown: 1, page: 1, pages: 2, from: 8 })
assert.deepEqual(R.trophyPaging(25, -1), { shown: 8, page: 0, pages: 4, from: 0 })
})
test('alle 21 Räume zeichnen, jeder Titel erscheint', () => {
const { texts, rects } = draw(R.createLook())
assert.ok(rects.length > 300)
for (const title of Object.values(ROOM_TITLES)) assert.ok(texts.some((x) => x.text === title), title)
})
test('graue Räume tragen das Schild, sonst keins (Review Focus 4)', () => {
const look = R.createLook()
look.greyRooms = new Set(['kleinanzeigen', 'portale'])
assert.equal(draw(look).texts.filter((x) => x.text === SIGN).length, 2)
assert.equal(draw(R.createLook()).texts.filter((x) => x.text === SIGN).length, 0)
})
test('Pult-Zahl, Pokal- und Bot-Lead-Zähler', () => {
const look = R.createLook()
look.pultOpen = 7
look.dealsMonth = 9
look.botLeads = 112
const t = draw(look).texts.map((x) => x.text)
assert.ok(t.includes('7'))
assert.ok(t.includes('9 Deals'))
assert.ok(t.includes('112 Bot-Leads'))
assert.ok(!draw(R.createLook()).texts.some((x) => x.text === '7'))
})
test('Gebäude: Etagenschilder, Lampen, Pausenschleier', () => {
const m = makeCtx()
B.drawTower(m.ctx, layout, 1, { at: (i) => i === 3 })
for (const title of Object.values(FLOOR_TITLES)) assert.ok(m.texts.some((x) => x.text === title), title)
const on = makeCtx()
const look = R.createLook()
look.paused = true
B.drawPauseVeil(on.ctx, look)
assert.ok(on.texts.some((x) => x.text === 'Pausiert'))
const off = makeCtx()
B.drawPauseVeil(off.ctx, R.createLook())
assert.equal(off.texts.length, 0)
B.drawOutside(makeCtx().ctx)
})
// ---- Ergänzungen: Verhalten, das die fünf Tests oben nicht berühren ----
test('createLook: Ausgangszustand ohne gemeinsame Mengen zwischen zwei Aufrufen', () => {
const a = R.createLook()
const b = R.createLook()
assert.ok(a.greyRooms instanceof Set && a.busyRooms instanceof Set)
assert.equal(a.greyRooms.size + a.busyRooms.size, 0)
assert.deepEqual({ ...a, greyRooms: 0, busyRooms: 0 }, { greyRooms: 0, busyRooms: 0, pultOpen: 0, dealsMonth: 0, botLeads: 0, trophyPage: 0, pageT: 0, trophyPop: 0, vaultFlash: 0, paused: false })
a.busyRooms.add('netz')
assert.equal(b.busyRooms.size, 0)
})
test('ROOM_DRAWERS: eine Zeichnung für jede Raumart des Layouts, eingefroren', () => {
const kinds = new Set(Object.values(ROOM_META).map((m) => m.kind))
assert.equal(kinds.size, 16)
for (const kind of kinds) assert.equal(typeof R.ROOM_DRAWERS[kind], 'function', kind)
assert.ok(Object.isFrozen(R.ROOM_DRAWERS))
})
test('jeder Raum zeichnet sichtbaren Inhalt über Tint und Titel hinaus (kein leerer Raum)', () => {
// Rechtecke je Raum zählen: Raum für Raum in ein eigenes Layout mit nur dieser Etage
for (const floor of layout.floors) {
for (const room of floor.rooms) {
const single = { ...layout, floors: [{ ...floor, rooms: [room] }] }
const m = makeCtx()
R.drawRooms(m.ctx, single, 1, R.createLook())
assert.ok(m.rects.length >= 5, room.id)
}
}
})
test('trophyPaging: ungültige Werte fallen auf eine leere erste Seite zurück', () => {
const empty = { shown: 0, page: 0, pages: 1, from: 0 }
assert.deepEqual(R.trophyPaging(NaN, NaN), empty)
assert.deepEqual(R.trophyPaging(undefined, undefined), empty)
assert.deepEqual(R.trophyPaging(-4, 2), empty)
assert.deepEqual(R.trophyPaging(16, 1), { shown: 8, page: 1, pages: 2, from: 8 })
assert.deepEqual(R.trophyPaging(5, 0, 2), { shown: 2, page: 0, pages: 3, from: 0 })
})
test('Pokalbrett zeigt die gewählte Seite; der neueste Pokal blinkt bei trophyPop', () => {
assert.equal(trophies(looks()), 0)
assert.equal(trophies(looks({ dealsMonth: 3 })), 3)
assert.equal(trophies(looks({ dealsMonth: 20 })), 8)
assert.equal(trophies(looks({ dealsMonth: 9, trophyPage: 1 })), 1)
assert.equal(trophies(looks({ dealsMonth: 9, trophyPage: 7 })), 1)
// floor(0.25 * 10) = 2 -> gerade: sichtbar; floor(0.15 * 10) = 1 -> ungerade: der neueste Pokal fehlt
assert.equal(trophies(looks({ dealsMonth: 3, trophyPop: 0.25 })), 3)
assert.equal(trophies(looks({ dealsMonth: 3, trophyPop: 0.15 })), 2)
})
test('Tresor blitzt Gold bei vaultFlash, sonst nicht', () => {
const gold = (look) => draw(look).alphas.filter((a) => a > 0.1).length
assert.ok(gold(looks({ vaultFlash: 0.7 })) > gold(looks()))
})
test('Pult-Zahl: 0 zeigt keine Zahl, ab 100 steht 99+', () => {
const nums = (n) => draw(looks({ pultOpen: n })).texts.map((x) => x.text).filter((x) => /^\d+\+?$/.test(x))
assert.deepEqual(nums(0), [])
assert.deepEqual(nums(120), ['99+'])
assert.deepEqual(nums(99), ['99'])
})
test('Zähler zeigen immer ihre Zahl, auch 0', () => {
const t = draw(R.createLook()).texts.map((x) => x.text)
assert.ok(t.includes('0 Deals'))
assert.ok(t.includes('0 Bot-Leads'))
})
test('Monitore laufen nur in Räumen aus busyRooms', () => {
const lines = (look) => count(draw(look).rects, TEAM.aerzte)
const idle = lines(looks())
const busy = lines(looks({ busyRooms: new Set(['aerzte']) }))
assert.ok(busy > idle)
// ein anderer Raum arbeitet: Ärzte & Praxen bleibt dunkel
assert.equal(lines(looks({ busyRooms: new Set(['handwerk']) })), idle)
})
test('graue Räume: Monitor aus trotz busyRooms, pult und tresor werden nie grau', () => {
const lines = (look) => count(draw(look).rects, TEAM.aerzte)
const grey = looks({ greyRooms: new Set(['aerzte']), busyRooms: new Set(['aerzte']) })
const greyIdle = looks({ greyRooms: new Set(['aerzte']) })
assert.equal(lines(grey), lines(greyIdle))
const never = looks({ greyRooms: new Set(['pult', 'tresor', 'gibt-es-nicht']) })
assert.equal(draw(never).texts.filter((x) => x.text === SIGN).length, 0)
})
test('Schild steht innerhalb des grauen Raums und in der Etage seiner Figur', () => {
const look = looks({ greyRooms: new Set(['kleinanzeigen']) })
const m = draw(look)
const sign = m.texts.find((x) => x.text === SIGN)
const floor = layout.floors.find((f) => f.id === 'anfragen')
const room = floor.rooms.find((r) => r.id === 'kleinanzeigen')
// Mitte des Raums (k = 3, align center), Zeile innerhalb der Etage
assert.equal(sign.x, Math.round((room.x + room.w / 2) * 3))
assert.ok(sign.y >= floor.top * 3 && sign.y < floor.floorY * 3)
})
test('unbekannte Raumart zeichnet nur Titel und Tint, ohne Wurf', () => {
const odd = { ...layout, floors: layout.floors.map((f) => ({ ...f, rooms: f.rooms.map((r) => ({ ...r, kind: 'gibt-es-nicht' })) })) }
const m = makeCtx()
assert.doesNotThrow(() => R.drawRooms(m.ctx, odd, 1, R.createLook()))
assert.ok(m.texts.some((x) => x.text === ROOM_TITLES.netz))
})
test('drawRooms hält save/restore im Gleichgewicht', () => {
const m = draw(looks({ greyRooms: new Set(['netz']), pultOpen: 3, dealsMonth: 2 }))
assert.equal(m.counts.save, m.counts.restore)
})
test('Gebäude: Bodenlinie liegt auf dem Boden der Tresor-Etage (y 224)', () => {
const tresor = layout.floors.find((f) => f.id === 'tresor')
assert.equal(tresor.floorY, 224)
const m = makeCtx()
B.drawOutside(m.ctx)
// k = 3: volle Breite 960, eine logische Einheit hoch, auf y 672
assert.ok(m.rects.some((r) => r.x === 0 && r.y === 224 * 3 && r.w === 960 && r.h === 3))
// Erde unter der Bodenlinie, bis zum Weltrand
assert.ok(m.rects.some((r) => r.y === 225 * 3 && r.h === (256 - 225) * 3))
})
test('Gebäude: Lampe der Etage mit Kabine leuchtet grün, keine ohne Kabine', () => {
const green = (at) => {
const m = makeCtx()
B.drawTower(m.ctx, layout, 1, { at })
return count(m.rects, PAL.green)
}
const none = green(() => false)
assert.equal(green((i) => i === 3), none + 1)
assert.equal(green((i) => i === 0 || i === 9), none + 2)
})
test('Gebäude: Etagenschilder rechts außen bei x 234, in der Zeile ihrer Etage', () => {
const m = makeCtx()
B.drawTower(m.ctx, layout, 1, { at: () => false })
for (const floor of layout.floors) {
const sign = m.texts.find((x) => x.text === floor.title)
assert.equal(sign.x, 234 * 3, floor.id)
assert.ok(sign.y >= floor.top * 3 && sign.y < floor.floorY * 3, floor.id)
}
})
test('Gebäude: Hülle reicht bis zum Fundament der letzten Etage', () => {
const m = makeCtx()
B.drawTower(m.ctx, layout, 1, { at: () => false })
const last = layout.floors[layout.floors.length - 1]
const bottom = Math.max(...m.rects.map((r) => (r.y + r.h) / 3))
assert.equal(bottom, last.floorY + 2)
assert.ok(m.rects.every((r) => r.x >= 0 && (r.x + r.w) / 3 <= 320))
})
test('Pausenschleier: 45 % Weiß über der ganzen Welt, Aufrufe gleichen sich aus', () => {
const m = makeCtx()
B.drawPauseVeil(m.ctx, looks({ paused: true }))
assert.ok(m.alphas.includes(0.45))
const veil = m.rects.find((r) => r.fill === PAL.w)
assert.ok(veil.x <= 0 && veil.y <= 0 && veil.x + veil.w >= 960 && veil.y + veil.h >= 768)
assert.equal(m.counts.save, m.counts.restore)
const off = makeCtx()
B.drawPauseVeil(off.ctx, R.createLook())
assert.equal(off.rects.length, 0)
})
test('Gebäude: Layout ohne Etagen zeichnet nichts und wirft nicht', () => {
const m = makeCtx()
assert.doesNotThrow(() => B.drawTower(m.ctx, { floors: [], homes: {}, spots: {} }, 1, { at: () => false }))
assert.doesNotThrow(() => R.drawRooms(m.ctx, { floors: [], homes: {}, spots: {} }, 1, R.createLook()))
})