Created
July 22, 2019 16:25
-
-
Save willmanduffy/33a708816e95044dabafcbfe9e3c7bb8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { mount } from 'enzyme'; | |
| import React from 'react'; | |
| import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils'; | |
| import WithInfiniteScrolling from './with-infinite-scrolling'; | |
| describe('WithInfiniteScrolling', () => { | |
| afterEach(() => { | |
| jest.clearAllMocks(); | |
| }); | |
| const loadMoreFunction = jest.fn(); | |
| describe('when infinite scroll is not yet enabled', () => { | |
| describe('when the collection has multiple pages', () => { | |
| const wrapper = mount( | |
| <WithInfiniteScrolling | |
| hasMultiplePages={true} | |
| loadMoreFunction={loadMoreFunction} | |
| requireButtonClick={true} | |
| > | |
| <div id="very-cool-child" /> | |
| </WithInfiniteScrolling> | |
| ); | |
| it('renders the child component', () => { | |
| expect(wrapper.find('#very-cool-child')).toHaveLength(1); | |
| }); | |
| it('does not render the beacon', () => { | |
| expect(wrapper.find('#infinite-scroll-beacon')).toHaveLength(0); | |
| }); | |
| describe('clicking the load more button', () => { | |
| it('begins to load more', () => { | |
| const subject = wrapper.find( | |
| '#test-infinite-scroll-load-more-button' | |
| ); | |
| subject.simulate('click'); | |
| expect(loadMoreFunction).toHaveBeenCalled(); | |
| }); | |
| }); | |
| }); | |
| describe('when the collection does not have multiple pages', () => { | |
| const wrapper = mount( | |
| <WithInfiniteScrolling | |
| loadMoreFunction={loadMoreFunction} | |
| hasMultiplePages={false} | |
| requireButtonClick={true} | |
| > | |
| <div id="very-cool-child" /> | |
| </WithInfiniteScrolling> | |
| ); | |
| it('should not display the load more button', () => { | |
| const subject = wrapper.find('#test-infinite-scroll-load-more-button'); | |
| expect(subject).toHaveLength(0); | |
| }); | |
| it('renders the child component', () => { | |
| expect(wrapper.find('#very-cool-child')).toHaveLength(1); | |
| }); | |
| }); | |
| }); | |
| describe('when infinite is enabled', () => { | |
| describe('when the collection has multiple pages', () => { | |
| describe('when not already loading more items from the collection', () => { | |
| const wrapper = mount( | |
| <WithInfiniteScrolling | |
| hasMultiplePages={true} | |
| loading={false} | |
| loadMoreFunction={loadMoreFunction} | |
| requireButtonClick={false} | |
| > | |
| <div id="very-cool-child" /> | |
| </WithInfiniteScrolling> | |
| ); | |
| // FIXME: Having trouble with Enzyme and react-intersection-observer test utils | |
| // https://github.com/thebuilder/react-intersection-observer/issues/241 | |
| it.skip('triggers loading more when the beacon is in view', () => { | |
| const beacon = wrapper.find('#test-infinite-scroll-beacon'); | |
| mockAllIsIntersecting(true); | |
| wrapper.update(); | |
| expect(loadMoreFunction).toHaveBeenCalled(); | |
| }); | |
| it('should not display the load more button anymore', () => { | |
| const subject = wrapper.find( | |
| '#test-infinite-scroll-load-more-button' | |
| ); | |
| expect(subject).toHaveLength(0); | |
| }); | |
| it('should display the loading signifier', () => {}); | |
| it('renders the child component', () => { | |
| expect(wrapper.find('#very-cool-child')).toHaveLength(1); | |
| }); | |
| }); | |
| describe('when already loading more items fom the collection', () => { | |
| const wrapper = mount( | |
| <WithInfiniteScrolling | |
| hasMultiplePages={true} | |
| loading={true} | |
| loadMoreFunction={loadMoreFunction} | |
| requireButtonClick={false} | |
| > | |
| <div id="very-cool-child" /> | |
| </WithInfiniteScrolling> | |
| ); | |
| it('does nothing when the beacon is in view', () => { | |
| mockAllIsIntersecting(true); | |
| expect(loadMoreFunction).not.toHaveBeenCalled(); | |
| }); | |
| }); | |
| }); | |
| describe('when the collection does not have multiple pages', () => { | |
| const wrapper = mount( | |
| <WithInfiniteScrolling | |
| loadMoreFunction={loadMoreFunction} | |
| hasMultiplePages={false} | |
| requireButtonClick={false} | |
| > | |
| <div id="very-cool-child" /> | |
| </WithInfiniteScrolling> | |
| ); | |
| describe('when the beacon is in view', () => { | |
| it('does nothing', () => {}); | |
| }); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useEffect, useState } from 'react'; | |
| import { useInView } from 'react-intersection-observer'; | |
| const WithInfiniteScrolling = ({ | |
| children, | |
| hasMultiplePages, | |
| loading, | |
| loadMoreFunction, | |
| requireButtonClick = true | |
| }) => { | |
| const [infiniteDisabled, setInfiniteDisabled] = useState(requireButtonClick); | |
| const [beaconRef, beaconInView] = useInView(); | |
| const eligibleToLoadMore = hasMultiplePages && !infiniteDisabled && !loading; | |
| useEffect(() => { | |
| if (eligibleToLoadMore && beaconInView) { | |
| loadMoreFunction(); | |
| } | |
| }, [eligibleToLoadMore, beaconInView]); | |
| return ( | |
| <> | |
| {children} | |
| <div className="collection-frame-footer"> | |
| {hasMultiplePages && infiniteDisabled && !loading && ( | |
| <button | |
| id="test-infinite-scroll-load-more-button" | |
| onClick={() => { | |
| setInfiniteDisabled(false); | |
| loadMoreFunction(); | |
| }} | |
| > | |
| That's not enough | |
| </button> | |
| )} | |
| {loading && <span>Loading...</span>} | |
| {/* When this beacon comes into view (via IntersectionObserver) we will trigger the | |
| loadMoreFunction. The absolute positioning / negative margin is to help deal with | |
| latency as it will come into view before the bottom of the loaded collection. */} | |
| {eligibleToLoadMore && ( | |
| <div | |
| id="test-infinite-scroll-beacon" | |
| ref={beaconRef} | |
| style={{ position: 'absolute', marginTop: '-500px' }} | |
| /> | |
| )} | |
| </div> | |
| </> | |
| ); | |
| }; | |
| export default WithInfiniteScrolling; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment