我在打字稿的反应测试库中编写了一些测试。测试成功通过,但控制台中有我无法破译的错误,有人可以帮助我吗?它发生在我在测试结束时更新我的测试之后。组件将值 ohio
输入一个字段并根据该值返回数据,我在测试中对此进行了模拟。
我所指的测试是此行运行后的 lands on the page and searches by state
:
act(() => {
fireEvent.click(getByText("Sort"));
})
expect(axiosMock.get).toHaveBeenCalledTimes(2);
api 在 Sort
按钮提交时触发,测试通过,但留下了令人讨厌的错误。有人可以向我解释一下吗?
这是我的测试文件和我正在测试的组件:
组件 - Brewerlist.tsx :
import React, { useEffect, useState } from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import queryString from 'query-string';
import beer from '../assets/beerMug.png';
import axios from 'axios';
import Pagination from './Pagination';
import '../App.css';
type Breweries = {
id: number;
name: string;
brewery_type: string;
state: string;
city: string;
country: string;
street: string;
}
function Brewerlist() {
const [breweries, setBreweries] = useState<Breweries[]>([]);
const [error, setError] = useState<any>(null);
const [sortType, setSortType] = useState<string>("");
const [sortValue, setSortValue] = useState<string>("");
const [sortValueEmpty, setSortValueEmpty] = useState<boolean>(false);
// const { response, error }: { response: object, error: string} = useFetch("https://api.openbrewerydb.org/breweries");
const location = useLocation();
const history = useHistory();
const path = window.location.pathname;
const url = queryString.parse(location.search);
const pageNo = Number(url.page) || 1;
const [currentPage, setCurrentPage] = useState(pageNo);
const [ordersPerPage] = useState(10);
const indexOfLastOrder = currentPage * ordersPerPage;
const indexOfFirstOrder = indexOfLastOrder - ordersPerPage;
const currentOrders = breweries?.slice(indexOfFirstOrder, indexOfLastOrder);
const paginate = (pageNumber: any) => setCurrentPage(pageNumber);
//fetch breweries
const fetchData = async () => {
try {
const res = await axios.get("https://api.openbrewerydb.org/breweries?per_page=50");
setBreweries(res?.data);
} catch (error) {
console.log(error);
}
}
useEffect(() => {
fetchData();
history.push(`${path}?page=${currentPage}`);
}, [currentPage, history, path]);
//handlers
const handleSort = (event: React.ChangeEvent<HTMLSelectElement>) => {
setSortType(event.target.value)
}
const handleSortValue = (event: React.ChangeEvent<HTMLInputElement>) => {
setSortValue(event.target.value)
}
const hideError = () => {
setSortValueEmpty(false)
}
//refresh results
const refreshResults = () => {
fetchData();
}
//fetcher function
const fetcher = async (api: string, type: string, val: string) => {
const res = await axios.get(`${api}by_${type}=${val}`);
setBreweries(res.data)
}
//fetch by term
const fetchByType = async (type: string, value: string) => {
if(sortValue === "") {
setSortValueEmpty(true)
}
if(value && type === "state"){
try {
fetcher("https://api.openbrewerydb.org/breweries?", type, value)
} catch (error) {
console.log(error);
}
}
if(type === "brewery_type") {
try {
fetcher("https://api.openbrewerydb.org/breweries?", "type", value)
} catch (error) {
console.log(error);
}
}
}
const mapBreweries = () => {
return (
<>
{currentOrders.map((item: Breweries) => (
<div className="item" key={item.id}>
<ul>
<li><span className="title">Name:</span>{item.name}</li>
<li><span className="title">State:</span>{item.state}</li>
<li><span className="title">Brewery type:</span>{item.brewery_type}</li>
<li><span className="title">Street:</span>{item.street || "N/A"}</li>
<li><span className="title">Country:</span>{item.country}</li>
<li><span className="title">City:</span>{item.city}</li>
</ul>
</div>
))}
</>
)
}
return (
<React.Fragment>
<div className="header">
<img src={beer} className="image" alt=""/>
<h1>Sherman Brewery</h1>
<img src={beer} className="image" alt=""/>
</div>
<div className="container">
<div className="selectContainer">
<label htmlFor="type">Sort by: </label>
<select name="type" data-testid="select" onChange={handleSort}>
<option value="" selected defaultValue="Sort By" disabled hidden>Sort By</option>
<option data-testid="type-option" value="state">State</option>
<option data-testid="type-option" value="brewery_type">Brewery Type</option>
</select>
<label htmlFor="sortBy">Search by {sortType === "state" ? "State: " : "Brewery Type: "} </label>
<input data-testid="search" disabled={sortType ? false : true} name="sortby" type="text" onFocus={hideError} onChange={handleSortValue} />
<button disabled={sortType ? false : true} type="submit" onClick={() => fetchByType(sortType, sortValue)}>Sort</button>
<button type="submit" onClick={refreshResults}>Refresh results</button>
{sortValueEmpty ? <span className="error"> Please add a value</span> : null}
</div>
{mapBreweries()}
<Pagination
ordersPerPage={ordersPerPage}
ordersAmount={breweries?.length}
paginate={paginate}
/>
</div>
</React.Fragment>
);
}
export default Brewerlist;
测试文件 - Brewerlist.test.js
import "@testing-library/jest-dom";
import "@testing-library/jest-dom/extend-expect";
import React from "react";
import axiosMock from "axios";
import Brewerlist from "../components/Brewerlist";
import { cleanup, render, fireEvent, waitFor } from "@testing-library/react";
import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import { fixtures } from './data';
import { ohio } from './ohioData';
import axios from "./axios";
import { act } from "react-dom/test-utils";
afterEach(cleanup);
jest.mock("axios");
let data = fixtures;
let url = "https://api.openbrewerydb.org/breweries?per_page=50";
it("lands on the page and displays data", async () => {
axiosMock.get.mockResolvedValueOnce({
data
});
const history = createMemoryHistory()
const { getByText, getByLabelText } = render(<Router history={history}><Brewerlist /></Router>);
await waitFor(() => expect(getByText("Sherman Brewery")).toBeInTheDocument());
await waitFor(() => expect(getByText("Avondale Brewing Co")).toBeInTheDocument());
expect(axiosMock.get).toHaveBeenCalledTimes(1)
});
it("lands on the page and searches by state", async () => {
axiosMock.get.mockResolvedValueOnce({
data
});
const history = createMemoryHistory()
const { getByText, getByLabelText, getAllByTestId, getByTestId } = render(<Router history={history}><Brewerlist /></Router>);
await waitFor(() => expect(getByText("Sherman Brewery")).toBeInTheDocument());
await waitFor(() => expect(getByText("Avondale Brewing Co")).toBeInTheDocument());
fireEvent.change(getByTestId("select"), { target: { value: "state" } });
let typeOptions = getAllByTestId("type-option");
expect(typeOptions[0].selected).toBeTruthy();
expect(typeOptions[1].selected).toBeFalsy();
expect(getByText("Search by State:")).toBeInTheDocument();
const searchInput = getByTestId("search");
fireEvent.change(searchInput, { target: { value: "ohio" } });
expect(searchInput.value).toBe("ohio");
axiosMock.get.mockResolvedValueOnce({
ohio
});
act(() => {
fireEvent.click(getByText("Sort"));
})
expect(axiosMock.get).toHaveBeenCalledTimes(2);
await waitFor(() => expect(getByText("Magic City Brewing Company")).toBeInTheDocument());
})
axios.js - 用于模拟 api
export default {
get: jest.fn().mockResolvedValue({
data: [{}]
}),
};
测试数据:
export const fixtures = [
{
"id":2,
"name":"Avondale Brewing Co",
"brewery_type":"micro",
"street":"201 41st St S",
"address_2":null,
"address_3":null,
"city":"Birmingham",
"state":"Alabama",
"county_province":null,
"postal_code":"35222-1932",
"country":"United States",
"longitude":"-86.774322",
"latitude":"33.524521",
"phone":"2057775456",
"website_url":"http://www.avondalebrewing.com",
"updated_at":"2018-08-23T23:19:57.825Z",
"created_at":"2018-07-24T01:32:47.255Z"
},
]
export const ohio = [
{
"id":2,
"name":"Magic City Brewing Company",
"brewery_type":"micro",
"street":"201 41st St S",
"address_2":null,
"address_3":null,
"city":"Birmingham",
"state":"Ohio",
"county_province":null,
"postal_code":"35222-1932",
"country":"United States",
"longitude":"-86.774322",
"latitude":"33.524521",
"phone":"2057775456",
"website_url":"http://www.avondalebrewing.com",
"updated_at":"2018-08-23T23:19:57.825Z",
"created_at":"2018-07-24T01:32:47.255Z"
},
]
运行 lands on the page and searches by state
测试时返回的错误
Error: Uncaught [TypeError: Cannot read property 'map' of undefined]
at reportException (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:62:24)
at innerInvokeEventListeners (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:333:9)
at invokeEventListeners (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
at HTMLUnknownElementImpl._dispatch (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
at HTMLUnknownElementImpl.dispatchEvent (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
at HTMLUnknownElement.dispatchEvent (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
at Object.invokeGuardedCallbackDev (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
at invokeGuardedCallback (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
at beginWork$1 (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
at performUnitOfWork (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:22779:12) TypeError: Cannot read property 'map' of undefined
at mapBreweries (/Users/nathan/Desktop/work/breweryapp/src/components/Brewerlist.tsx:108:26)
at Brewerlist (/Users/nathan/Desktop/work/breweryapp/src/components/Brewerlist.tsx:145:14)
at renderWithHooks (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:14985:18)
at updateFunctionComponent (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:17356:20)
at beginWork (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:19063:16)
at HTMLUnknownElement.callCallback (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:3945:14)
at HTMLUnknownElement.callTheUserObjectsOperation (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
at innerInvokeEventListeners (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:318:25)
at invokeEventListeners (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
at HTMLUnknownElementImpl._dispatch (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
at HTMLUnknownElementImpl.dispatchEvent (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
at HTMLUnknownElement.dispatchEvent (/Users/nathan/Desktop/work/breweryapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)
at Object.invokeGuardedCallbackDev (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:3994:16)
at invokeGuardedCallback (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
at beginWork$1 (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:23964:7)
at performUnitOfWork (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:22779:12)
at workLoopSync (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:22707:5)
at renderRootSync (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:22670:7)
at performSyncWorkOnRoot (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:22293:18)
at /Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:11327:26
at unstable_runWithPriority (/Users/nathan/Desktop/work/breweryapp/node_modules/scheduler/cjs/scheduler.development.js:646:12)
at runWithPriority$1 (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:11276:10)
at flushSyncCallbackQueueImpl (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:11322:9)
at flushSyncCallbackQueue (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:11309:3)
at scheduleUpdateOnFiber (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:21893:9)
at setBreweries (/Users/nathan/Desktop/work/breweryapp/node_modules/react-dom/cjs/react-dom.development.js:16139:5)
at fetcher (/Users/nathan/Desktop/work/breweryapp/src/components/Brewerlist.tsx:81:3)
at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
at reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:28)
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:333:9)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
console.error
The above error occurred in the <Brewerlist> component:
at Brewerlist (/Users/nathan/Desktop/work/breweryapp/src/components/Brewerlist.tsx:25:37)
at Router (/Users/nathan/Desktop/work/breweryapp/node_modules/react-router/cjs/react-router.js:99:30)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
at logCapturedError (node_modules/react-dom/cjs/react-dom.development.js:20085:23)
at update.callback (node_modules/react-dom/cjs/react-dom.development.js:20118:5)
at callCallback (node_modules/react-dom/cjs/react-dom.development.js:12318:12)
at commitUpdateQueue (node_modules/react-dom/cjs/react-dom.development.js:12339:9)
at commitLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:20736:11)
at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:23426:7)
at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14)