摘要:昨天我們使用了庫(kù)來(lái)編寫我們對(duì)組件的第一個(gè)測(cè)試。是由團(tuán)隊(duì)發(fā)布和維護(hù)的測(cè)試實(shí)用程序庫(kù)它提供了一個(gè)更好的高級(jí)的來(lái)處理測(cè)試中的組件。我們將使用導(dǎo)出的函數(shù)來(lái)裝載我們的組件。相反我們必須使用提供的方法。
本文轉(zhuǎn)載自:眾成翻譯
譯者:iOSDevLog
鏈接:http://www.zcfy.cc/article/3806
原文:https://www.fullstackreact.com/30-days-of-react/day-25/
今天,我們將看看一個(gè)由Airbnb所維護(hù)的開源庫(kù),名為Enzyme,使得測(cè)試變得簡(jiǎn)單易用。
昨天我們使用了react-addons-test-utils 庫(kù)來(lái)編寫我們對(duì)Timeline 組件的第一個(gè)測(cè)試。但是, 此庫(kù)是相當(dāng)?shù)图?jí)的, 使用起來(lái)可能有點(diǎn)麻煩。Enzyme是由 AirBnb 團(tuán)隊(duì)發(fā)布和維護(hù)的測(cè)試實(shí)用程序庫(kù), 它提供了一個(gè)更好的、高級(jí)的 API 來(lái)處理測(cè)試中的React組件。
我們?cè)跍y(cè)試我們的
我們將使用Enzyme, 使這些測(cè)試更容易寫和更可讀。
昨天, 我們寫了我們的第一個(gè)測(cè)試如下:
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(); TestUtils .findRenderedDOMComponentWithClass(wrapper, "notificationsFrame"); }); })
雖然這是可行的, 但它不是世界上最容易閱讀的測(cè)試。當(dāng)用Enzyme我們重寫它時(shí)讓我們看看這個(gè)測(cè)試的樣子。
我們可以只測(cè)試組件的輸出, 而不是用Enzyme來(lái)測(cè)試完整的組件樹。將不渲染任何組件的子級(jí)。這稱為 淺 渲染。
Enzyme使淺渲染超容易。我們將使用Enzyme導(dǎo)出的shallow 函數(shù)來(lái)裝載我們的組件。
讓我們更新src/components/Timeline/__tests__/Timeline-test.js 文件, 包括從 enzyme導(dǎo)入shallow 函數(shù):
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也支持淺渲染。事實(shí)上, Enzyme素只是包裝這個(gè)函數(shù)。雖然昨天我們沒有使用淺渲染, 但如果我們使用它看起來(lái)像這樣:
> const renderer = ReactTestUtils.createRenderer(); > renderer.render() > const result = renderer.getRenderOutput(); >
現(xiàn)在, 為了渲染我們的組件, 我們可以使用shallow 方法并將結(jié)果存儲(chǔ)在一個(gè)變量中。然后, 我們將為在其虛擬 dom 中渲染的不同的React元素 (HTML 或子組件) 查詢 渲染的組件。
整個(gè)斷言包括兩行:
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(); expect(wrapper.find(".notificationsFrame").length).toEqual(1); }); it("has a title of Timeline", () => { wrapper = mount( ) expect(wrapper.find(".title").text()).toBe("Timeline") }) describe("search button", () => { let search; beforeEach(() => wrapper = mount( )) 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( ) expect( wrapper.find("ActivityItem").length ).toBeGreaterThan(3) }) }) })
我們可以使用yarn test命令 (或 npm test 命令) 一樣的方式運(yùn)行測(cè)試:
yarn test
我們的測(cè)試通過, 并且更易于閱讀和維護(hù)。
讓我們繼續(xù)寫斷言, 從我們昨天開始的假設(shè)列表中抽取。我們將首先構(gòu)建我們的測(cè)試套件的其余部分, 寫出我們的describe 和it 塊。我們將填寫的規(guī)格與斷言后:
import React from "react"; import { shallow } from "enzyme"; import Timeline from "../Timeline"; describe("Timeline", () => { let wrapper; it("wraps content in a div with .notificationsFrame class", () => { wrapper = shallow(); 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") }) })
如果我們遵循測(cè)試驅(qū)動(dòng)開發(fā) (簡(jiǎn)稱 TDD), 我們將首先編寫這些假設(shè), 然后構(gòu)建組件以通過這些測(cè)試。
讓我們填寫這些測(cè)試, 以便它們通過我們現(xiàn)有的Timeline 組件。
我們的標(biāo)題測(cè)試比較簡(jiǎn)單。我們將查找標(biāo)題元素并確認(rèn)標(biāo)題為Timeline。
我們希望標(biāo)題可以在 .title類下使用。因此, 要在規(guī)范中使用 .title 類, 我們只需使用Enzyme所暴露的find 函數(shù)即可獲取組件。
因?yàn)槲覀兊?b>Header組件是 Timeline 組件的子組件, 所以不能使用shallow() 方法。相反, 我們必須使用Enzyme提供的 mount() 方法。
Shallow? Mount?shallow() 渲染函數(shù)只渲染我們專門測(cè)試的組件, 它不會(huì)渲染子元素。相反, 我們將不得不mount() 組件, 因?yàn)樽咏M件Header 不可用的 jsdom, 否則。
我們將在本文的末尾看到更多的Enzyme函數(shù)。
現(xiàn)在讓我們填寫標(biāo)題描述:
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(); expect(wrapper.find(".notificationsFrame").length).toEqual(1); }); it("has a title of Timeline", () => { wrapper = mount( ) // notice the `mount` expect(wrapper.find(".title").text()).toBe("Timeline") }) })
運(yùn)行我們的測(cè)試, 我們將看到這兩個(gè)期望通過:
接下來(lái), 讓我們更新我們的搜索按鈕測(cè)試。我們?cè)谶@里有兩個(gè)測(cè)試, 其中一個(gè)要求我們測(cè)試一個(gè)交互。Enzyme為處理相互作用提供了一個(gè)非常干凈的界面。讓我們來(lái)看看如何根據(jù)搜索圖標(biāo)編寫測(cè)試。
同樣, 由于我們?cè)跁r(shí)間軸中對(duì)子元素進(jìn)行測(cè)試, 因此我們必須mount() 元素。因?yàn)槲覀円谝粋€(gè)嵌套的describe()塊中編寫兩個(gè)測(cè)試, 所以我們可以在幫助器之前編寫一個(gè)新的 mount() 來(lái)為每個(gè)測(cè)試重新創(chuàng)建, 這樣它們是純的。
此外, 我們還將使用 input.searchInput 元素進(jìn)行兩個(gè)測(cè)試, 因此, 讓我們?cè)谇懊娴膸椭髦袨樵撛鼐帉?b>.find() 。
describe("Timeline", () => { let wrapper; // ... describe("search button", () => { let search; beforeEach(() => wrapper = mount()) beforeEach(() => search = wrapper.find("input.searchInput")) // ... }) })
若要測(cè)試是否隱藏了搜索輸入, 我們只需要知道是否應(yīng)用了active 類。Enzyme為我們提供了一種使用 hasClass() 方法檢測(cè)組件是否有類的方法。讓我們填寫第一個(gè)測(cè)試, 期望搜索輸入沒有活動(dòng)類:
describe("Timeline", () => { let wrapper; // ... describe("search button", () => { let search; beforeEach(() => wrapper = mount()) beforeEach(() => search = wrapper.find("input.searchInput")) it("starts out hidden", () => { expect(search.hasClass("active")).toBeFalsy() }) it("becomes visible after being clicked on") // ... }) })
關(guān)于第二個(gè)測(cè)試的棘手部分是, 我們需要點(diǎn)擊圖標(biāo)元素。在我們看如何做到這一點(diǎn)之前, 讓我們先找到它。我們可以在包裝上的目標(biāo)通過它的 .searchIcon 類定位到它。
it("becomes visible after being clicked on", () => { const icon = wrapper.find(".searchIcon") })
現(xiàn)在, 我們有了圖標(biāo), 我們想模擬一個(gè)點(diǎn)擊元素。回想一下, onClick() 方法實(shí)際上只是瀏覽器事件的門面。即, 單擊一個(gè)元素只是一個(gè)通過組件冒泡的事件。而不是控制鼠標(biāo)或調(diào)用元素上的click , 我們將模擬發(fā)生在它上的事件。對(duì)我們來(lái)說, 這將是click 事件。
我們將在icon 上使用simulate() 方法來(lái)創(chuàng)建此事件:
it("becomes visible after being clicked on", () => { const icon = wrapper.find(".searchIcon") icon.simulate("click") })
現(xiàn)在我們可以設(shè)定一個(gè)search 組件具有active 類的期望。
it("becomes visible after being clicked on", () => { const icon = wrapper.find(".searchIcon") icon.simulate("click") expect(search.hasClass("active")).toBeTruthy() })
我們對(duì)Timeline 組件的最后期望是至少有四狀態(tài)更新。當(dāng)我們將這些元素放置在Timeline 組件上時(shí), 我們可以 "淺" 渲染組件。此外, 由于每個(gè)元素都是自定義組件, 因此我們可以搜索"ActivityItem"類型的特定組件的列表。
describe("status updates", () => { it("has 4 status updates at minimum", () => { wrapper = shallow() // ... }) })
現(xiàn)在, 我們可以測(cè)試ActivityItem 組件列表的長(zhǎng)度。我們將設(shè)定我們的期望, 如果長(zhǎng)度至少是4的名單。
describe("status updates", () => { it("has 4 status updates at minimum", () => { wrapper = shallow() expect( wrapper.find("ActivityItem").length ).toBeGreaterThan(3) }) })
我們現(xiàn)在的整個(gè)測(cè)試套件如下所示:
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([](#whats-the-deal-with-find)find()處理什么?); expect(wrapper.find(".notificationsFrame").length).toEqual(1); }); it("has a title of Timeline", () => { wrapper = mount( ) expect(wrapper.find(".title").text()).toBe("Timeline") }) describe("search button", () => { let search; beforeEach(() => wrapper = mount( )) 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( ) expect( wrapper.find("ActivityItem").length ).toBeGreaterThan(3) }) }) })
在我們結(jié)束今天之前, 我們應(yīng)該看看一個(gè)Enzyme"渲染的界面 (在我們的測(cè)試中, wrapper 的對(duì)象)。Enzyme文檔 太棒了, 所以我們要保持這個(gè)簡(jiǎn)短。
基本上, 當(dāng)我們使用find() 函數(shù)時(shí), 我們會(huì)將它傳遞給一個(gè)選擇器, 它將返回一個(gè)ShallowWrapper 實(shí)例來(lái)包裝找到的節(jié)點(diǎn)。find() 函數(shù)可以取字符串、函數(shù)或?qū)ο蟆?/p>
當(dāng)我們將字符串傳遞給find()函數(shù)時(shí), 我們可以傳遞 CSS 選擇器或組件的 _顯示名稱_。例如:
wrapper.find("div.link"); wrapper.find("Link")
我們還可以將它傳遞給組件構(gòu)造函數(shù), 例如:
import { Link } from "react-router"; // ... wrapper.find(Link)
最后, 我們還可以傳遞對(duì)象屬性選擇器對(duì)象, 它通過鍵和值來(lái)選擇元素。例如:
wrapper.find({to: "/login"});
返回值是一個(gè) ShallowWrapper, 它是一種ShallowWrapper類型 (我們可以渲染包裝和淺包裝)。這些 Wrapper 實(shí)例有一組功能, 我們可以使用這些函數(shù)來(lái)針對(duì)不同的子組件, 查看 props 和 state,的方法, 以及渲染的組件的其他屬性, 如html()和text()。更甚的是, 我們可以把這些調(diào)用串在一起。
以 組件為例。如果我們想找到基于所有可用鏈接的鏈接類的 HTML, 我們可以編寫這樣的測(cè)試:
// ... it("displays a link tag with the Login text", () => { link = wrapper .find("Link") .find({to: "/login"}) expect(link.html()) .toBe("Login") });
哦!今天有很多新的信息, 但是看看我們是如何快速地用Enzyme來(lái)編寫后續(xù)測(cè)試的。閱讀的速度要快得多, 而且更容易辨別實(shí)際發(fā)生的事情。
明天, 我們將繼續(xù)我們的測(cè)試旅程和通過集成測(cè)試測(cè)試我們的應(yīng)用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/87161.html
摘要:今天我們將討論創(chuàng)建組件的最終方案,即無(wú)狀態(tài)函數(shù)的純組件。今天我們正在研究一種處理提出的復(fù)雜數(shù)據(jù)的方法,稱為體系結(jié)構(gòu)。第天部署介紹今天,我們將探討部署我們的應(yīng)用所涉及的不同部分,以便外界可以使用我們的應(yīng)用。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3758原文:https://www.fullstackreact.com/3...
摘要:我們將討論三種不同的軟件測(cè)試范例單元測(cè)試功能測(cè)試和集成測(cè)試。在中單元測(cè)試通常不需要瀏覽器可以快速運(yùn)行不需要寫入斷言本身通常是簡(jiǎn)單而簡(jiǎn)潔的。集成測(cè)試最后我們將研究的最后一種測(cè)試是集成測(cè)試。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3809原文:https://www.fullstackreact.com/30-days-of...
摘要:包包含由團(tuán)隊(duì)提供的測(cè)試實(shí)用程序。將在一個(gè)名為的目錄中自動(dòng)查找整個(gè)樹中的測(cè)試文件是的帶有下劃線。讓我們?yōu)闀r(shí)間軸組件創(chuàng)建第一個(gè)測(cè)試。其中之一是命令?,F(xiàn)在我們已經(jīng)編寫了第一個(gè)測(cè)試并確認(rèn)了我們的設(shè)置我們將在明天開始測(cè)試我們的時(shí)間軸組件。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3807原文:https://www.fullstac...
摘要:我們的第一個(gè)假設(shè)是非常簡(jiǎn)單的測(cè)試。我們正在測(cè)試以確保元素被包裝在類中。在我們編寫的每個(gè)測(cè)試中我們都需要將應(yīng)用呈現(xiàn)在工作測(cè)試文檔中。作為提醒我們可以使用命令或命令來(lái)運(yùn)行測(cè)試。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3804原文:https://www.fullstackreact.com/30-days-of-react/...
摘要:今天我們將討論創(chuàng)建組件的最終方案,即無(wú)狀態(tài)函數(shù)的純組件。為了獲得更多的性能和簡(jiǎn)單性,同樣允許我們使用正常的函數(shù)創(chuàng)建純粹的,無(wú)狀態(tài)的組件。在中,功能組件被稱為一個(gè)參數(shù)的類似于構(gòu)造函數(shù)類,它們是它所調(diào)用的,以及組件樹的當(dāng)前。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3819原文:https://www.fullstackrea...
閱讀 3463·2023-04-26 01:46
閱讀 3031·2023-04-25 20:55
閱讀 5627·2021-09-22 14:57
閱讀 3035·2021-08-27 16:23
閱讀 1776·2019-08-30 14:02
閱讀 2130·2019-08-26 13:44
閱讀 703·2019-08-26 12:08
閱讀 3194·2019-08-26 11:47