| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- /**
- * Tests for SpoolBuddy AMS page logic:
- * - External slot active state (tray_now=255 bug fix)
- * - Fill level override fallback chain (inventory → AMS remain)
- *
- * These mirror inline logic from SpoolBuddyAmsPage.tsx, extracted for testability.
- */
- import { describe, it, expect } from 'vitest';
- /**
- * Mirrors the ext slot isExtActive calculation from SpoolBuddyAmsPage.tsx.
- * tray_now=255 means "no tray loaded" (idle) — should never mark any slot active.
- */
- function computeExtActive(
- trayNow: number,
- isDualNozzle: boolean,
- extTrayId: number,
- activeExtruder: number | undefined,
- ): boolean {
- return trayNow === 255 ? false
- : isDualNozzle && trayNow === 254
- ? (extTrayId === 254 && activeExtruder === 1) ||
- (extTrayId === 255 && activeExtruder === 0)
- : trayNow === extTrayId;
- }
- /**
- * Mirrors the effective fill fallback from SpoolBuddyAmsPage.tsx and AmsUnitCard.tsx.
- * Priority: inventory fill override → AMS remain (if >= 0)
- */
- function computeEffectiveFill(
- fillOverride: number | null,
- amsRemain: number | null | undefined,
- ): number | null {
- const amsFill = amsRemain != null && amsRemain >= 0 ? amsRemain : null;
- return fillOverride ?? amsFill;
- }
- describe('ext slot active state', () => {
- describe('tray_now=255 (idle) — no slot should be active', () => {
- it('single-nozzle: ext (id=254) not active when tray_now=255', () => {
- expect(computeExtActive(255, false, 254, undefined)).toBe(false);
- });
- it('dual-nozzle: ext-L (id=254) not active when tray_now=255', () => {
- expect(computeExtActive(255, true, 254, 1)).toBe(false);
- });
- it('dual-nozzle: ext-R (id=255) not active when tray_now=255', () => {
- // This was the bug: trayNow(255) === extTrayId(255) without the guard
- expect(computeExtActive(255, true, 255, 0)).toBe(false);
- });
- });
- describe('tray_now=254 on dual-nozzle — uses active_extruder', () => {
- it('ext-L active when active_extruder=1 (left)', () => {
- expect(computeExtActive(254, true, 254, 1)).toBe(true);
- });
- it('ext-R active when active_extruder=0 (right)', () => {
- expect(computeExtActive(254, true, 255, 0)).toBe(true);
- });
- it('ext-L not active when active_extruder=0 (right)', () => {
- expect(computeExtActive(254, true, 254, 0)).toBe(false);
- });
- it('ext-R not active when active_extruder=1 (left)', () => {
- expect(computeExtActive(254, true, 255, 1)).toBe(false);
- });
- });
- describe('tray_now=254 on single-nozzle — direct ID match', () => {
- it('ext (id=254) active when tray_now=254', () => {
- expect(computeExtActive(254, false, 254, undefined)).toBe(true);
- });
- });
- describe('AMS tray active — ext slots not active', () => {
- it('ext not active when AMS slot is active (tray_now=5)', () => {
- expect(computeExtActive(5, false, 254, undefined)).toBe(false);
- });
- });
- });
- describe('fill level override fallback', () => {
- it('uses inventory fill when available, ignoring AMS remain', () => {
- expect(computeEffectiveFill(75, 50)).toBe(75);
- });
- it('falls back to AMS remain when no inventory fill', () => {
- expect(computeEffectiveFill(null, 50)).toBe(50);
- });
- it('returns null when neither source available', () => {
- expect(computeEffectiveFill(null, null)).toBeNull();
- });
- it('returns null when AMS remain is -1 (unknown) and no inventory fill', () => {
- expect(computeEffectiveFill(null, -1)).toBeNull();
- });
- it('uses inventory fill even when AMS remain is -1', () => {
- expect(computeEffectiveFill(80, -1)).toBe(80);
- });
- it('uses AMS remain of 0 (empty) as valid fill', () => {
- expect(computeEffectiveFill(null, 0)).toBe(0);
- });
- it('uses inventory fill of 0 over AMS remain', () => {
- expect(computeEffectiveFill(0, 50)).toBe(0);
- });
- });
|