【发布时间】:2021-07-11 19:24:12
【问题描述】:
我正在尝试使用虚拟子组件测试上下文。
虚拟组件
function DefaultMockComponent() {
const values = useContext(CurrencyContext)
const valuesItems = Object.keys(values).map(value => {
if (typeof values[value] === 'function') {
return <div key={value} data-testid={value}>{value + '()'}</div>
} else {
return <div key={value} data-testid={value}>{values[value]}</div>
}
})
return(
<>
{valuesItems}
</>
)
}
上下文单元测试
// This test don't re render with the new data from fetch
it('should pass the correct values', async () => {
// This mock FAILS (see edit 2)
fetch
.mockResponse(req => {
if (/.*\/ticker\/.*/.test(req.url)) {
return new Promise(() => ({ body: JSON.stringify(tickerResponse) }))
} else if (/.*\/day-summary\/.*/.test(req.url)) {
return new Promise(() => ({ body: JSON.stringify(summaryResponse) }))
}
})
render(
<CurrencyProvider>
<DefaultMockComponent />
</CurrencyProvider>
)
await waitFor(() => expect(screen.getByTestId('currency').textContent).toBe("btc"))
await waitFor(() => expect(screen.getByTestId('volBRL').textContent).toBe("41198719.10154287"))
await waitFor(() => expect(screen.getByTestId('closing').textContent).toBe("326900.00666999"))
await waitFor(() => expect(screen.getByTestId('sell').textContent).toBe("360000.00000000"))
await waitFor(() => expect(screen.getByTestId('buy').textContent).toBe("359999.99006000"))
await waitFor(() => expect(screen.getByTestId('last').textContent).toBe("359999.99006000"))
await waitFor(() => expect(screen.getByTestId('vol').textContent).toBe("259.88030295"))
await waitFor(() => expect(screen.getByTestId('low').textContent).toBe("353684.14000000"))
await waitFor(() => expect(screen.getByTestId('high').textContent).toBe("380000.00000000"))
});
这里 fetch 是模拟的。我正在阅读 MockComponent 信息并将其与响应对象信息进行比较。我的问题是 MockComponent 仅使用默认上下文状态值呈现,如您所见:
渲染的模拟组件
<body>
<div>
<div
data-testid="high"
>
0
</div>
<div
data-testid="low"
>
0
</div>
<div
data-testid="vol"
>
0
</div>
<div
data-testid="last"
>
0
</div>
<div
data-testid="buy"
>
0
</div>
<div
data-testid="sell"
>
0
</div>
<div
data-testid="closing"
>
0
</div>
<div
data-testid="volBRL"
>
0
</div>
<div
data-testid="currency"
>
btc
</div>
<div
data-testid="setCurrency"
>
setCurrency()
</div>
</div>
</body>
这很奇怪,因为 我的赛普拉斯 E2E 测试工作正常。如何使 DefaultMockComponent 呈现从 fetch 返回的数据?
编辑 1
CurrencyContext 的CurrencyProvider
export default function CurrencyProvider({children}) {
const [currency, setCurrency] = useState('btc')
const [high, setHigh] = useState('0')
const [low, setLow] = useState('0')
const [vol, setVol] = useState('0')
const [last, setLast] = useState('0')
const [buy, setBuy] = useState('0')
const [sell, setSell] = useState('0')
const [closing, setClosing] = useState('0')
const [volBRL, setVolBRL] = useState('0')
useEffect(update, [currency])
function update() {
const ticker = `https://www.mercadobitcoin.net/api/${currency}/ticker/`
fetch(ticker)
.then(response => response.json())
.then(data => {
setHigh(data.ticker.high)
setLow(data.ticker.low)
setVol(data.ticker.vol)
setLast(data.ticker.last)
setBuy(data.ticker.buy)
setSell(data.ticker.sell)
})
const date = new Date()
date.setDate(date.getDate() - 1)
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const summary = `https://www.mercadobitcoin.net/api/${currency}/day-summary/${year}/${month}/${day}/`
fetch(summary)
.then(response => response.json())
.then(data => {
setClosing(data.closing)
setVolBRL(data.volume)
})
}
return(
<CurrencyContext.Provider value={{
high,
low,
vol,
last,
buy,
sell,
closing,
volBRL,
currency,
setCurrency
}}>
{children}
</CurrencyContext.Provider>
)
}
编辑 2
感谢lissettdm。现在 fetch 函数没有失败,但是值仍然没有更新,而且我收到“测试中的 CurrencyProvider 更新没有包含在 act(...) 中”警告。遵循有效的模拟代码:
没有 jest-fetch-mock 的模拟(作为 lissettdm 的答案)
const fetchSpy = jest.spyOn(window, "fetch").mockImplementation((req) =>
Promise.resolve({
json: () => {
if (/.*\/ticker\/.*/.test(req)) {
return tickerResponse
} else if (/.*\/day-summary\/.*/.test(req)) {
return summaryResponse
}
},
})
);
用 jest-fetch-mock 模拟
fetch
.mockResponse(req => {
if (/.*\/ticker\/.*/.test(req.url)) {
return Promise.resolve({ body: JSON.stringify(tickerResponse) })
} else if (/.*\/day-summary\/.*/.test(req.url)) {
return Promise.resolve({ body: JSON.stringify(summaryResponse) })
}
})
【问题讨论】:
-
不完全理解您的代码,但在我看来,您从未更改 CurrencyContext 中的任何内容,您只调用值。如果任何状态都没有变化,则不会导致重新渲染。
-
感谢您的评论@JoseRodrigues。我将编辑问题以包含我的上下文,因为那里的状态发生了变化。让我感到奇怪的是,相同的代码在可视化测试中有效,而在单元测试中却失败了。
-
应该
useEffect(update, [currency])去追求实际的更新功能吗? -
因为我已经用function关键字声明了update,所以我什么时候使用都没关系。我只是为了检查而进行了更改,但它失败了。谢谢。
标签: reactjs unit-testing