SpoolBuddyAmsPageLogic.test.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * Tests for SpoolBuddy AMS page logic:
  3. * - External slot active state (tray_now=255 bug fix)
  4. * - Fill level override fallback chain (inventory → AMS remain)
  5. *
  6. * These mirror inline logic from SpoolBuddyAmsPage.tsx, extracted for testability.
  7. */
  8. import { describe, it, expect } from 'vitest';
  9. /**
  10. * Mirrors the ext slot isExtActive calculation from SpoolBuddyAmsPage.tsx.
  11. * tray_now=255 means "no tray loaded" (idle) — should never mark any slot active.
  12. */
  13. function computeExtActive(
  14. trayNow: number,
  15. isDualNozzle: boolean,
  16. extTrayId: number,
  17. activeExtruder: number | undefined,
  18. ): boolean {
  19. return trayNow === 255 ? false
  20. : isDualNozzle && trayNow === 254
  21. ? (extTrayId === 254 && activeExtruder === 1) ||
  22. (extTrayId === 255 && activeExtruder === 0)
  23. : trayNow === extTrayId;
  24. }
  25. /**
  26. * Mirrors the effective fill fallback from SpoolBuddyAmsPage.tsx and AmsUnitCard.tsx.
  27. * Priority: inventory fill override → AMS remain (if >= 0)
  28. */
  29. function computeEffectiveFill(
  30. fillOverride: number | null,
  31. amsRemain: number | null | undefined,
  32. ): number | null {
  33. const amsFill = amsRemain != null && amsRemain >= 0 ? amsRemain : null;
  34. return fillOverride ?? amsFill;
  35. }
  36. describe('ext slot active state', () => {
  37. describe('tray_now=255 (idle) — no slot should be active', () => {
  38. it('single-nozzle: ext (id=254) not active when tray_now=255', () => {
  39. expect(computeExtActive(255, false, 254, undefined)).toBe(false);
  40. });
  41. it('dual-nozzle: ext-L (id=254) not active when tray_now=255', () => {
  42. expect(computeExtActive(255, true, 254, 1)).toBe(false);
  43. });
  44. it('dual-nozzle: ext-R (id=255) not active when tray_now=255', () => {
  45. // This was the bug: trayNow(255) === extTrayId(255) without the guard
  46. expect(computeExtActive(255, true, 255, 0)).toBe(false);
  47. });
  48. });
  49. describe('tray_now=254 on dual-nozzle — uses active_extruder', () => {
  50. it('ext-L active when active_extruder=1 (left)', () => {
  51. expect(computeExtActive(254, true, 254, 1)).toBe(true);
  52. });
  53. it('ext-R active when active_extruder=0 (right)', () => {
  54. expect(computeExtActive(254, true, 255, 0)).toBe(true);
  55. });
  56. it('ext-L not active when active_extruder=0 (right)', () => {
  57. expect(computeExtActive(254, true, 254, 0)).toBe(false);
  58. });
  59. it('ext-R not active when active_extruder=1 (left)', () => {
  60. expect(computeExtActive(254, true, 255, 1)).toBe(false);
  61. });
  62. });
  63. describe('tray_now=254 on single-nozzle — direct ID match', () => {
  64. it('ext (id=254) active when tray_now=254', () => {
  65. expect(computeExtActive(254, false, 254, undefined)).toBe(true);
  66. });
  67. });
  68. describe('AMS tray active — ext slots not active', () => {
  69. it('ext not active when AMS slot is active (tray_now=5)', () => {
  70. expect(computeExtActive(5, false, 254, undefined)).toBe(false);
  71. });
  72. });
  73. });
  74. describe('fill level override fallback', () => {
  75. it('uses inventory fill when available, ignoring AMS remain', () => {
  76. expect(computeEffectiveFill(75, 50)).toBe(75);
  77. });
  78. it('falls back to AMS remain when no inventory fill', () => {
  79. expect(computeEffectiveFill(null, 50)).toBe(50);
  80. });
  81. it('returns null when neither source available', () => {
  82. expect(computeEffectiveFill(null, null)).toBeNull();
  83. });
  84. it('returns null when AMS remain is -1 (unknown) and no inventory fill', () => {
  85. expect(computeEffectiveFill(null, -1)).toBeNull();
  86. });
  87. it('uses inventory fill even when AMS remain is -1', () => {
  88. expect(computeEffectiveFill(80, -1)).toBe(80);
  89. });
  90. it('uses AMS remain of 0 (empty) as valid fill', () => {
  91. expect(computeEffectiveFill(null, 0)).toBe(0);
  92. });
  93. it('uses inventory fill of 0 over AMS remain', () => {
  94. expect(computeEffectiveFill(0, 50)).toBe(0);
  95. });
  96. });