-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(useElementVisibility)!: use useIntersectionObserver instead of sc…
…roll event handler (#2551)
- Loading branch information
1 parent
a2f334d
commit 74b00a0
Showing
3 changed files
with
62 additions
and
106 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,75 @@ | ||
import { nextTick } from 'vue-demi' | ||
import { useElementVisibility } from '.' | ||
|
||
describe('useElementVisibility', () => { | ||
let el: HTMLDivElement | ||
const overLeft = document.documentElement.clientWidth + 100 | ||
const overTop = document.documentElement.clientHeight + 100 | ||
const rect = { | ||
y: 0, | ||
bottom: 0, | ||
height: 0, | ||
left: 0, | ||
right: 0, | ||
top: 0, | ||
width: 0, | ||
} as DOMRect | ||
function scrollTrigger() { | ||
window.dispatchEvent(new Event('scroll')) | ||
} | ||
function mockGetBoundingClientRect(values: DOMRect[]) { | ||
const mocker = values.reduce((f, result) => f.mockReturnValueOnce(result), vi.fn()) | ||
// prevent error when other tests trigger scroll | ||
mocker.mockImplementation(() => rect) | ||
return mocker | ||
} | ||
|
||
beforeEach(() => { | ||
el = document.createElement('div') | ||
window.innerWidth = document.documentElement.clientWidth | ||
window.innerHeight = document.documentElement.clientHeight | ||
document.body.appendChild(el) | ||
}) | ||
|
||
it('should work when el is not an element', async () => { | ||
const visible = useElementVisibility(null) | ||
expect(visible.value).toBeFalsy() | ||
scrollTrigger() | ||
await nextTick() | ||
}) | ||
|
||
it('should work when window is undefined', () => { | ||
// @ts-expect-error set window null | ||
const visible = useElementVisibility(el, { window: null }) | ||
expect(visible.value).toBeFalsy() | ||
}) | ||
|
||
it('should work when scrollY', async () => { | ||
el.getBoundingClientRect = mockGetBoundingClientRect([ | ||
rect, | ||
{ ...rect, top: overTop }, | ||
rect, | ||
{ ...rect, top: overTop }, | ||
]) | ||
describe('when internally using useIntersectionObserver', async () => { | ||
const { useIntersectionObserver } = await import('../useIntersectionObserver') | ||
|
||
const visible = useElementVisibility(el) | ||
expect(visible.value).toBeTruthy() | ||
beforeAll(() => { | ||
vi.resetAllMocks() | ||
vi.mock('../useIntersectionObserver') | ||
}) | ||
|
||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeFalsy() | ||
it('should call useIntersectionObserver internally', () => { | ||
expect(useIntersectionObserver).toHaveBeenCalledTimes(0) | ||
useElementVisibility(el) | ||
expect(useIntersectionObserver).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
window.innerHeight = 0 | ||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeTruthy() | ||
it('passes the given element to useIntersectionObserver', () => { | ||
useElementVisibility(el) | ||
expect(vi.mocked(useIntersectionObserver).mock.lastCall?.[0]).toBe(el) | ||
}) | ||
|
||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeFalsy() | ||
}) | ||
it('passes a callback to useIntersectionObserver that sets visibility to false only when isIntersecting is false', () => { | ||
const isVisible = useElementVisibility(el) | ||
const callback = vi.mocked(useIntersectionObserver).mock.lastCall?.[1] | ||
const callMockCallbackWithIsIntersectingValue = (isIntersecting: boolean) => callback?.([{ isIntersecting } as IntersectionObserverEntry], {} as IntersectionObserver) | ||
|
||
it('should work when scrollX', async () => { | ||
el.getBoundingClientRect = mockGetBoundingClientRect([ | ||
rect, | ||
{ ...rect, left: overLeft }, | ||
rect, | ||
{ ...rect, left: overLeft }, | ||
]) | ||
// It should be false initially | ||
expect(isVisible.value).toBe(false) | ||
|
||
const visible = useElementVisibility(el) | ||
expect(visible.value).toBeTruthy() | ||
// It should still be false if the callback doesn't get an isIntersecting = true | ||
callMockCallbackWithIsIntersectingValue(false) | ||
expect(isVisible.value).toBe(false) | ||
|
||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeFalsy() | ||
// But it should become true if the callback gets an isIntersecting = true | ||
callMockCallbackWithIsIntersectingValue(true) | ||
expect(isVisible.value).toBe(true) | ||
|
||
window.innerWidth = 0 | ||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeTruthy() | ||
// And it should become false again if isIntersecting = false | ||
callMockCallbackWithIsIntersectingValue(false) | ||
expect(isVisible.value).toBe(false) | ||
}) | ||
|
||
scrollTrigger() | ||
await nextTick() | ||
expect(visible.value).toBeFalsy() | ||
}) | ||
it('passes the given window to useIntersectionObserver', () => { | ||
const mockWindow = {} as Window | ||
|
||
it('should work when window is undefined', () => { | ||
// @ts-expect-error set window null | ||
const visible = useElementVisibility(el, { window: null }) | ||
expect(visible.value).toBeFalsy() | ||
useElementVisibility(el, { window: mockWindow }) | ||
expect(vi.mocked(useIntersectionObserver).mock.lastCall?.[2]).toContain({ window: mockWindow }) | ||
}) | ||
|
||
it('uses the given scrollTarget as the root element in useIntersectionObserver', () => { | ||
const mockScrollTarget = document.createElement('div') | ||
|
||
useElementVisibility(el, { scrollTarget: mockScrollTarget }) | ||
expect(vi.mocked(useIntersectionObserver).mock.lastCall?.[2]).toContain({ root: mockScrollTarget }) | ||
}) | ||
}) | ||
}) |
This file contains 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
This file contains 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