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