From 12e7440ccc886fe5b2be194a8952ae87bfe04cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=20Cai?= Date: Fri, 6 Dec 2024 20:51:07 +0800 Subject: [PATCH 1/2] test(affix): improve Affix component and tests - optimize environment judgment - correctly judge whether parameters are passed in --- src/affix/Affix.tsx | 12 +-- src/affix/__tests__/affix.test.tsx | 119 +++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/src/affix/Affix.tsx b/src/affix/Affix.tsx index d0db2483fa..d950033b57 100644 --- a/src/affix/Affix.tsx +++ b/src/affix/Affix.tsx @@ -44,16 +44,16 @@ const Affix = forwardRef((props, ref) => { } const calcTop = wrapToTop - containerToTop; // 节点顶部到 container 顶部的距离 - const containerHeight = - scrollContainer.current[scrollContainer.current instanceof Window ? 'innerHeight' : 'clientHeight'] - - wrapHeight; + const isWindow = typeof window !== 'undefined' && scrollContainer.current === window; + + const containerHeight = scrollContainer.current[isWindow ? 'innerHeight' : 'clientHeight'] - wrapHeight; const calcBottom = containerToTop + containerHeight - (offsetBottom ?? 0); // 计算 bottom 相对应的 top 值 let fixedTop: number | false; - if (offsetTop !== undefined && calcTop <= offsetTop) { + if (props.offsetTop !== undefined && calcTop <= offsetTop) { // top 的触发 fixedTop = containerToTop + offsetTop; - } else if (offsetBottom !== undefined && wrapToTop >= calcBottom) { + } else if (props?.offsetBottom !== undefined && wrapToTop >= calcBottom) { // bottom 的触发 fixedTop = calcBottom; } else { @@ -102,7 +102,7 @@ const Affix = forwardRef((props, ref) => { }); } ticking.current = true; - }, [classPrefix, offsetBottom, offsetTop, onFixedChange, zIndex]); + }, [classPrefix, offsetBottom, offsetTop, onFixedChange, props?.offsetBottom, props.offsetTop, zIndex]); useImperativeHandle(ref, () => ({ handleScroll, diff --git a/src/affix/__tests__/affix.test.tsx b/src/affix/__tests__/affix.test.tsx index 33bd0cadd6..5ecb18051c 100644 --- a/src/affix/__tests__/affix.test.tsx +++ b/src/affix/__tests__/affix.test.tsx @@ -1,15 +1,27 @@ import React from 'react'; -import { render, describe, vi, mockTimeout } from '@test/utils'; +import { render, describe, vi, mockTimeout } from '../../../test/utils'; import Affix from '../index'; describe('Affix 组件测试', () => { const mockFn = vi.spyOn(HTMLDivElement.prototype, 'getBoundingClientRect'); const mockScrollTo = async (top: number) => { - mockFn.mockImplementation(() => ({ top, bottom: 0 })); + mockFn.mockImplementation(() => ({ + top, + bottom: 0, + left: 0, + right: 0, + height: 0, + width: 0, + x: 0, + y: 0, + toJSON: () => ({}), + })); }; + beforeEach(async () => { await mockScrollTo(0); }); + test('render perfectly', async () => { const { queryByText } = render( @@ -19,24 +31,115 @@ describe('Affix 组件测试', () => { expect(queryByText('固钉')).toBeInTheDocument(); }); - test('offsetTop and onFixedChange and zIndex', async () => { + + test('className', async () => { + const { container } = render( + +
固钉
+
, + ); + + const affixElement = container.querySelector('.custom-class-name'); + expect(affixElement).not.toBeNull(); + expect(affixElement?.className).toContain('custom-class-name'); + }); + + test('style', async () => { + const { container } = render( + +
固钉
+
, + ); + const affixElement = container.querySelector('.custom-class-name'); + expect(affixElement).not.toBeNull(); + expect((affixElement as HTMLElement)?.style.background).toBe('red'); + }); + + test('content', async () => { + const Children = () =>
固钉
; + const { queryByText } = render(} />); + expect(queryByText('固钉')).toBeInTheDocument(); + }); + + test('offsetTop trigger onFixedChange and zIndex', async () => { + const onFixedChangeMock = vi.fn(); + + const { getByText } = render( + +
固钉
+
, + ); + // 默认 + expect(onFixedChangeMock).toHaveBeenCalledTimes(0); + expect(getByText('固钉').parentNode).not.toHaveClass('t-affix'); + expect(getByText('固钉').parentElement?.style.zIndex).toBe(''); + + // offsetTop + await mockScrollTo(30); + await mockScrollTo(10); + await mockTimeout(() => false, 200); + expect(onFixedChangeMock).toHaveBeenCalledTimes(1); + + expect(getByText('固钉').parentNode).toHaveClass('t-affix'); + expect(getByText('固钉').parentElement?.style.zIndex).toBe('2'); + }); + + test('offsetBottom trigger onFixedChange and zIndex', async () => { const onFixedChangeMock = vi.fn(); const { getByText } = render( - +
固钉
, ); + // 默认 + expect(onFixedChangeMock).toHaveBeenCalledTimes(0); + expect(getByText('固钉').parentNode).not.toHaveClass('t-affix'); + expect(getByText('固钉').parentElement?.style.zIndex).toBe(''); + + // offsetBottom + const isWindow = typeof window !== 'undefined' && window.innerHeight !== undefined; + const { clientHeight } = document.documentElement; + const { innerHeight } = window; + await mockScrollTo((isWindow ? innerHeight : clientHeight) - 40); + await mockScrollTo(isWindow ? innerHeight : clientHeight); + await mockTimeout(() => false, 200); + expect(onFixedChangeMock).toHaveBeenCalledTimes(1); + + expect(getByText('固钉').parentNode).toHaveClass('t-affix'); + expect(getByText('固钉').parentElement?.style.zIndex).toBe('2'); + }); + + test('offsetTop and offsetBottom trigger onFixedChange and zIndex', async () => { + const onFixedChangeMock = vi.fn(); - expect(onFixedChangeMock).toBeCalledTimes(0); + const { getByText } = render( + +
固钉
+
, + ); + // 默认 + expect(onFixedChangeMock).toHaveBeenCalledTimes(0); expect(getByText('固钉').parentNode).not.toHaveClass('t-affix'); - expect(getByText('固钉').parentElement.style.zIndex).toBe(''); + expect(getByText('固钉').parentElement?.style.zIndex).toBe(''); - await mockScrollTo(-10); + // offsetTop + await mockScrollTo(30); + await mockScrollTo(10); + await mockTimeout(() => false, 200); + expect(onFixedChangeMock).toHaveBeenCalledTimes(1); + // offsetBottom + const isWindow = typeof window !== 'undefined' && window.innerHeight !== undefined; + const { clientHeight } = document.documentElement; + const { innerHeight } = window; + await mockScrollTo((isWindow ? innerHeight : clientHeight) - 40); + await mockScrollTo(isWindow ? innerHeight : clientHeight); await mockTimeout(() => false, 200); + expect(onFixedChangeMock).toHaveBeenCalledTimes(1); + expect(getByText('固钉').parentNode).toHaveClass('t-affix'); - expect(getByText('固钉').parentElement.style.zIndex).toBe('2'); + expect(getByText('固钉').parentElement?.style.zIndex).toBe('2'); }); }); From 4507a75e764aef79da100ac8c6c703c6fe90195e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=20Cai?= Date: Wed, 18 Dec 2024 16:49:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20=20=E6=81=A2=E5=A4=8D=E4=B9=8B?= =?UTF-8?q?=E5=89=8D=E7=9A=84=20`@test/utils`=20=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/affix/__tests__/affix.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/affix/__tests__/affix.test.tsx b/src/affix/__tests__/affix.test.tsx index 5ecb18051c..9771f5e972 100644 --- a/src/affix/__tests__/affix.test.tsx +++ b/src/affix/__tests__/affix.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, describe, vi, mockTimeout } from '../../../test/utils'; +import { render, describe, vi, mockTimeout } from '@test/utils'; import Affix from '../index'; describe('Affix 组件测试', () => {