next icon indicating copy to clipboard operation
next copied to clipboard

[Balloon]testing-library测试Balloon组件无法捕获到正确的气泡弹出隐藏DOM状态

Open Symous opened this issue 1 year ago • 10 comments
trafficstars

Component

Balloon

Steps to reproduce

我在使用Jest testing-library/react测试Balloon组件的气泡显示隐藏时,遇到了由于Balloon组件显示隐藏的动画效果影响,使得testing-library无法捕获到正确的DOM的问题,我的测试代码如下:

/** @jest-environment jsdom */
import React from 'react';
import { Balloon, Button } from '@alifd/next';
import { render, screen, fireEvent, act, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';

describe('Balloon', () => {
    it('鼠标悬浮显示气泡,鼠标移开隐藏气泡', async () => {
        const { container } = render(
            <Balloon
                title="balloon"
                trigger={<Button>触发器</Button>}
            >
                气泡内容
            </Balloon>
            , {
                container: document.body
            });

        jest.useFakeTimers();

        const button = screen.queryByRole('button');
        expect(button).toBeInTheDocument();
        fireEvent.mouseEnter(button);

        // 由于气泡的延时显示,使用timer延时;
        act(() => {
          jest.advanceTimersByTime(1000);
        });

        console.log('--------')
        console.log(container.innerHTML);
        console.log('--------')

        // 输出内容
        // <button aria-haspopup="true" aria-expanded="true" type="button" class="next-btn next-medium next-btn-normal"><span class="next-btn-helper">触发器</span></button><div class="next-overlay-wrapper"><div role="tooltip" aria-live="polite" class="next-balloon next-balloon-normal next-balloon-medium next-balloon-top next-overlay-inner zoomIn zoomInBig" style="transform-origin: top; position: absolute; left: 0px; top: 12px;" aria-hidden="false"><div class="next-balloon-arrow"><div class="next-balloon-arrow-content"></div></div><div class="next-balloon-title next-balloon-closable">balloon<a role="button" aria-label="关闭" tabindex="0" class="next-balloon-close"><i class="next-icon next-icon-close next-small"></i></a></div><div class="next-balloon-content">气泡内容</div></div></div>
    
        // 注意其中的next-balloon div 包含一个 zoomIn zoomInBig 的样式名

        expect(document.querySelector('.next-balloon')).toBeInTheDocument();
        expect(screen.queryByText("气泡内容")).toBeInTheDocument();

        fireEvent.mouseLeave(button);

        // 由于气泡的延时隐藏,使用timer延时;
        act(() => {
          jest.advanceTimersByTime(1000);
        })

        console.log('--------')
        console.log(container.innerHTML);
        console.log('--------')

        // 输出内容
        // <button aria-haspopup="true" aria-expanded="false" type="button" class="next-btn next-medium next-btn-normal"><span class="next-btn-helper">触发器</span></button><div class="next-overlay-wrapper"><div role="tooltip" aria-live="polite" class="next-balloon next-balloon-normal next-balloon-medium next-balloon-top next-overlay-inner zoomOut zoomOutBig" style="transform-origin: top; position: absolute; left: 0px; top: 12px;" aria-hidden="false"><div class="next-balloon-arrow"><div class="next-balloon-arrow-content"></div></div><div class="next-balloon-title next-balloon-closable">balloon<a role="button" aria-label="关闭" tabindex="0" class="next-balloon-close"><i class="next-icon next-icon-close next-small"></i></a></div><div class="next-balloon-content">气泡内容</div></div></div>

        // 注意其中的next-balloon div 包含一个 zoomOut zoomOutBig 的样式名

        // FIXME: 【无法通过测试!!!】,因为动画效果的存在,无法捕获到正确的document渲染内容
        expect(document.querySelector('.next-balloon')).not.toBeInTheDocument();
        expect(screen.queryByText("气泡内容")).not.toBeInTheDocument();

    })
})

理论上来说,当我们的鼠标从触发器离开后,气泡应当消失,也就是说 next-balloon类名元素以及 “气泡内容” 文字都应当找不到才对,但是在实际表现中,他们仍然能够被找到。

为了找到原因,我在代码中,加入了在鼠标悬浮后以及离开后的DOM打印(见代码中的输出内容),发现根本的原因在于,由于Balloon组件气泡的动画效果,testing-library只捕获到了气泡即将出现时的状态(next-balloon中包含zoomIn zoomInBig)以及即将隐藏时的状态(next-balloon中包含zoomOut zoomOutBig),而没有捕获到气泡完全显示(next-balloon存在且没有zoomX样式)以及完全消失的状态(next-balloon不应存在),导致测试断言失效!

为了验证这个问题,我将Balloon组件添加了animation={false}来隐藏动画效果,发现如此一来能捕获到正确的DOM变化(没有动画中间态),用例便能跑通了。

此外,我也尝试了其他获取DOM的方法,比如await waitForawait findByText等方法,结果均是一样的,所以我现在非常确认Balloon组件的实现与testing-library存在某种冲突。

我并不是为了测试Balloon组件而写该测试用例,只是因为我有一个业务组件对Balloon进行了二次封装,我是在测试自己业务组件时发现的Balloon组件的这个测试问题。

请我该问题出现的原因是什么?如果我的测试用例有问题,那我应当如何修正?谢谢!

Symous avatar Mar 09 '24 06:03 Symous

这是您为 Fusion/Next 提的第一个 issue,感谢您对 Fusion 的信任和支持,我们会尽快进行处理。

github-actions[bot] avatar Mar 09 '24 06:03 github-actions[bot]

这感觉是一个使用 jest 和 react-testing-library 的问题,而不是 Fusion 的问题,因为 React 组件中使用 Animation 是很常见的情况,这并不是一个 Fusion 的使用问题或者 bug。关于如何在你说的测试框架下测试动画结束相关的,可以参考 stackoverflow 的这个 issue:https://stackoverflow.com/questions/77250912/how-to-wait-until-an-animation-ends-to-test-an-on-click-callback

eternalsky avatar Mar 11 '24 08:03 eternalsky

@eternalsky 感谢你的回复,事实上,在我发起issue之前,我就已经尝试了fireEvent.animationEnd的处理方式,然后我又参照你提供的链接又重新梳理测试了下,发现和我上面描述的是一样的问题,我相信这个问题并不是由于Fusion引起的,而是jest和react-testing-library的原因。

在我提问之前,我去Fusion源代码的Balloon等组件的测试用例试图找一些参考,但是发现你们官方也没有提供测试trigger行为引起的弹层气泡消失的用例。能否辛苦贵团队完善一下相关测试用例为我们其他开发者提供一下参考如何正确处理动画效果?因为作为Balloon组件来讲,气泡的出现和消失是它非常重要的一个测试项,谢谢!

Symous avatar Mar 14 '24 10:03 Symous

@eternalsky 感谢你的回复,事实上,在我发起issue之前,我就已经尝试了fireEvent.animationEnd的处理方式,然后我又参照你提供的链接又重新梳理测试了下,发现和我上面描述的是一样的问题,我相信这个问题并不是由于Fusion引起的,而是jest和react-testing-library的原因。

在我提问之前,我去Fusion源代码的Balloon等组件的测试用例试图找一些参考,但是发现你们官方也没有提供测试trigger行为引起的弹层气泡消失的用例。能否辛苦贵团队完善一下相关测试用例为我们其他开发者提供一下参考如何正确处理动画效果?因为作为Balloon组件来讲,气泡的出现和消失是它非常重要的一个测试项,谢谢!

我们正在使用 cypress 对组件的测试用例进行重构,有些组件已经完成了跟动画相关的,比如 Animate 组件,可以作为参考。

eternalsky avatar Mar 15 '24 03:03 eternalsky

@eternalsky 感谢你的指导,我参考了Animate组件的cypress测试用例,但是还是有点摸不到头脑无法完成测试。就像我上面说的,气泡的显示和隐藏式Balloon组件一个非常重要的测试特性,但是贵团队的组件库却没有包含相关测试用例,能否请贵团队先对我issue中提出的testing-library用例代码进行指正如何借助Animated组件的测试思路完成测试?麻烦了。

Symous avatar Mar 20 '24 03:03 Symous

你好,该 issue 已 30 天没有活动,因此被标记为 stale,如果之后的 7 天仍然没有活动,该 issue 将被自动关闭

github-actions[bot] avatar Apr 19 '24 17:04 github-actions[bot]

该问题目前没有明确的解决方案,如何重新打开issue?

Symous avatar Apr 28 '24 01:04 Symous

@eternalsky 感谢你的指导,我参考了Animate组件的cypress测试用例,但是还是有点摸不到头脑无法完成测试。就像我上面说的,气泡的显示和隐藏式Balloon组件一个非常重要的测试特性,但是贵团队的组件库却没有包含相关测试用例,能否请贵团队先对我issue中提出的testing-library用例代码进行指正如何借助Animated组件的测试思路完成测试?麻烦了。

按照 cypress 的思路,这里应该是要反复查询一段时间到出现为止。如果超过一段时间没有出现,则认为失败

eternalsky avatar Apr 29 '24 03:04 eternalsky

@eternalsky 我已经尝试过了等待一段时间等各种方式,但是testing-library仍然捕获不到有动画效果时气泡的最终状态,现在完全没有解决头绪,只能在用例里强制把动画效果关掉,能不能提供一个测试demo给像我这样有需要的开发者参考?

Symous avatar Apr 29 '24 03:04 Symous

@eternalsky 我已经尝试过了等待一段时间等各种方式,但是testing-library仍然捕获不到有动画效果时气泡的最终状态,现在完全没有解决头绪,只能在用例里强制把动画效果关掉,能不能提供一个测试demo给像我这样有需要的开发者参考?

我们的组件本身是使用 enzyme 做测试的,重构后会使用 cypress,并没有使用 testing-library,因此也无法给你做准确的参考,这也不在我们提供的支持范围内。我们本身 balloon 有大量的 test case 你可以参考他们来实现你自己的 tc。

eternalsky avatar Apr 29 '24 13:04 eternalsky

你好,该 issue 已 30 天没有活动,因此被标记为 stale,如果之后的 7 天仍然没有活动,该 issue 将被自动关闭

github-actions[bot] avatar May 29 '24 17:05 github-actions[bot]