Skip to content

Commit 85c3df7

Browse files
committed
test: add coverage for window scroll mode, initialScrollY, touch PTR, null scrollableTarget, and missing refreshFunction
1 parent bc691b9 commit 85c3df7

4 files changed

Lines changed: 170 additions & 0 deletions

File tree

src/__tests__/bottom.test.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,27 @@ describe('bottom detection triggers next', () => {
7373

7474
expect(next).toHaveBeenCalledTimes(1);
7575
});
76+
77+
it('uses null root (viewport) in window scroll mode', () => {
78+
const next = jest.fn();
79+
render(
80+
<InfiniteScroll
81+
dataLength={0}
82+
loader={'Loading...'}
83+
hasMore={true}
84+
next={next}
85+
>
86+
<div />
87+
</InfiniteScroll>
88+
);
89+
90+
// No height, no scrollableTarget → root must be null (viewport IO)
91+
expect(MockIntersectionObserver.instances[0].options.root).toBeNull();
92+
93+
act(() => {
94+
MockIntersectionObserver.instances[0].triggerIntersect();
95+
});
96+
97+
expect(next).toHaveBeenCalled();
98+
});
7699
});

src/__tests__/index.test.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,88 @@ describe('React Infinite Scroll Component', () => {
105105
});
106106
});
107107

108+
describe('When pullDownToRefresh is true but refreshFunction is missing', () => {
109+
it('throws an error', () => {
110+
const consoleSpy = jest
111+
.spyOn(console, 'error')
112+
.mockImplementation(() => {});
113+
114+
expect(() =>
115+
render(
116+
<InfiniteScroll
117+
dataLength={0}
118+
loader={'Loading...'}
119+
hasMore={false}
120+
next={() => {}}
121+
pullDownToRefresh
122+
>
123+
<div />
124+
</InfiniteScroll>
125+
)
126+
).toThrow('Mandatory prop "refreshFunction" missing');
127+
128+
consoleSpy.mockRestore();
129+
});
130+
});
131+
132+
describe('initialScrollY', () => {
133+
it('calls scrollTo on mount when scrollHeight exceeds initialScrollY', () => {
134+
const scrollToSpy = jest.fn();
135+
const originalScrollTo = HTMLElement.prototype.scrollTo;
136+
HTMLElement.prototype.scrollTo = scrollToSpy as any;
137+
138+
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
139+
configurable: true,
140+
get: () => 500,
141+
});
142+
143+
render(
144+
<InfiniteScroll
145+
dataLength={0}
146+
loader={'Loading...'}
147+
hasMore={false}
148+
next={() => {}}
149+
height={100}
150+
initialScrollY={200}
151+
>
152+
<div />
153+
</InfiniteScroll>
154+
);
155+
156+
expect(scrollToSpy).toHaveBeenCalledWith(0, 200);
157+
158+
HTMLElement.prototype.scrollTo = originalScrollTo;
159+
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', {
160+
configurable: true,
161+
get: () => 0,
162+
});
163+
});
164+
165+
it('does not call scrollTo when scrollHeight is insufficient', () => {
166+
const scrollToSpy = jest.fn();
167+
const originalScrollTo = HTMLElement.prototype.scrollTo;
168+
HTMLElement.prototype.scrollTo = scrollToSpy as any;
169+
170+
// scrollHeight defaults to 0 in jsdom — less than initialScrollY
171+
render(
172+
<InfiniteScroll
173+
dataLength={0}
174+
loader={'Loading...'}
175+
hasMore={false}
176+
next={() => {}}
177+
height={100}
178+
initialScrollY={200}
179+
>
180+
<div />
181+
</InfiniteScroll>
182+
);
183+
184+
expect(scrollToSpy).not.toHaveBeenCalled();
185+
186+
HTMLElement.prototype.scrollTo = originalScrollTo;
187+
});
188+
});
189+
108190
describe('When user scrolls to the bottom', () => {
109191
it('does not show loader if hasMore is false', () => {
110192
const { queryByText } = render(

src/__tests__/pullDown.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,48 @@ describe('pull down to refresh', () => {
7272

7373
expect(refresh).toHaveBeenCalled();
7474
});
75+
76+
it('calls refreshFunction after touch pull past threshold', () => {
77+
const refresh = jest.fn();
78+
const { container } = render(
79+
<InfiniteScroll
80+
dataLength={10}
81+
loader={'Loading...'}
82+
hasMore={true}
83+
next={() => {}}
84+
height={200}
85+
pullDownToRefresh
86+
pullDownToRefreshThreshold={50}
87+
refreshFunction={refresh}
88+
pullDownToRefreshContent={<div style={{ height: 100 }}>Pull</div>}
89+
>
90+
<div />
91+
</InfiniteScroll>
92+
);
93+
94+
const node = container.querySelector(
95+
'.infinite-scroll-component'
96+
) as HTMLElement;
97+
98+
const touchStart = new TouchEvent('touchstart', { bubbles: true });
99+
Object.defineProperty(touchStart, 'touches', { value: [{ pageY: 0 }] });
100+
act(() => {
101+
node.dispatchEvent(touchStart);
102+
});
103+
104+
const touchMove = new TouchEvent('touchmove', { bubbles: true });
105+
Object.defineProperty(touchMove, 'touches', { value: [{ pageY: 60 }] });
106+
act(() => {
107+
node.dispatchEvent(touchMove);
108+
});
109+
110+
expect(node.style.transform).toBe('translate3d(0px, 60px, 0px)');
111+
112+
const touchEnd = new TouchEvent('touchend', { bubbles: true });
113+
act(() => {
114+
node.dispatchEvent(touchEnd);
115+
});
116+
117+
expect(refresh).toHaveBeenCalled();
118+
});
75119
});

src/__tests__/scrollableTarget.test.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,25 @@ describe('scrollableTarget as element id', () => {
6666

6767
document.body.removeChild(target);
6868
});
69+
70+
it('warns when scrollableTarget is null', () => {
71+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
72+
73+
render(
74+
<InfiniteScroll
75+
dataLength={0}
76+
loader={'Loading...'}
77+
hasMore={true}
78+
next={() => {}}
79+
scrollableTarget={null}
80+
>
81+
<div />
82+
</InfiniteScroll>
83+
);
84+
85+
expect(warnSpy).toHaveBeenCalledWith(
86+
expect.stringContaining('scrollableTarget but it is null')
87+
);
88+
warnSpy.mockRestore();
89+
});
6990
});

0 commit comments

Comments
 (0)