本文转载自:众成翻译
译者:iOSDevLog
链接:http://www.zcfy.cc/article/3806
原文:https://www.fullstackreact.com/30-days-of-react/day-25/
今天,我们将看看一个由Airbnb所维护的开源库,名为Enzyme,使得测试变得简单易用。
昨天我们使用了react-addons-test-utils
库来编写我们对Timeline
组件的第一个测试。但是,此库是相当低级的,使用起来可能有点麻烦。@L_404_4@是由 AirBnb 团队发布和维护的测试实用程序库,它提供了一个更好的、高级的 API 来处理测试中的React组件。
我们在测试我们的 <Timeline />
组件:
使用Enzyme@H_404_20@
我们将使用Enzyme,使这些测试更容易写和更可读。
昨天,我们写了我们的第一个测试如下:
import React from 'react'; import TestUtils from 'react-addons-test-utils'; import Timeline from '../Timeline'; describe('Timeline',() => { it('wraps content in a div with .notificationsFrame class',() => { const wrapper = TestUtils.renderIntoDocument(<Timeline />); TestUtils .findRenderedDOMComponentWithClass(wrapper,'notificationsFrame'); }); })
虽然这是可行的,但它不是世界上最容易阅读的测试。当用Enzyme我们重写它时让我们看看这个测试的样子。
我们可以只测试组件的输出,而不是用Enzyme来测试完整的组件树。将不渲染任何组件的子级。这称为 浅 渲染。
Enzyme使浅渲染超容易。我们将使用Enzyme导出的shallow
函数来装载我们的组件。
让我们更新src/components/Timeline/__tests__/Timeline-test.js
文件,包括从 enzyme
导入shallow
函数:
import React from 'react'; import { shallow } from 'enzyme'; describe('Timeline',() => { it('wraps content in a div with .notificationsFrame class',() => { // our tests }); })
react-addons-test-utils
也支持浅渲染。事实上,Enzyme素只是包装这个函数。虽然昨天我们没有使用浅渲染,但如果我们使用它看起来像这样:
> const renderer = ReactTestUtils.createRenderer(); > renderer.render(<Timeline />) > const result = renderer.getRenderOutput(); >
现在,为了渲染我们的组件,我们可以使用shallow
方法并将结果存储在一个变量中。然后,我们将为在其虚拟 dom 中渲染的不同的React元素 (HTML 或子组件) 查询 渲染的组件。
整个断言包括两行:
import React from 'react'; import { shallow,mount } from 'enzyme'; import Timeline from '../Timeline'; describe('Timeline',() => { let wrapper; it('wraps content in a div with .notificationsFrame class',() => { wrapper = shallow(<Timeline />); expect(wrapper.find('.notificationsFrame').length).toEqual(1); }); it('has a title of Timeline',() => { wrapper = mount(<Timeline />) expect(wrapper.find('.title').text()).toBe("Timeline") }) describe('search button',() => { let search; beforeEach(() => wrapper = mount(<Timeline />)) beforeEach(() => search = wrapper.find('input.searchInput')) it('starts out hidden',() => { expect(search.hasClass('active')).toBeFalsy() }) it('becomes visible after being clicked on',() => { const icon = wrapper.find('.searchIcon') icon.simulate('click') expect(search.hasClass('active')).toBeTruthy() }) }) describe('status updates',() => { it('has 4 status updates at minimum',() => { wrapper = shallow(<Timeline />) expect( wrapper.find('ActivityItem').length ).toBeGreaterThan(3) }) }) })
我们可以使用yarn test
命令 (或 npm test
命令) 一样的方式运行测试:
yarn test
我们的测试通过,并且更易于阅读和维护。
让我们继续写断言,从我们昨天开始的假设列表中抽取。我们将首先构建我们的测试套件的其余部分,写出我们的describe
和it
块。我们将填写的规格与断言后:
import React from 'react'; import { shallow } from 'enzyme'; import Timeline from '../Timeline'; describe('Timeline',() => { wrapper = shallow(<Timeline />); expect(wrapper.find('.notificationsFrame').length).toEqual(1); }); it('has a title of Timeline') describe('search button',() => { it('starts out hidden') it('becomes visible after being clicked on') }) describe('status updates',() => { it('has 4 status updates at minimum') }) })
如果我们遵循测试驱动开发 (简称 TDD),我们将首先编写这些假设,然后构建组件以通过这些测试。
让我们填写这些测试,以便它们通过我们现有的Timeline
组件。
我们的标题测试比较简单。我们将查找标题元素并确认标题为Timeline
。
我们希望标题可以在 .title
类下使用。因此,要在规范中使用 .title
类,我们只需使用Enzyme所暴露的find
函数即可获取组件。
因为我们的Header
组件是 Timeline
组件的子组件,所以不能使用shallow()
方法。相反,我们必须使用Enzyme提供的 mount()
方法。
Shallow? Mount?@H_404_20@
shallow()
渲染函数只渲染我们专门测试的组件,它不会渲染子元素。相反,我们将不得不mount()
组件,因为子组件Header
不可用的 jsdom,否则。我们将在本文的末尾看到更多的Enzyme函数。
现在让我们填写标题描述:
import React from 'react'; import { shallow,() => { wrapper = mount(<Timeline />) // notice the `mount` expect(wrapper.find('.title').text()).toBe("Timeline") }) })
运行我们的测试,我们将看到这两个期望通过:
接下来,让我们更新我们的搜索按钮测试。我们在这里有两个测试,其中一个要求我们测试一个交互。Enzyme为处理相互作用提供了一个非常干净的界面。让我们来看看如何根据搜索图标编写测试。
同样,由于我们在时间轴中对子元素进行测试,因此我们必须mount()
元素。因为我们要在一个嵌套的describe()
块中编写两个测试,所以我们可以在帮助器之前编写一个新的 mount()
来为每个测试重新创建,这样它们是纯的。
此外,我们还将使用 input.searchInput
元素进行两个测试,因此,让我们在前面的帮助器中为该元素编写.find()
。
describe('Timeline',() => { let wrapper; // ... describe('search button',() => { let search; beforeEach(() => wrapper = mount(<Timeline />)) beforeEach(() => search = wrapper.find('input.searchInput')) // ... }) })
若要测试是否隐藏了搜索输入,我们只需要知道是否应用了active
类。Enzyme为我们提供了一种使用 hasClass()
方法检测组件是否有类的方法。让我们填写第一个测试,期望搜索输入没有活动类:
describe('Timeline',() => { expect(search.hasClass('active')).toBeFalsy() }) it('becomes visible after being clicked on') // ... }) })
关于第二个测试的棘手部分是,我们需要点击图标元素。在我们看如何做到这一点之前,让我们先找到它。我们可以在包装上的目标通过它的 .searchIcon
类定位到它。
it('becomes visible after being clicked on',() => { const icon = wrapper.find('.searchIcon') })
现在,我们有了图标,我们想模拟一个点击元素。回想一下,onClick()
方法实际上只是浏览器事件的门面。即,单击一个元素只是一个通过组件冒泡的事件。而不是控制鼠标或调用元素上的click
,我们将模拟发生在它上的事件。对我们来说,这将是click
事件。
我们将在icon
上使用simulate()
方法来创建此事件:
it('becomes visible after being clicked on',() => { const icon = wrapper.find('.searchIcon') icon.simulate('click') })
现在我们可以设定一个search
组件具有active
类的期望。
it('becomes visible after being clicked on',() => { const icon = wrapper.find('.searchIcon') icon.simulate('click') expect(search.hasClass('active')).toBeTruthy() })
我们对Timeline
组件的最后期望是至少有四状态更新。当我们将这些元素放置在Timeline
组件上时,我们可以 "浅" 渲染组件。此外,由于每个元素都是自定义组件,因此我们可以搜索'ActivityItem'类型的特定组件的列表。
describe('status updates',() => { it('has 4 status updates at minimum',() => { wrapper = shallow(<Timeline />) // ... }) })
现在,我们可以测试ActivityItem
组件列表的长度。我们将设定我们的期望,如果长度至少是4的名单。
describe('status updates',() => { wrapper = shallow(<Timeline />) expect( wrapper.find('ActivityItem').length ).toBeGreaterThan(3) }) })
我们现在的整个测试套件如下所示:
import React from 'react'; import { shallow,() => { wrapper = shallow(<Timeline />) expect( wrapper.find('ActivityItem').length ).toBeGreaterThan(3) }) }) })
[](#whats-the-deal-with-find)find()
处理什么?@H_404_20@
在我们结束今天之前,我们应该看看一个Enzyme"渲染的界面 (在我们的测试中,wrapper
的对象)。Enzyme文档 太棒了,所以我们要保持这个简短。
基本上,当我们使用find()
函数时,我们会将它传递给一个选择器,它将返回一个ShallowWrapper
实例来包装找到的节点。find()
函数可以取字符串、函数或对象。
当我们将字符串传递给find()
函数时,我们可以传递 CSS 选择器或组件的 _显示名称_。例如:
wrapper.find('div.link'); wrapper.find('Link')
我们还可以将它传递给组件构造函数,例如:
import { Link } from 'react-router'; // ... wrapper.find(Link)
最后,我们还可以传递对象属性选择器对象,它通过键和值来选择元素。例如:
wrapper.find({to: '/login'});
返回值是一个 ShallowWrapper
,它是一种ShallowWrapper
类型 (我们可以渲染包装和浅包装)。这些 Wrapper
实例有一组功能,我们可以使用这些函数来针对不同的子组件,查看 props
和 state
,的方法,以及渲染的组件的其他属性,如html()
和text()
。更甚的是,我们可以把这些调用串在一起。
以 <Link />
组件为例。如果我们想找到基于所有可用链接的链接类的 HTML,我们可以编写这样的测试:
// ... it('displays a link tag with the Login text',() => { link = wrapper .find('Link') .find({to: '/login'}) expect(link.html()) .toBe('<a class="link">Login</a>') });
哦!今天有很多新的信息,但是看看我们是如何快速地用Enzyme来编写后续测试的。阅读的速度要快得多,而且更容易辨别实际发生的事情。
明天,我们将继续我们的测试旅程和通过集成测试测试我们的应用。
原文链接:https://www.f2er.com/react/303202.html