Next.js參加了開發課程,該課程使該圖書館過時採用了測試方法。下一頁測試器維護者建議使用瀏覽器測試。
Next.js的缺少DOM集成測試工具
給定下一個庫路由,此庫將在JSDOM中渲染匹配頁面,並提供從Next.js的路由系統和數據獲取方法得出的預期道具。
import { getPage } from 'next-page-tester' ;
import { screen , fireEvent } from '@testing-library/react' ;
describe ( 'Blog page' , ( ) => {
it ( 'renders blog page' , async ( ) => {
const { render } = await getPage ( {
route : '/blog/1' ,
} ) ;
render ( ) ;
expect ( screen . getByText ( 'Blog' ) ) . toBeInTheDocument ( ) ;
fireEvent . click ( screen . getByText ( 'Link' ) ) ;
await screen . findByText ( 'Linked page' ) ;
} ) ;
} ) ; 該庫背後的想法是盡可能地與接下來的方式相關。 JS在不啟動服務器的情況下工作,並在本地JSDOM環境中渲染輸出。
為了提供有價值的測試經驗next-page-tester複製了實際next.js應用程序:
head元素)安裝的應用程序是交互式的,可以使用任何DOM測試庫進行測試(例如@testing-library/react )。
next-page-tester將會照顧:
getServerSideProps , getInitialProps或getStaticProps )_app和_document組件包裝頁面Link , router.push , router.replace模擬客戶端導航redirect返回next/router , next/head , next/link , next/config和環境變量 getPage接受選項對象並返回4個值:
import { getPage } from 'next-page-tester' ;
const { render , serverRender , serverRenderToString , page } = await getPage ( {
options ,
} ) ; type : () => { nextRoot: HTMLElement<NextRoot> }
返回: #__next next根元素。
除非您有高級用例,否則您應該主要使用此方法。在引擎蓋下,它調用serverRender() ,然後將React應用程序安裝/水合到JSDOM #__next root Element中。這是用戶訪問頁面時會得到/看到的。
type : () => { nextRoot: HTMLElement<NextRoot> }
返回: #__next next根元素。
將服務器端的輸出渲染到DOM中,但不會安裝反應。使用它來測試下一步的方式。 JS在以下情況下呈現:
type : () => { html: string }
將服務器端的輸出渲染為HTML字符串。這是一種沒有副作用的純方法。
類型: React.ReactElement<AppElement>
應用程序的反應元素。
| 財產 | 描述 | 類型 | 預設 |
|---|---|---|---|
| 路線(強制性) | 下一個路線(必須以/開始) | string | - |
| req | 增強默認模擬請求對象 | req => req | - |
| res | 增強默認模擬的響應對象 | res => res | - |
| 路由器 | 增強默認模擬的下一個路由器對象 | router => router | - |
| useapp | 渲染自定義應用程序組件 | boolean | true |
| 渲染文檔組件 | boolean | false | |
| Nextroot | 絕對通往Next的路徑。 JS根文件夾 | string | 自動檢測到 |
| dotenvfile | .env文件保存環境變量的相對路徑 | string | - |
| 包裝紙 | 包裝器文件的絕對路徑。對於用模擬的提供商裝飾組件樹有用。 | string | - |
| 共享模型 | 應保留客戶端和服務器上下文之間身份的模塊列表。 | string[] | [] |
如果您的頁面/組件導入文件類型不是Node.js本地處理的(例如樣式表,圖像, .svg ,...),則應配置測試環境以正確處理它們。例如,如果開玩笑,您可能想配置一些moduleNameMapper 。
next-page-tester希望遇到JSDOM環境。如果使用開玩笑將這一行添加到您的jest配置:
"testEnvironment" : "jsdom" ,由於Next.js並非旨在在JSDOM環境中運行,因此我們需要設置默認的JSDOM ,以允許更平穩的測試體驗。默認情況下, next-page-tester將:
window.scrollTo和IntersectionObserver模擬但是,您可以選擇通過將NPT_SKIP_AUTO_SETUP ENV變量設置為true來跳過自動清理和幫助者的初始化。您可以像這樣cross-env做:
cross - env NPT_SKIP_AUTO_SETUP = true jest如果使用Jest V26,則可能需要修補它,以便使用適當的服務器/客戶端環境加載模塊。維護工作將針對最新的開玩笑版本。
在示例文件夾下,我們正在記錄next-page-tester啟用的測試案例。
next-page-tester只著眼於僅支持Next.js和Jest的最後一個版本:
| 下一頁 - 塔斯特 | next.js | 笑話 |
|---|---|---|
| V0.1.0-> V0.7.0 | v9.xx | v26.xx |
| V0.8.0-> V0.22.0 | V10.0.0-> v10.0.7 | |
| V0.23.0-> v0.25.x | v10.0.8-> v11.0.x | |
| V0.26.0-> v0.27.x | v10.0.8-> v11.0.x | v27.xx |
| V0.28.0-> V0.28.x | V11.1.0 | |
| V0.29.0 + | v11.1.1-> v11.x | |
| V0.31.0 + | v12.1.0 | |
| V0.32.0 + | v12.1.1 + |
自從:
請注意,我們不能保證支持Next.js的未來版本的支持。即使是補丁或次要版本也可能會破壞。在這種情況下,您必須等待發布新的next-page-tester版。
貢獻非常歡迎,我們會盡力支持外部貢獻者。
req和res對像是用節點莫克斯-HTTP模擬的strict模式下使用TypeScript時,可能有必要安裝@types/react-dom和@types/webpackuseDocument選項useDocument選項是部分實現的,可能是不穩定的。
模擬網絡請求的第一種建議方法是與Mock service worker和Mirage JS等庫在網絡層進行模擬。
另一種可行的方法可能包括用諸如fetch-mock之類的庫模擬全局fetch對象。
如果您想要一種更傳統的方法,涉及嘲笑負責獲取數據的用戶陸地模塊,則需要考慮一個額外的步驟:由於“客戶端”和“服務器”渲染之間的next-page-tester隔離隔離了模塊,因此在測試(客戶端上下文)中創建的模擬(例如,在服務器上下文中都無法執行)(例如,數據獲取方法)。
為了克服這一問題,我們需要通過通過sharedModules選項傳遞“客戶端”和“服務器”上下文之間的“污染”此類模塊以在“客戶端”和“服務器”上下文之間的身份。
test ( 'as a user I want to mock a module in client & server environment' , async ( ) => {
const stub = jest . spyOn ( api , 'getData' ) . mockReturnValue ( Promise . resolve ( 'data' ) )
const { render } = await getPage ( {
route : '/page' ,
nextRoot ,
sharedModules : [ ` ${ process . cwd ( ) } /src/path/to/my/module` ] ,
} ) ;
expect ( stub ) . toHaveBeenCalledTimes ( 1 ) ; // this was executed in your data fetching method
}您可以通過將cookie附加到document.cookie來設置getPage 。 next-page-tester將將cookie傳播到ctx.req.headers.cookie ,以便它們可用於數據獲取方法。這也適用於隨後的獲取方法由客戶端導航觸發的調用。
test ( 'authenticated page' , async ( ) => {
document . cookie = 'SessionId=super=secret' ;
document . cookie = 'SomeOtherCookie=SomeOtherValue' ;
const { render } = await getPage ( {
route : '/authenticated' ,
} ) ;
render ( ) ;
} ) ;注意: document.cookie不會自動清理。每次測試後,您都必須手動清除它,以使所有內容保持孤立。
next.js Link組件調用window.scrollTo在單擊時,該crollto在JSDOM環境中未實現。為了解決錯誤,您應該設置測試環境或提供自己的window.scrollTo 。
此警告意味著您的頁面在服務器和瀏覽器之間呈現不同。這可以是預期的行為,也可以是您代碼中的錯誤。
此警告意味著您在渲染過程中的應用程序執行了一些尚未嘲笑的網絡請求。您應該找到它們並根據需要進行模擬。
trailingSlash選項_error頁面debug選項來記錄執行信息謝謝這些好人(表情符號鑰匙):
安德里亞·卡拉羅(Andrea Carraro) ? | Matejšnuderl ? | 傑森·威廉姆斯 ? | Arelaxend ? | kfazinic ? | Tomasz Rondio ? | 亞歷山大·門德斯(Alexander Mendes) |
Jan Sepke ? | Davidorchard ? | doaa ismael ? | 安德魯·赫爾(Andrew Hurle) ? | Massimeddu-Sonic ? | 傑西·特爾福德(Jess Telford) ? | 約瑟夫 ? |
Gergo Tolnai ? | 布雷特 ? | 弗拉德·伊拉金 | 丹尼爾·斯托克曼(Daniel Stockman) | Madeuz | 德里克·奧斯丁博士 ? | feargal ? |
Jan R. Biasi ? | OtávioAugusto Soares ? |
該項目遵循全企業規範。歡迎任何形式的貢獻!