React-Testing library not rendering Material-UI Dialog in snapshot
export default function CommentDialog(props) {
const {
approvalValue,
handleSubmit,
handleDialog,
handleChange,
handleApprovalChange,
value,
characterCount,
maxCharacterValue,
} = props;
const { handleOpen, handleClose, open } = handleDialog;
const classes = useStyles();
return (
<>
<AddCommentButton onClick={handleOpen} />
<Dialog fullWidth onClose={handleClose} aria-labelledby="customized-dialog-title" open={open}>
<DialogTitle id="customized-dialog-title" onClose={handleClose}>
Please select an outcome for this Targeting Request
</DialogTitle>
<RadioGroup
aria-label="quiz"
name="quiz"
value={approvalValue}
onChange={handleApprovalChange}
className={classes.radioButtons}
>
<FormControlLabel value="Approved" control={<Radio color="primary" />} label="APPROVE" />
<FormControlLabel value="Denied" control={<Radio color="secondary" />} label="DENY" />
</RadioGroup>
<DialogContent>
<MarkdownEditor
id="comment-markdown"
error={characterCount >= maxCharacterValue && MAX_CHARACTER_MSG}
value={value}
onChange={handleChange}
label="Please enter your comments"
/>
</DialogContent>
<Divider />
<DialogActions className={classes.bottomDiv}>
<TextField
disableUnderline
id="max-character-counter"
label="Maximum Characters"
InputProps={{
readOnly: true,
}}
value={`${characterCount}/${maxCharacterValue}`}
disabled
error={characterCount >= maxCharacterValue && MAX_CHARACTER_MSG}
/>
<div>
<Button
disabled={(approvalValue === 'Denied' && value === '') || approvalValue === ''}
onClick={handleSubmit}
color="primary"
>
Submit
</Button>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
</div>
</DialogActions>
</Dialog>
</>
);
}
it('onChange called on type in markdown box', async () => {
const { container } = render(<CommentDialog {...modifiedProps} />);
expect(container).toMatchSnapshot();
});
Expected behaviour: The button and the dialog are rendered Actual behaviour: The button alone is rendered.
This render is only rendering the button at the top of the component. The open value spread from handleDialog is true, therefore the dialog should be open, but on my snapshot it only shows the button.
I don't think it's to do with anything asynchronous and it firing before something has loaded. I have using JSDOM 16 and Jest to run the tests.
See also questions close to this topic
-
How can I filter 2 object arrays in React?
const obj1 = [{'food': ['apple', 'banana'], 'drink': ['wine', 'juice']}]; const obj2 = [{'food': ['apple'], dummy: 'test', 'drink':['wine', 'juice']}, {'food': 'banana', dummy: 'test', 'drink':['juice']}, {'food': ['apple', 'banana'], dummy: 'test'},'drink':['juice']} ];
if there's two object arrays, how can I filter obj1 on obj2? What I'm going to do is
if obj1 has same value with obj2, leave obj2's objects that contains same value with obj1.
set the state with those remained objects.
this is how I tried.
the problem of this logic is
returned value contains only filtered value.
ex) {food:['banana]}
but It has to return all object that contain 'banana', not only 'banana'.
(so that I can set State with filtered result)//key arg is recived key from outside. (it should be 'food' or 'drink') //and filtered arg is obj1 const showFilteredRes = (filtered, key) => { let filteredRes = {}; obj2.forEach((obj2) => { for (let filters in filtered) { for (let infos in obj2) { if (filters === infos) { filteredRes[infos] = obj2[key]; console.log(filteredRes); } } } }); };
how can I develop this code?
-
Material-UI FAB animation between icon and extended variant
Suppose I have a Material-UI FAB that's code looks like this:
<Fab size="medium" color="primary" aria-label="add"> <AddIcon /> </Fab>
I have a controlled way to toggle between this other state:
<Fab variant="extended" size="medium" color="primary" aria-label="add" > <NavigationIcon/> Extended </Fab>
My question is how do I achieve some kind of animation between these two states? I'm thinking of a way when the FAB expands, instead of suddenly displaying the text. I can't figure it out, any help is appreciated.
-
React-Datepicker layout broken inside a Bootstrap-React Modal (calendar truncated)
I'm using React Datepicker inside a Bootstrap React Modal dialog.
Getting the following layout issue when clicking the text box to open the calendar:
The basic code is this:
<Modal show={this.state.isDialogOpenB} onHide={this.handleDialogCloseB}> <Modal.Header closeButton> <Modal.Title>Editing UserID: {this.state.activeItemIdB} Username: {this.state.activeItemNameB}</Modal.Title> </Modal.Header> <Modal.Body> <div class="custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input" id="bChkboxLocked"></input> <label class="custom-control-label" htmlFor="bChkboxLocked">Locked</label> </div> <div> <DatePicker dateFormat="MM/dd/yyyy" selected={this.state.testDate} onChange={this.handleDatePickerChangeB} /> </div> </Modal.Body> <Modal.Footer> <Button variant="secondary" onClick={this.handleDialogCloseB}> Close </Button> </Modal.Footer> </Modal>
-
Testing vue 3 async setup
I can't quite figure out how to test my async setup vue 3 component.
<script> import { someRepository } from "@/repositories" import { onMounted, toRefs } from 'vue' export default { name: 'HelloWorld', props: { msg: String }, async setup(props) { const { msg } = toRefs(props) console.log(await someRepository.get()) return { msg } } } </script>
Wrapping this component with a
Suspense
component works as expected. However when running tests:import { someRepository } from "@/repositories" import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' jest.mock("@/repositories", () => { return { someRepository: { get: jest.fn() } } }) describe('HelloWorld.vue', () => { beforeEach(() => { someRepository.get.mockImplementation(() => Promise.resolve("asdasd")) }); it('renders props.msg when passed', () => { const msg = 'new message' const wrapper = mount(HelloWorld, { props: { msg } }) expect(wrapper.text()).toMatch(msg) }) }
This will throw an error
TypeError: Cannot read property 'addEventListener' of null
on theshallowMount
ormount
. I've also tried making them async but that also doesn't work throwing the same error.The only solution is using
onMounted
hook. But that's not how Suspense is supposed to be used. Any ideas? Or is this simply not yet supported? -
How to use jest to mock a function just for some specified arguments, but uses its original logic for any other arguments?
Say I have a function:
function complexCompute(num: number): string { switch(num) { case 1: return '...something...'; case 2: return '...something...'; case 3: return '...something...'; // more cases }
It is used many times in the code I want to test, but I want to mock it like this:
- when I pass the argument
num
is1
,complexCompute
returns my mocked stringmy-mock-string1
- when I pass any other argument, it uses its original logic
I can't find a way to do it, since if I mocked the module:
jest.mock('./complexCompute')
The mocked
complexCompute
doesn't have original logic. I have to define the mock value for argument1
, and also rewrite the whole logic for other arguments.Is there any way to do it?
- when I pass the argument
-
Jest ReferenceError: You are trying to `import` a file after the Jest environment has been torn down
I am trying to test my APIs using jest.
I am having this error show after each time I run the tests
PASS test/auth.test.js √ Create a new user (237 ms) √ SignIn with user (133 ms) √ Delete The user (144 ms) Test Suites: 1 passed, 1 total Tests: 3 passed, 3 total Snapshots: 0 total Time: 2.173 s, estimated 8 s Ran all test suites. ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
my test file
const auth = require("../routes/auth"); const fetch = require('node-fetch'); fetch.Promise = require("bluebird"); (async () => { beforeAll(done =>{ jest.useFakeTimers(); done(); }) afterAll(done => { done(); }) jest.setTimeout(10000) test("Create a new user", async () => { const status = await fetch(URL + "/api/auth/signUp", { method:"POST", headers: { 'Content-Type': 'application/json;charset=utf-8' }, body:JSON.stringify(SignUpReq) }) .then(res => res.status) await expect(status).toBe(201); }) test("SignIn with user", async () => { let status = await fetch(URL + "/api/auth/signin", { method:"POST", headers: { 'Content-Type': 'application/json;charset=utf-8' }, body:JSON.stringify(deleteUserReq) }) .then(res => res.status) await expect(status).toBe(200); }) test("Delete The user", async () => { const status = await fetch(URL + "/api/auth/deleteUser", { method:"DELETE", headers: { 'Content-Type': 'application/json;charset=utf-8', 'Authorization': 'Bearer <token>' }, body:JSON.stringify(deleteUserReq) }) .then(res => res.status) await expect(status).toBe(200); }) })()
The APIs test the actual database, not a mock DB
I tried
mongoose.connection.close()
jest.useFakeTimers();
changing jest timeout
adding done before and after all
using await before each expect
still, the error shows up
my env:
"node": "V12.19.0" "bcrypt": "^5.0.0", "bluebird": "^3.7.2", "cors": "^2.8.5", "express": "^4.17.1", "jsonwebtoken": "^8.5.1", "md5": "^2.3.0", "mongoose": "^5.11.8", "node-fetch": "^2.6.1", "jest": "^26.6.3"
my DB is hosted on mongo atlas
How can I remove this error message?
-
Module not found: Error: Can't resolve '@material-ui/icons/Facebook' .This is something different
Every material ui icon was perfectly working on localhost but when I tried to pull changes on the real server it showed me this error while sudo npm run build. Please help if you know anything about this problem
-
Getting the value of an uncontrolled Material UI TextField
From the documentation, it describes having an uncontrolled field by omitting the
value
andonChange
attribute. The React website says to use aref
on any uncontrolled inputs, but doing this with a TextField only refs its container, a div. What is the recommended way of retrieving the value of an uncontrolled TextField in Material UI? I could use aquerySelector
to find the element, but that doesn't seem like a proper way. -
Error: Uncaught [TypeError: Cannot read property 'map' of undefined] react testing library
I've written some tests in react testing library on typescript. The tests past successfully but there are errors in the console that I cannot decipher, can someone help me out please. It happens after I have updated my test at the very end of the test. The component inputs the value
ohio
into a field and returns data based on that value, I'm mocking this in the test.the test I'm referring to is the
lands on the page and searches by state
after this line runs:act(() => { fireEvent.click(getByText("Sort")); }) expect(axiosMock.get).toHaveBeenCalledTimes(2);
the api is triggered on submit of the
Sort
button and the tests passes but it leaves a nasty error. Can someone explain this to me please?Here is my test file and the component I'm testing:
component - 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;
test file - 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 - for mocking the api
export default { get: jest.fn().mockResolvedValue({ data: [{}] }), };
test 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" }, ]
the error returned when I run the
lands on the page and searches by state
testError: 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)
-
How to test react functional component async call
I have a functional component. Inside the component, I have called SpecialistsListService service. The service called the API via Axios. I have to test the async function getSpecialistsList and useEffect functions but I don't do that anyone helps me to solve the problem. When I used class component I simply call the method like await wrapper.instance.getSpecialistsList() then check the state but the functional component approach are different I think.
import React, { useState, useEffect } from "react"; import SpecialistsListService from "../../../services/specialists"; import SpecialistsPageView from "./SpecialistsPageView"; import "./index.scss"; export default function SpecialistsPage() { const [specialistsList, setSpecialistsList] = useState([]); const [isLoading, setIsLoading] = useState(true); const specialistsListService = new SpecialistsListService(); useEffect(() => { getSpecialistsList(); }, []); async function getSpecialistsList() { const specialistsListData = await specialistsListService.getSpecialistsList(); setSpecialistsList(specialistsListData); setIsLoading(false); } return ( <SpecialistsPageView isLoading={isLoading} specialists={specialistsList} /> ); }
-
Fire click event twice in react-testing-library
I'm trying to test if a button toggle works as expected.
This is my code.
<> <IconButton color="secondary" data-testid="HelpIconButton" ref={anchorRef} onClick={handleToggle}> <Help /> </IconButton> <Popper {...{ open }} anchorEl={anchorRef.current} transition disablePortal data-testid="HelpIconPopper"> {({ TransitionProps, placement }) => ( <Grow {...TransitionProps} style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}> <Paper> <ClickAwayListener onClickAway={handleClose}> <MenuList autoFocusItem={open} onKeyDown={handleListKeyDown}> {menuItems.map(({ onClick, label }, index) => ( <MenuItem key={index} {...{ onClick }}> {label} </MenuItem> ))} </MenuList> </ClickAwayListener> </Paper> </Grow> )} </Popper> </>
In the browser, clicking the browser works as expected. Clicking on the
IconButton
toggles thePopper
, removing and adding it into the DOM. On test however, firing a click event placed thePopper
in the DOM but its not removed when fired again. Hence, the popper isn't toggled.Here is the test Code.
it('Ensures the help menu toggles when the help button is clicked.', () => { const { getByTestId, queryByTestId } = render(<HelpButton />); expect(queryByTestId('HelpIconPopper')).not.toBeInTheDocument(); fireEvent.click(getByTestId('HelpIconButton')); expect(queryByTestId('HelpIconPopper')).toBeInTheDocument(); fireEvent.click(getByTestId('HelpIconButton')); expect(queryByTestId('HelpIconPopper')).not.toBeInTheDocument(); });
A work around currently in use is using
fireEvent.doubleClick
it('Ensures the help menu toggles when the help button is clicked.', () => { const { getByTestId, queryByTestId } = render(<HelpButton />); expect(queryByTestId('HelpIconPopper')).not.toBeInTheDocument(); fireEvent.doubleClick(getByTestId('HelpIconButton')); expect(queryByTestId('HelpIconPopper')).not.toBeInTheDocument(); });
The second test passes.