haSensorDisplay.test.ts 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /**
  2. * describeHASensorReading is the single formatter shared by the printer row
  3. * and both location-sensor display sites (InventoryPage, SettingsPage).
  4. * Before this, all three carried their own near-identical copy, and the
  5. * printer's copy (no decimals) had quietly drifted from the location copies
  6. * (fixed to two decimals, a deliberate width-alignment choice). Locking both
  7. * behaviors down here as the one place either could change.
  8. */
  9. import { describe, it, expect } from 'vitest';
  10. import { describeHASensorReading } from '../../utils/haSensorDisplay';
  11. const t = (key: string, opts?: Record<string, unknown>) =>
  12. (opts?.defaultValue as string | undefined) ?? key;
  13. describe('describeHASensorReading', () => {
  14. it('shows the raw value with no decimals option — the printer row behavior', () => {
  15. const reading = { kind: 'numeric' as const, value: 23.4, unit: '°C', state: '23.4', reachable: true, device_class: 'temperature' };
  16. expect(describeHASensorReading(reading, t)).toBe('23.4 °C');
  17. });
  18. it('pads to a fixed decimal count when asked — the location sensor behavior', () => {
  19. const reading = { kind: 'numeric' as const, value: 23.4, unit: '°C', state: '23.4', reachable: true, device_class: 'temperature' };
  20. expect(describeHASensorReading(reading, t, { decimals: 2 })).toBe('23.40 °C');
  21. });
  22. it('pads a whole-number value too, e.g. battery at 87%', () => {
  23. const reading = { kind: 'numeric' as const, value: 87, unit: '%', state: '87', reachable: true, device_class: 'battery' };
  24. expect(describeHASensorReading(reading, t, { decimals: 2 })).toBe('87.00 %');
  25. });
  26. it('omits the unit when the reading has none', () => {
  27. const reading = { kind: 'numeric' as const, value: 23.4, unit: null, state: '23.4', reachable: true, device_class: 'temperature' };
  28. expect(describeHASensorReading(reading, t)).toBe('23.4');
  29. });
  30. it('falls back to the raw state string when value is null', () => {
  31. const reading = { kind: 'numeric' as const, value: null, unit: '°C', state: 'unknown', reachable: true, device_class: 'temperature' };
  32. expect(describeHASensorReading(reading, t)).toBe('unknown');
  33. });
  34. it('shows unavailable text for an unreachable sensor, regardless of kind', () => {
  35. const reading = { kind: 'numeric' as const, value: 23.4, unit: '°C', state: '23.4', reachable: false, device_class: 'temperature' };
  36. expect(describeHASensorReading(reading, t)).toBe('haSensors.unavailable');
  37. });
  38. it('shows unavailable text when state is null even if marked reachable', () => {
  39. const reading = { kind: 'numeric' as const, value: null, unit: '°C', state: null, reachable: true, device_class: 'temperature' };
  40. expect(describeHASensorReading(reading, t)).toBe('haSensors.unavailable');
  41. });
  42. it('translates a binary reading through its device-class label', () => {
  43. const reading = { kind: 'binary' as const, value: null, unit: null, state: 'on', reachable: true, device_class: 'door' };
  44. expect(describeHASensorReading(reading, t)).toBe('open');
  45. });
  46. it('falls back to the raw on/off state for a binary reading with no known device class', () => {
  47. const reading = { kind: 'binary' as const, value: null, unit: null, state: 'on', reachable: true, device_class: 'unmapped_class' };
  48. expect(describeHASensorReading(reading, t)).toBe('on');
  49. });
  50. });