/** * Gauge Update Behavior Tests * Tests for how gauge responds to prop updates (renderChart vs initChart paths) */ describe('Gauge Update Behavior', () => { describe('renderChart Path (no full reinit)', () => { /** * Simulates the shouldRenderChart logic - returns true when props should be handled * by renderChart instead of initChart (avoiding gauge reset) */ const shouldUseRenderChart = (prev: any, curr: any): { shouldRender: boolean; changes: string[] } => { const changes: string[] = []; // Value changes go through renderChart if (prev.value !== curr.value) { changes.push('valueChanged'); } // Pointer props (except hide) go through renderChart const pointerPropsToCheck = ['type', 'color', 'length', 'width', 'strokeWidth', 'strokeColor']; pointerPropsToCheck.forEach(prop => { if (prev.pointer?.[prop] !== curr.pointer?.[prop]) { changes.push(`pointer.${prop}Changed`); } }); // Multi-pointer value and prop changes go through renderChart if (Array.isArray(prev.pointers) && Array.isArray(curr.pointers)) { const valuesChanged = curr.pointers.some((p: any, i: number) => p.value !== prev.pointers[i]?.value ); if (valuesChanged) { changes.push('multiPointerValuesChanged'); } const propsChanged = curr.pointers.some((p: any, i: number) => { const prevP = prev.pointers[i]; if (!prevP) return false; return p.type !== prevP.type || p.color !== prevP.color; }); if (propsChanged) { changes.push('multiPointerPropsChanged'); } } return { shouldRender: changes.length > 0, changes }; }; it('should use renderChart for value changes', () => { const prev = { value: 50 }; const curr = { value: 75 }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('valueChanged'); }); it('should use renderChart for pointer type changes', () => { const prev = { pointer: { type: 'needle' } }; const curr = { pointer: { type: 'blob' } }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('pointer.typeChanged'); }); it('should use renderChart for pointer color changes', () => { const prev = { pointer: { color: '#464A4F' } }; const curr = { pointer: { color: '#ff0000' } }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('pointer.colorChanged'); }); it('should use renderChart for pointer length changes', () => { const prev = { pointer: { length: 0.8 } }; const curr = { pointer: { length: 0.6 } }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('pointer.lengthChanged'); }); it('should use renderChart for multi-pointer value changes', () => { const prev = { pointers: [{ value: 30 }, { value: 60 }] }; const curr = { pointers: [{ value: 40 }, { value: 70 }] }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('multiPointerValuesChanged'); }); it('should use renderChart for multi-pointer prop changes', () => { const prev = { pointers: [{ value: 30, type: 'needle' }] }; const curr = { pointers: [{ value: 30, type: 'blob' }] }; const { shouldRender, changes } = shouldUseRenderChart(prev, curr); expect(shouldRender).toBe(true); expect(changes).toContain('multiPointerPropsChanged'); }); }); describe('Animation Flag Preservation', () => { it('should preserve animation progress when using renderChart path', () => { // Simulates that renderChart doesn't reset animation flags const initialAnimationTriggered = { current: true }; const animationInProgress = { current: false }; // After renderChart (not initChart), flags should be preserved // initChart would reset these to false expect(initialAnimationTriggered.current).toBe(true); }); it('should allow animation to continue from current position', () => { const lastRenderedProgress = 0.6; const targetProgress = 0.8; // Animation should interpolate from current to target const animationStartPercent = lastRenderedProgress; expect(animationStartPercent).toBe(0.6); expect(targetProgress - animationStartPercent).toBeCloseTo(0.2); }); }); describe('Slider Real-time Updates', () => { it('should detect value change immediately', () => { const prevValue = 50 as number; const currValue = 51 as number; // Small change from slider drag const valueChanged = prevValue !== currValue; expect(valueChanged).toBe(true); }); it('should not require full reinit for slider updates', () => { const prev = { value: 50 as number, pointer: { type: 'needle' as string } }; const curr = { value: 51 as number, pointer: { type: 'needle' as string } }; // Only value changed, pointer is same const onlyValueChanged = prev.value !== curr.value && prev.pointer.type === curr.pointer.type; expect(onlyValueChanged).toBe(true); }); }); });