diff --git a/src/ui/VirtualRenderers/useLeftScrollSync.test.tsx b/src/ui/VirtualRenderers/useLeftScrollSync.test.tsx
new file mode 100644
index 0000000000..737fa3ebe6
--- /dev/null
+++ b/src/ui/VirtualRenderers/useLeftScrollSync.test.tsx
@@ -0,0 +1,52 @@
+import { fireEvent, render, screen, waitFor } from '@testing-library/react'
+import { useRef } from 'react'
+
+import { useLeftScrollSync } from './useLeftScrollSync'
+
+const mockAddEventListener = vi.fn()
+
+const NullRefComponent = () => {
+ const ref = useRef(null)
+ useLeftScrollSync({
+ // @ts-expect-error - testing something
+ textAreaRef: { current: null, addEventListener: mockAddEventListener },
+ overlayRef: ref,
+ })
+ return
+}
+
+const TestComponent = () => {
+ const textAreaRef = useRef(null)
+ const overlayRef = useRef(null)
+ useLeftScrollSync({ textAreaRef, overlayRef })
+ return (
+
+ )
+}
+
+describe('useLeftScrollSync', () => {
+ describe('refs are null', () => {
+ it('early returns', () => {
+ render()
+
+ expect(mockAddEventListener).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('refs are set', () => {
+ it('syncs scroll left', async () => {
+ render()
+
+ const textArea = screen.getByTestId('text-area')
+ await fireEvent.scroll(textArea, {
+ target: { scrollLeft: 100 },
+ })
+
+ const overlay = screen.getByTestId('overlay')
+ await waitFor(() => expect(overlay.scrollLeft).toBe(100))
+ })
+ })
+})
diff --git a/src/ui/VirtualRenderers/useSyncScrollMargin.test.ts b/src/ui/VirtualRenderers/useSyncScrollMargin.test.ts
new file mode 100644
index 0000000000..406d3d8158
--- /dev/null
+++ b/src/ui/VirtualRenderers/useSyncScrollMargin.test.ts
@@ -0,0 +1,44 @@
+import { renderHook } from '@testing-library/react'
+
+import { useSyncScrollMargin } from './useSyncScrollMargin'
+
+class ResizeObserverMock {
+ callback = (x: any) => null
+
+ constructor(callback: any) {
+ this.callback = callback
+ }
+
+ observe() {
+ this.callback([{ target: { getBoundingClientRect: () => ({ top: 100 }) } }])
+ }
+ unobserve() {
+ // do nothing
+ }
+ disconnect() {
+ // do nothing
+ }
+}
+global.window.ResizeObserver = ResizeObserverMock
+
+describe('useSyncScrollMargin', () => {
+ describe('overlayRef is null', () => {
+ it('returns undefined', () => {
+ const { result } = renderHook(() =>
+ useSyncScrollMargin({ overlayRef: { current: null } })
+ )
+
+ expect(result.current).toBe(undefined)
+ })
+ })
+
+ describe('overlayRef is set', () => {
+ it('returns the scroll margin', () => {
+ const { result } = renderHook(() =>
+ useSyncScrollMargin({ overlayRef: { current: {} as HTMLDivElement } })
+ )
+
+ expect(result.current).toBe(100)
+ })
+ })
+})
diff --git a/src/ui/VirtualRenderers/useSyncWrapperWidth.test.ts b/src/ui/VirtualRenderers/useSyncWrapperWidth.test.ts
new file mode 100644
index 0000000000..4f4eff3067
--- /dev/null
+++ b/src/ui/VirtualRenderers/useSyncWrapperWidth.test.ts
@@ -0,0 +1,44 @@
+import { act, renderHook } from '@testing-library/react'
+
+import { useSyncWrapperWidth } from './useSyncWrapperWidth'
+
+class ResizeObserverMock {
+ callback = (x: any) => null
+
+ constructor(callback: any) {
+ this.callback = callback
+ }
+
+ observe() {
+ this.callback([{ contentRect: { width: 100 } }])
+ }
+ unobserve() {
+ // do nothing
+ }
+ disconnect() {
+ // do nothing
+ }
+}
+global.window.ResizeObserver = ResizeObserverMock
+
+describe('useSyncWrapperWidth', () => {
+ describe('wrapperRefState is null', () => {
+ it('returns the wrapper width as 100%', () => {
+ const { result } = renderHook(() => useSyncWrapperWidth())
+
+ expect(result.current.wrapperWidth).toBe('100%')
+ })
+ })
+
+ describe('wrapperRefState is set', () => {
+ it('returns the wrapper width from the ResizeObserver entry', () => {
+ const { result } = renderHook(() => useSyncWrapperWidth())
+
+ act(() => {
+ result.current.setWrapperRefState({} as HTMLDivElement)
+ })
+
+ expect(result.current.wrapperWidth).toBe(100)
+ })
+ })
+})