Mock return object of useLocation() hook
useLocation
hook from react-router returns object location
, I need to mock the object in my test, how to do it?
This is the code in my component which I need to test:
const { search } = useLocation();
By best guess solution looks like:
jest.mock('react-router-dom', () => ({
useLocation: jest.fn().mockReturnValue({
location: '/test',
}),
}));
See also questions close to this topic
-
Unable to catch and log the error from axios request
I'm validating user input and result in express and am returning 422 if the input is invalid and a 400 if result is empty. The problem is that I can't log the response object when an error occurs.
Nodejs:
if (q === '' || q.length < 3 || q.length > 150) { console.log('invalid query'); return res.sendStatus(422).send('Search not found'); } else { try { // Fetch redis data const data = await GET_ASYNC('data'); // stuff here // Result Validation if (!Array.isArray(data) || !data.length) { res.status(400).send('Search not found'); } else { // do stuff res.status(200).send(data); } } catch (err) { console.error(err); res.sendStatus(500); // Server error }
Now my react code:
const searchDb = useCallback(async() => { const CancelToken = axios.CancelToken; const source = CancelToken.source(); try { axios.get(`/api/bestProduct?q=${searchValue}`, { cancelToken: source.token }) .then(res => { console.log(res) // nothing shows up const data = res.data; setData(data) }); } catch (err) { if (axios.isCancel(err)) { console.log(err.response); // nothing shows up } else { console.log('hello??') // nothing return setError(`There's been a problem on our end.`) } } }, [])
I've looked at other solution and tried to log the res and res.status but nothing shows up. This is what my console looks like during the error:
-
Dynamic object keys... Cannot create property on string
I'm trying to make an input automatically store its value in an object. The key should be the input's id. Ex: {screen1_input1: 'whatever'}. The first character does that. The second character crashes with "TypeError: Cannot create property on string". I think I see what's happening but I don't know how to fix it.
import { useState } from 'react' function Demo() { const [contentData, setContentData] = useState({}) const onChange = (e) => { let oldData = contentData setContentData(oldData[e.target.id] = e.target.value) console.log('*') } const Screen1 = () => { return ( <> <input type="text" id="screen1_input1" onChange={onChange} /> </> ) } return ( <> <h2 className="Demo"> {Screen1()} </h2> </> ) } export default Demo
-
How can I extract a nested array of objects and put them in the core array?
I am working on a functionality where I need to group some items and also ungroup them.
Some days ago I asked this question: How can I group specific items within an object in the same array and delete them from the core array? where a couple of people helped me solving the grouping part. But it is very related to this question.
What I need to do now, is to ungroup the items with the exact same requirement: ungroup the
checked === true
group and put the items back from where they came from and remove all duplicates.Here is a reproducible demo with both functionalities: https://codesandbox.io/s/ts-react-grouping-forked-rmwhr?file=/src/App.tsx
And here the relevante piece of code:
const handleUngroupingQuestions = (): void => { const questionAddedCopy: VariableConfig[] = [...questionAdded] const filteredByChecked: VariableConfig[] = questionAddedCopy.filter((q: VariableConfig) => isCheck.includes(q.id)) if (isCheck.length) { setCheck([]) const extractGroup = (i: number): VariableConfig[] => filteredByChecked[i].questionGroup const addChecked = (q: VariableConfig): VariableConfig => ({ ...q, questionGroup: [] }) // @TODO // Remove this when we have a proper data structure clearVariable() const nestChecked = (qs: VariableConfig[], found = false) => qs.flatMap((q: VariableConfig, i: number) => { if (filteredByChecked.includes(q)) { if (found) { return [] } else { found = true return [...[addChecked(q)], ...extractGroup(i)] } } else { return [q] } }) const getNew = [...nestChecked(questionAdded)] console.log({ getNew: JSON.stringify(getNew, null, 2) }) addQuestion(getNew.filter((g, i, a) => a.indexOf(g) === i)) } }
For some reason right now I am getting an error:
Cannot read property 'questionGroup' of undefined
Something is happening with an index.
So what I need is to group all of the items with the checked property being true. Then click on
ungroup
and bring the items back to its original position and deleting the current group. I must be able to do that even when there are multiple groups of questions.What am I missing?
-
React router Multiple layouts with not found page
I have a problem with multiple layouts in react routing and not found page
Main routs => with main layout
Admin routs => with admin layout
login page => without any layouts
404 page => without any layouts
My code:
import React from 'react'; import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; import AuthContextProvider from './context/authContext/AuthContext';
const main = () => { return ( <div> <Navbar /> <Switch> <Route path="/" exact component={Main} /> <Route path="/contact" exact component={Contact} /> <Route path="/about" exact component={About} /> <Route path="/blog" exact component={Blog} /> </Switch> </div> ) }
const admin = () => { return ( <div> <PanelNavbar /> <Switch> <Route path="/admin/panel" exact component={Panel} /> <Route path="/admin/panel/menu" exact component={Menu} /> <Route path="/admin/panel/blog" exact component={Blog} /> </Switch> </div> ) }
const App = (props) => { return ( <Router> <AuthContextProvider> <Switch> <Route path="/admin/login" exact component={Login} /> <Route path='/admin' component={admin} /> <Route path="/" component={main} /> <Route path='/404' component={Page404} /> <Redirect to='/404' /> </Switch> </AuthContextProvider> </Router> ); }
I don't want 404 page to take any layouts.
I want just the wrong address to be redirected to a 404 page.
Please help me.
Thanks.
-
Ionic 5 + React - State value is not updated in <Route> component after Redirect
I have a strange behavior using Ionic 5 + React 16, dealing with
<Route />
and<Redirect />
components.I exploit
useMountEffect
hook to call user's session when the App mounts first time. While waiting for API response I show a loader. When session is returned, if user is still logged I save the data in my UserContext (with theuseContext
hook) and perform a redirect to it's personal page (the<Tabs />
component). If user is not defined, I show classic Login / Sigup buttons (this is done inside the<Home />
component). I used the classicuseState
hook to manage loading/ready state while waiting for API response.As u can see in the code below, at the bottom of the
<Router />
I added a<Redirect />
component that sends all unknown routes to the home page.Everything works perfect except for this last case: when I visit a random route (e.g.
/redirect-me
) the app is correctly re-routed do home (/
), but inside therender()
method of<Route exact path="/" render={...} />
(see code below) theloading
state is alwaystrue
, even ifsetLoading(false)
has been called correctly and App component has been re-rendered with the new value.Some snippets:
packages versions
... "@ionic/react": "^5.3.4", "@ionic/react-router": "^5.3.4", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react": "^16.13.1", "react-dom": "^16.13.1", ...
App.tsx
// ... imports const App: React.FC = () => { const userCtx = useContext(UserContext); const [loading, setLoading] = useState<boolean>(true); console.log('App renders with loading state', loading); // check for user session (persistent login) useMountEffect(() => { console.log('use mount effect') getSession() // this API checks if user is logged and returns session data (if any) .then((session: any) => { console.log('session', session); if (session.user) { userCtx.set(session.user); } // done loading API console.log('set is loading to false'); setLoading(false); }) .catch(err => { alert('Sorry, something went wrong'); setLoading(false); }); }); return ( <IonApp> <IonReactRouter> <IonRouterOutlet> <Route exact path="/" render={() => { console.log(`render home route - is loading? ${loading}`); // here's the problem - after redirecting, loading is always true here!! return userCtx.user ? <Redirect to="/user" /> : <Home isLoading={loading} /> }} /> {/* don't use exact here because there are nested routes */} <Route path="/user" render={() => { if (loading) { return <LoadingSplash />; } else if (userCtx.user) { return <Tabs />; } else { return <Redirect to="/" />; } }} /> <Route path="/login" render={() => userCtx.user ? <Redirect to="/user" /> : <Login />} /> <Route path="/signup" component={Signup} /> <Route path="/complete-login-social" component={CompleteLoginSocial} /> <Redirect exact to='/' /> </IonRouterOutlet> </IonReactRouter> </IonApp> ); }; export default App;
Home.tsx
const Home: React.FC<IHome> = props => { console.log('render Home', props); return ( <IonPage> <IonContent fullscreen className="ion-align-items-center ion-justify-content-center bg-image"> <IonGrid id="main-grid"> <IonRow className="ion-align-items-center ion-justify-content-center"> <IonCol size="12" size-md="8" size-lg="5"> <div className="d-flex flex-col ion-align-items-center ion-justify-content-center"> <IonImg id="top-logo" src="../assets/img/logo.svg" /> {props.isLoading ? <Loader className="ion-margin-top" type="TailSpin" color="#fff" height={60} width={60} /> : null} {!props.isLoading ? <HomeButtons /> : null} </div> </IonCol> </IonRow> </IonGrid> </IonContent> </IonPage> ); }; export default React.memo(Home);
NOTE - I tried without React.memo and nothing changes
Here are the console logs in the above code when visiting
localhost:3000/random-path
App.tsx:51 App renders with loading state true App.tsx:55 use mount effect App.tsx:124 render home route - is loading? true Home.tsx:25 render Home {isLoading: true} App.tsx:124 render home route - is loading? true /* Home is not rendering a second time here because of React.memo() */ App.tsx:59 session {message: "no-token"} App.tsx:105 set is loading to false App.tsx:51 App renders with loading state false App.tsx:124 App.tsx:124 render home route - is loading? true /* <- this should be false!! */
Anyone ever encountered something similar? I realize it's a tricky one, I did my best to describe the scenario :)
Thank you in advance, Francesco
-
Router render same component for every rout path
For both path react render only landing component. for path '/' and for path '/home' also. router render only landing component.
import {Route, BrowserRouter, Switch, HashRouter} from 'react-router-dom' import Layout from './pages/Layout' import './style/style.css'; import Landing from './pages/Landing'; function App() { return ( <> <HashRouter> <Switch> <Route path='/'><Layout/></Route> </Switch> <Switch> <Route exact path="/land"><Landing/></Route> </Switch> </HashRouter> </> ); } export default App;
-
Jest mock middleware response
I am trying to mock a middleware response, and i am trying to use
jest.spyOn()
but can't seem to get it workingMy controller.ts has the following
import someMiddleware from '../someMiddleware; .... .... this.route.post('/getData', someMiddleware, setValue)
In someMiddlware.ts
//making a fetch call based on data in req.body ..... const data = await fetchData(url, data) next() .....
In my test file controller.test.ts
describe('Test Data', () => { beforeEach(() => { someMiddlewareSpyOn = jest.spyOn(meddelware, "someMiddleware"); }); afterEach(() => { jest.resetModules(); jest.resetAllMocks(); }); it('response status should be a 200', async () => { someMiddlewareSpyOn.mockResolvedValue({data:[].....}); const res = await request(app.getServer()) .post('/getData'); expect(res.status).toBe(200); }) });
The above does not work, looking for assistance on how to do this.
-
Testing Controller and Service in Jest
I'm fairly new to Jest and have been trying (with no luck) to figure out how to write tests for my controller. I'm not sure how to write the test as it calls another function. It would be great if I could get pointed in the right direction at least. Thanks in advance.
controller.ts
import * as Services from './services'; export async function GetCountriesList(req: Request, res: Response): Promise<void> { const response = await Services.GetCountriesList(); res.status(response.code).json({ status: response.status, message: response.message, count: response.count, data: response.data }); }
service.ts
import db from '../../modules/db'; import { DBGenericDataResponse } from '../../types/models'; export async function GetCountriesList(): Promise<DBGenericDataResponse> { const lQuery = 'somquery'; const responseMessage: DBGenericDataResponse = { code: 200, status: 'ok', message: '', count: 0, data: [], error: '' }; try { const dbResult = await db.query<any>(lQuery); responseMessage.message = 'Countries returned'; responseMessage.count = dbResult.rows.length; responseMessage.data = dbResult.rows; } catch (err) { responseMessage.code = 400; responseMessage.status = 'error'; responseMessage.message = 'Error retrieving Countries List'; responseMessage.error = err; } return responseMessage; }
-
Warning: <TEXT /> is using incorrect casing
console.error node_modules/react-dom/cjs/react-dom.development.js
Warning:
<TEXT />
is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.I have the issue with Jest and react-pdf
In the component where I'm using the react-pdf components this is written as:
<Text>
, but when performing the test it's appearing as<TEXT>
My component:
const HeaderPDF: React.FC<Props> = (props: Props) => { return ( <View style={styles.headerContainer} fixed> <View style={styles.headerTop}> <Text style={styles.textBoldTopHeader}> "Some text" </Text> <View style={styles.headerTopInputContainer}> <View style={styles.headerTopInputTextContainer}> <Text style={styles.textInputTopHeader}>Route</Text> </View> <View style={styles.inputSmall} /> </View> </View> </View> ); };
The test:
import React from 'react'; import { render } from 'tests/support/customRender'; import HeaderPDF from ../../HeaderPDF'; describe('HeaderPDF', () => { it('Renders a HeaderPDF component successfully', () => { const { container } = render( <HeaderPDF someProps /> ); expect(container).toMatchSnapshot(); }); });