While I'm trying to make a test
import React from "react";
import {EventsLoadingContext} from "../../../src/components/data-admin/context/EventsLoadingContext";
import DataAdmin from "../../../src/components/data-admin/DataAdmin";
import { configure, mount, shallow } from "enzyme";
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
it("should render DataAdmin component", () => {
const component = shallow(<DataAdmin />, {context: EventsLoadingContext});
const dataTable = component.find(".table-container");
expect(dataTable.length).toBe(1);
});
and have a trouble like that:
In the context component I have:
export const EventsLoadingContext = createContext();
export const WithEventsLoadingContext = ({children}) => {
const [backendEvents, setBackendEvents] = useState([]);
const [integrationEvents, setIntegrationEvents] = useState([]);
const [allEvents, setAllEvents] = useState([]);
// ...
const value = {
preparedEvents,
dropdownItems,
dropdownClicked, setDropdownClicked,
loading,
updatedChanges, setUpdatedChanges
};
return (
<EventsLoadingContext.Provider value = {value}>
{children}
</EventsLoadingContext.Provider>
)
};
And in the DataAdmin component I have:
const DataAdmin = () => {
const {
preparedEvents,
dropdownItems,
dropdownClicked, setDropdownClicked,
loading,
updatedChanges, setUpdatedChanges
} = useContext(EventsLoadingContext);
and so on.
So how could I fix that?
So how could I fix that?
Seems like you should pass the EventsLoadingContext context in options parameter for shallow method. See shallow documentation.
Related
hello I'm writing test for a component with ref. I'd like to mock the ref element and change some properties but have no idea how to. Any suggestions?
import { test, expect } from "#playwright/experimental-ct-react";
import { useState } from "react";
import { useRef } from "react";
import Main from "./index";
test.use({ viewport: { width: 500, height: 500 } });
test("should work", async ({ mount }) => {
const refMain = useRef();
const refFooter = useRef();
const refMenuButton = useRef();
const [mainPostion, setMainPostion] = useState(startMainPostion);
const refContainerForMainFooter = useRef({
refMain,
refFooter,
refMenuButton,
});
const component = await mount(
<Main setMainPostion={setMainPostion} theme='light' ref={ref} />
);
// await expect(component).toContainText('DAMAN');
});
I am writing tests for components of my projects and one of components is changing context value. How can I check if click actually changes context value? Code I have right now gives error "Invalid hook call. Hooks can only be called inside of the body of a function component." What is the way to actually use hooks in tests?
import { useState, useContext } from "react";
import { IntlProvider } from "react-intl";
import { BrowserRouter } from "react-router-dom";
import { render, screen, fireEvent } from "#testing-library/react";
import { messages } from "../../App/App.const";
import Navbar from "./Navbar";
import { DarkModeContext } from "../../contexts/DarkModeContext";
function NavbarMock() {
const [search, setSearch] = useState("");
const [language, setLanguage] = useState("en");
return (
<IntlProvider
messages={messages[language as keyof typeof messages]}
locale={language}
defaultLocale="en"
>
<BrowserRouter>
<Navbar
setLanguage={setLanguage}
language={language}
setSearch={setSearch}
search={search}
/>
</BrowserRouter>
</IntlProvider>
);
}
describe("testing navbar component", () => {
test("renders logo correctly", async () => {
render(<NavbarMock />);
const logo = screen.getByText(/Todoly/i);
expect(logo).toBeInTheDocument();
});
test("renders mode icon correctly", async () => {
render(<NavbarMock />);
const svgEl = screen.getByTitle("mode icon");
expect(svgEl).toBeInTheDocument();
});
test("mode changes", async () => {
render(<NavbarMock />);
const svgEl = screen.getByTitle("mode icon");
const { isDarkMode } = useContext(DarkModeContext);
fireEvent.click(svgEl);
expect(isDarkMode).toBe(true);
});
test("renders language icon correctly", async () => {
render(<NavbarMock />);
const flagEl = screen.getByAltText("en");
expect(flagEl).toBeInTheDocument();
});
});
Ok, the error isn't caused by any of the provider, instead it's caused by the way you write useContext.
A hook can't be used unless it's referenced inside a Component, this is the RULE by React hooks. Because states defined by hooks are meaningless outside.
const AnotherNavbarMock = () => {
const { isDarkMode } = useContext(DarkModeContext);
return <NavbarMock />
}
The above code is the working example. Basically a test isn't a component, you have to define a component and then use it via <AnotherNavbarMock />, otherwise all the hook code would fail.
I want to send the array of objects in ContextProvider value attribute, so that i can use it in another component using useContext() hook. So that in the component i can destructure values from the array and map the array and display it on the browser.
Here is the ContextProvider file code:-
import React, { useState, useEffect, createContext } from "react";
import axios from "axios";
const APIContext = createContext();
export const APIContextProvider = (props) => {
const [orders, setOrders] = useState([]);
useEffect(() => {
const fetchData = async () => {
const res = await axios.get("/api/orders");
setOrders(res.data);
//res.data returns ARRAY OF OBJECTS
console.log(res.data);
};
fetchData();
}, []);
return (
<APIContext.Provider value={?}>{props.children}</APIContext.Provider>
);
};
Why you dont pass objects as value={{objects}} and then later access it as const {objects} = useContext(APIContext)
I've read that using multiple instances of Pusher is not recommended and therefore I am using React's context feature.
import React, { useContext, useEffect, useRef } from "react";
import Pusher from "pusher-js";
const PusherContext = React.createContext<Pusher | undefined>(undefined);
export const usePusher = () => useContext(PusherContext)
export const PusherProvider: React.FC = (props) => {
const clientRef = useRef<Pusher>();
useEffect(() => {
if (!clientRef.current) {
clientRef.current = new Pusher('pusher_key', {
cluster: 'pusher_cluster',
authEndpoint: 'auth_endpoint',
})
}
}, [clientRef]);
return (
<PusherContext.Provider value={clientRef?.current}>
{props.children}
</PusherContext.Provider>
)
}
Our pusher instance is of type Pusher or undefined. When we call usePusher it is always undefined.
import { usePusher } from "./services/pusher";
const Chat: React.FC = (props) => {
const pusher = usePusher()
useEffect(() => {
if (pusher) {
console.log("pusher is initialized/defined")
} else {
// it is always undefined
console.log("pusher is not initialized/defined")
}
}, [pusher])
return (
<div>
Test component
</div>
)
}
Where is the problem?
It seems to work. I was just doing something wrong when wrapping the provider. Hope it helps in case someone have similar problem!
I am following an article: https://dev.to/mongopark/learn-react-hooks-and-context-api-by-building-a-recipe-search-app-2-1g3o. In it, he uses useState and useEffect inside his created Context. When I try to do the same. I get errors sayin, " Line 10:28: React Hook "useState" is called in function "dataProvider" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks" for all the hooks. I would like to just know what I am doing wrong here.
import React, {useState, useEffect, createContext} from 'react';
import { headerFooter } from '../../api/Api';
import {setHeaderFooter} from '../../functions/generalFunctions'
import {grabUserInventory} from '../../api/Api'
import {getAllOrgs} from '../../api/Api'
const dataContext = createContext()
const dataProvider = (props) => {
const [data, setData] =useState("")
const [combined, setCombined] =useState(0)
const [inventory, setInventory] =useState([])
const [notes, setNotes] =useState([])
const [orgs, setOrgs] =useState([])
const [renderedData, setRenderedData]=useState([])
const [progress,setProgress] = useState(true)
useEffect(()=>{
console.log(props.match.params.token)
headerFooter(props.match.params.token)
.then(res=>{
setData(res)
setHeaderFooter(res.header,res.footer)
return grabUserInventory(res.user_id)
.then(data=>{
setInventory(data)
setRenderedData(data)
setProgress(false)
return getAllOrgs()
.then(data=>{
var outputData = data.map( Object.values );
setOrgs(outputData)
})
})
})
.catch(err=>console.error(err))
}, []);
return (
<dataContext.Provider value={{
data,
setData,
combined,
setCombined,
inventory,
setInventory,
orgs,
setOrgs,
renderedData,
setRenderedData,
progress,
setProgress
}}>
{props.children}
</dataContext.Provider>
);
}
export { dataProvider, dataContext }