dryingPresets.test.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /**
  2. * The drying popover has to name a material the printer will recognise.
  3. *
  4. * It seeds two things from one lookup: the temperature it prefills, and the
  5. * filament name the start command carries. The dropdown rendering that name
  6. * falls back to its first option when the value isn't in its list -- silently
  7. * -- so a lookup that can return something outside the table shows one material
  8. * and sends another. An AMS-HT holding Support for PLA/PETG displayed PLA and
  9. * told the printer PLA-S (#2774). These tests pin the invariant that closes
  10. * that: whatever comes back is a key the table has.
  11. */
  12. import { describe, it, expect } from 'vitest';
  13. import { resolveDryingPresetKey, type DryingPreset } from '../../utils/dryingPresets';
  14. // The shipped table, as PrintersPage.tsx defines it.
  15. const PRESETS: Record<string, DryingPreset> = {
  16. 'PLA': { n3f: 45, n3s: 45, n3f_hours: 12, n3s_hours: 12 },
  17. 'PETG': { n3f: 65, n3s: 65, n3f_hours: 12, n3s_hours: 12 },
  18. 'TPU': { n3f: 65, n3s: 75, n3f_hours: 12, n3s_hours: 18 },
  19. 'ABS': { n3f: 65, n3s: 80, n3f_hours: 12, n3s_hours: 8 },
  20. 'ASA': { n3f: 65, n3s: 80, n3f_hours: 12, n3s_hours: 8 },
  21. 'PA': { n3f: 65, n3s: 85, n3f_hours: 12, n3s_hours: 12 },
  22. 'PC': { n3f: 65, n3s: 80, n3f_hours: 12, n3s_hours: 8 },
  23. 'PVA': { n3f: 65, n3s: 85, n3f_hours: 12, n3s_hours: 18 },
  24. };
  25. describe('resolveDryingPresetKey', () => {
  26. it('always answers with a key the table has', () => {
  27. // The invariant behind #2774. Anything outside the table reaches the
  28. // dropdown as a value it will not display and the printer as a material
  29. // the user never chose.
  30. const trayTypes = [
  31. 'PLA', 'PETG', 'ABS', 'ASA', 'TPU', 'PA', 'PC', 'PVA',
  32. 'PLA-S', 'PLA-CF', 'PETG-CF', 'PET-CF', 'ABS-GF', 'ASA-CF', 'PAHT-CF',
  33. 'PA6-CF', 'PPS-CF', 'PPA-CF', 'HIPS', 'PP', 'PE', 'EVA', 'PHA', 'PCTG',
  34. 'Nylon', 'TPU for AMS', '', ' ', 'wildly unknown',
  35. ];
  36. for (const trayType of trayTypes) {
  37. expect(PRESETS).toHaveProperty(resolveDryingPresetKey(trayType, PRESETS));
  38. }
  39. });
  40. it('passes a listed material straight through', () => {
  41. expect(resolveDryingPresetKey('PETG', PRESETS)).toBe('PETG');
  42. expect(resolveDryingPresetKey('PVA', PRESETS)).toBe('PVA');
  43. });
  44. it('is case-insensitive and ignores a trailing qualifier', () => {
  45. expect(resolveDryingPresetKey('petg', PRESETS)).toBe('PETG');
  46. expect(resolveDryingPresetKey('TPU for AMS', PRESETS)).toBe('TPU');
  47. });
  48. it('dries a support material as its base', () => {
  49. // Support for PLA/PETG reports as PLA-S -- the case from the report.
  50. expect(resolveDryingPresetKey('PLA-S', PRESETS)).toBe('PLA');
  51. });
  52. it('dries a composite as its base rather than defaulting to PLA', () => {
  53. // The reason the suffix is stripped instead of just falling back: PETG-CF
  54. // wants PETG's 65 degrees, and landing on PLA's 45 would quietly waste the
  55. // cycle.
  56. expect(resolveDryingPresetKey('PETG-CF', PRESETS)).toBe('PETG');
  57. expect(resolveDryingPresetKey('PLA-CF', PRESETS)).toBe('PLA');
  58. expect(resolveDryingPresetKey('ABS-GF', PRESETS)).toBe('ABS');
  59. expect(resolveDryingPresetKey('ASA-CF', PRESETS)).toBe('ASA');
  60. });
  61. it('recognises the polyamide family under its own spellings', () => {
  62. // The grades have to be listed: "PA12" shares no prefix rule with "PA", so
  63. // dropping the suffix alone leaves it unrecognised. #3067 reported PA6 and
  64. // named PA11 and PA12 alongside it.
  65. expect(resolveDryingPresetKey('PA6-CF', PRESETS)).toBe('PA');
  66. expect(resolveDryingPresetKey('PA6-GF', PRESETS)).toBe('PA');
  67. expect(resolveDryingPresetKey('PA11-CF', PRESETS)).toBe('PA');
  68. expect(resolveDryingPresetKey('PA12-CF', PRESETS)).toBe('PA');
  69. expect(resolveDryingPresetKey('PAHT-CF', PRESETS)).toBe('PA');
  70. expect(resolveDryingPresetKey('Nylon', PRESETS)).toBe('PA');
  71. // Polyphthalamide is a distinct polymer rather than a nylon grade, so this
  72. // one is a judgement: an aromatic polyamide that takes up moisture the same
  73. // way, dried on the hottest row the table has.
  74. expect(resolveDryingPresetKey('PPA-CF', PRESETS)).toBe('PA');
  75. expect(resolveDryingPresetKey('PPA-GF', PRESETS)).toBe('PA');
  76. });
  77. it('falls back to the coolest row for an unknown material', () => {
  78. // Under-drying an exotic filament wastes a cycle; PA's 85 degrees would
  79. // deform a PLA spool. So an unrecognised material must never inherit a
  80. // hotter row than PLA's.
  81. for (const unknown of ['PPS-CF', 'PEEK', 'wildly unknown']) {
  82. expect(resolveDryingPresetKey(unknown, PRESETS)).toBe('PLA');
  83. }
  84. });
  85. it('handles an empty tray', () => {
  86. // No spool loaded -- the popover still has to open on something.
  87. expect(resolveDryingPresetKey(undefined, PRESETS)).toBe('PLA');
  88. expect(resolveDryingPresetKey(null, PRESETS)).toBe('PLA');
  89. expect(resolveDryingPresetKey('', PRESETS)).toBe('PLA');
  90. });
  91. it('respects a custom preset table', () => {
  92. // Users can override the table from settings, so the lookup answers about
  93. // the table it was handed, not the shipped one.
  94. const custom = { ...PRESETS, 'PLA-S': { n3f: 55, n3s: 55, n3f_hours: 8, n3s_hours: 8 } };
  95. expect(resolveDryingPresetKey('PLA-S', custom)).toBe('PLA-S');
  96. });
  97. });