import React, { useEffect, useRef } from 'react'; import Affix from '..'; import accessibilityTest from '../../../tests/shared/accessibilityTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { render, triggerResize, waitFakeTimer } from '../../../tests/utils'; import Button from '../../button'; const events: Partial) => void>> = {}; interface AffixProps { offsetTop?: number; offsetBottom?: number; style?: React.CSSProperties; onChange?: () => void; onTestUpdatePosition?: () => void; } const AffixMounter: React.FC = (props) => { const container = useRef(null); useEffect(() => { if (container.current) { container.current.addEventListener = jest .fn() .mockImplementation((event: keyof HTMLElementEventMap, cb: (ev: Event) => void) => { events[event] = cb; }); } }, []); return (
container.current} {...props}>
); }; describe('Affix Render', () => { rtlTest(Affix); accessibilityTest(Affix); const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect'); const classRect: Record = { container: { top: 0, bottom: 100 } as DOMRect }; beforeEach(() => { jest.useFakeTimers(); }); beforeAll(() => { domMock.mockImplementation(function fn(this: HTMLElement) { return classRect[this.className] || { top: 0, bottom: 0 }; }); }); afterEach(() => { jest.useRealTimers(); jest.clearAllTimers(); }); afterAll(() => { domMock.mockRestore(); }); const movePlaceholder = async (top: number) => { classRect.fixed = { top, bottom: top } as DOMRect; if (events.scroll == null) { throw new Error('scroll should be set'); } events.scroll({ type: 'scroll' }); await waitFakeTimer(); }; it('Anchor render perfectly', async () => { const { container } = render(); await waitFakeTimer(); await movePlaceholder(0); expect(container.querySelector('.ant-affix')).toBeFalsy(); await movePlaceholder(-100); expect(container.querySelector('.ant-affix')).toBeTruthy(); await movePlaceholder(0); expect(container.querySelector('.ant-affix')).toBeFalsy(); }); it('Anchor correct render when target is null', async () => { render( null}>test); await waitFakeTimer(); }); it('support offsetBottom', async () => { const { container } = render(); await waitFakeTimer(); await movePlaceholder(300); expect(container.querySelector('.ant-affix')).toBeTruthy(); await movePlaceholder(0); expect(container.querySelector('.ant-affix')).toBeFalsy(); await movePlaceholder(300); expect(container.querySelector('.ant-affix')).toBeTruthy(); }); it('updatePosition when offsetTop changed', async () => { const onChange = jest.fn(); const { container, rerender } = render(); await waitFakeTimer(); await movePlaceholder(-100); expect(onChange).toHaveBeenLastCalledWith(true); expect(container.querySelector('.ant-affix')).toHaveStyle({ top: 0 }); rerender(); await waitFakeTimer(); expect(container.querySelector('.ant-affix')).toHaveStyle({ top: `10px` }); }); describe('updatePosition when target changed', () => { it('function change', () => { document.body.innerHTML = `
`; const target = document.getElementById('mounter'); const getTarget = () => target; const { container, rerender } = render({null}); rerender( null}>{null}); expect(container.querySelector(`div[aria-hidden="true"]`)).toBeNull(); expect(container.querySelector('.ant-affix')?.getAttribute('style')).toBeUndefined(); }); it('check position change before measure', async () => { const { container } = render( <> , ); await waitFakeTimer(); await movePlaceholder(1000); expect(container.querySelector('.ant-affix')).toBeTruthy(); }); it('do not measure when hidden', async () => { const { container, rerender } = render(); await waitFakeTimer(); const affixStyleEle = container.querySelector('.ant-affix'); const firstAffixStyle = affixStyleEle ? affixStyleEle.getAttribute('style') : null; rerender(); await waitFakeTimer(); const secondAffixStyle = affixStyleEle ? affixStyleEle.getAttribute('style') : null; expect(firstAffixStyle).toEqual(secondAffixStyle); }); }); describe('updatePosition when size changed', () => { it('add class automatically', async () => { document.body.innerHTML = '
'; const { container } = render(, { container: document.getElementById('mounter')!, }); await waitFakeTimer(); await movePlaceholder(300); expect(container.querySelector(`div[aria-hidden="true"]`)).toBeTruthy(); expect(container.querySelector('.ant-affix')?.getAttribute('style')).toBeTruthy(); }); // Trigger inner and outer element for the two s. ['.ant-btn', '.fixed'].forEach((selector) => { it(`trigger listener when size change: ${selector}`, async () => { const updateCalled = jest.fn(); const { container } = render( , { container: document.getElementById('mounter')! }, ); updateCalled.mockReset(); triggerResize(container.querySelector(selector)!); await waitFakeTimer(); expect(updateCalled).toHaveBeenCalled(); }); }); }); });