diff --git a/react/src/hooks/useIntervalValue.test.tsx b/react/src/hooks/useIntervalValue.test.tsx
new file mode 100644
index 0000000000..f9bb8ff342
--- /dev/null
+++ b/react/src/hooks/useIntervalValue.test.tsx
@@ -0,0 +1,207 @@
+import { useInterval, useIntervalValue } from './useIntervalValue';
+import { render, screen, act } from '@testing-library/react';
+import React from 'react';
+
+// Test component for useInterval
+const TestIntervalComponent: React.FC<{
+  delay: number | null;
+  pauseWhenHidden?: boolean;
+}> = ({ delay, pauseWhenHidden = true }) => {
+  const [count, setCount] = React.useState(0);
+
+  useInterval(
+    () => {
+      setCount((prev) => prev + 1);
+    },
+    delay,
+    pauseWhenHidden,
+  );
+
+  return 
{count}
;
+};
+
+// Test component for useIntervalValue
+const TestIntervalValueComponent: React.FC<{
+  delay: number | null;
+  pauseWhenHidden?: boolean;
+}> = ({ delay, pauseWhenHidden = true }) => {
+  const value = useIntervalValue(
+    () => Date.now(),
+    delay,
+    undefined,
+    pauseWhenHidden,
+  );
+
+  return {value}
;
+};
+
+describe('useInterval and useIntervalValue hooks', () => {
+  beforeEach(() => {
+    jest.useFakeTimers();
+    // Mock document.hidden as false initially (page is visible)
+    Object.defineProperty(document, 'hidden', {
+      writable: true,
+      value: false,
+    });
+  });
+
+  afterEach(() => {
+    jest.useRealTimers();
+  });
+
+  describe('useInterval', () => {
+    it('should increment count at specified interval', () => {
+      render();
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+
+      act(() => {
+        jest.advanceTimersByTime(1000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('1');
+
+      act(() => {
+        jest.advanceTimersByTime(2000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('3');
+    });
+
+    it('should pause when pauseWhenHidden is true and page becomes hidden', () => {
+      render();
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+
+      // Page becomes hidden
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: true });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      // Timer should not increment
+      act(() => {
+        jest.advanceTimersByTime(2000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+
+      // Page becomes visible again
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: false });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      // Should execute immediately when visible again
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('1');
+
+      // Continue normal interval
+      act(() => {
+        jest.advanceTimersByTime(1000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('2');
+    });
+
+    it('should continue running when pauseWhenHidden is false and page becomes hidden', () => {
+      render();
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+
+      // Page becomes hidden
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: true });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      // Timer should continue to increment even when hidden
+      act(() => {
+        jest.advanceTimersByTime(2000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('2');
+    });
+
+    it('should not run when delay is null', () => {
+      render();
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+
+      act(() => {
+        jest.advanceTimersByTime(5000);
+      });
+
+      expect(screen.getByTestId('interval-count')).toHaveTextContent('0');
+    });
+  });
+
+  describe('useIntervalValue', () => {
+    it('should update value at specified interval', () => {
+      render();
+
+      const initialValue = screen.getByTestId('interval-value').textContent;
+
+      act(() => {
+        jest.advanceTimersByTime(1000);
+      });
+
+      const updatedValue = screen.getByTestId('interval-value').textContent;
+      expect(updatedValue).not.toBe(initialValue);
+    });
+
+    it('should pause value updates when page becomes hidden and pauseWhenHidden is true', () => {
+      render(
+        ,
+      );
+
+      const initialValue = screen.getByTestId('interval-value').textContent;
+
+      // Page becomes hidden
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: true });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      act(() => {
+        jest.advanceTimersByTime(2000);
+      });
+
+      // Value should not change when hidden
+      expect(screen.getByTestId('interval-value')).toHaveTextContent(
+        initialValue!,
+      );
+
+      // Page becomes visible again
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: false });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      // Value should update immediately when visible again
+      const newValue = screen.getByTestId('interval-value').textContent;
+      expect(newValue).not.toBe(initialValue);
+    });
+
+    it('should continue updating when pauseWhenHidden is false and page becomes hidden', () => {
+      render(
+        ,
+      );
+
+      const initialValue = screen.getByTestId('interval-value').textContent;
+
+      // Page becomes hidden
+      act(() => {
+        Object.defineProperty(document, 'hidden', { value: true });
+        document.dispatchEvent(new Event('visibilitychange'));
+      });
+
+      act(() => {
+        jest.advanceTimersByTime(1000);
+      });
+
+      // Value should continue to update even when hidden
+      const updatedValue = screen.getByTestId('interval-value').textContent;
+      expect(updatedValue).not.toBe(initialValue);
+    });
+  });
+});