I have been trying to test onclick event on a child component of a parent component but i am having no luck to make it work. Can someone help to point me in the right direction? below is my code.
Navbar.js file
const NavbarDownloadUserGuide = ({
const [anchorElement, setAnchorElement] = useState(null);
const handleOpenPopover = (event) => {
setAnchorElement(event.currentTarget);
};
return (
<>
<DownloadUserGuideWithTooltip
orientation="bottom"
onClick={handleOpenPopover}
data-testid="navbar-guide-button"
/>
</>
})
Navbar.spec.js
import React from 'react';
import { render, screen, fireEvent } from 'test-utils';
import wrapper from 'test-utils/store-wrapper';
import NavbarDownloadUserGuide from '../../../components/Navbar/NavbarDownloadUserGuide';
describe('NavbarDownloadUserGuide component', () => {
test('should handle open popover', () => {
const handleOpenPopover = jest.fn();
render(wrapper(<NavbarDownloadUserGuide><DownloadUserGuideWithTooltip onClick={handleOpenPopover} /></NavbarDownloadUserGuide>));
const downloadUserGuideWithTooltip = screen.getByTestId('navbar-guide-button');
fireEvent.click(downloadUserGuideWithTooltip);
expect(handleOpenPopover).toHaveBeenCalled();
})
})
Related
I have created a generic component to be used in 2 cases. 1 case when dealing with single piece of data the other when dealing with an array of data. I am trying to plot this data on a react leaflet map. Right now it works for my landingPage component which deals with the single plots of data.
Previously I had it also working for my array of data before I was passing props to generic component to render. The issue is when I try to load the page responsible for displaying the map with the array of data it returns null when the getInitPosition() function is called as the props data seems to be null when component is rendered but not null after it, I checked this through logging to console. I am confused as to how it works in the single component and not the array of data component as the calls to retrieve the data are very similar. Can anyone see where I am going wrong. It seems to be that although my polyineArray is set with correct values I then print out the polylines state to check if it is set after the call to setPolylines(polylineArray) but it seems to be empty and I do not know why?
Map array of data component:
import react from 'react';
import { useState, useEffect} from 'react';
import { MapContainer, TileLayer, Popup, Polyline} from 'react-leaflet';
import axios from 'axios';
import polyline from '#mapbox/polyline';
import MapComp from './MapComp';
function Mapp() {
const [activities, setActivities] = useState([]);
const [polylines, setPolylines] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setActivitieData();
}, [])
useEffect(() => {
if(activities.length) {
setPolylineArray();
setIsLoading(false);
}
}, [activities])
const getActivityData = async () => {
const response = await axios.get(
"http://localhost:8800/api/"
);
return response.data;
};
const setActivitieData = async () => {
const activityData = await getActivityData();
setActivities(activityData);
};
const setPolylineArray = () => {
const polylineArray = []
for(let i = 0; i < activities.length; i++) {
const polylineData = activities[i].map.summary_polyline;
const activityName = activities[i].name;
const activityType = activities[i].type
polylineArray.push({positions: polyline.decode(polylineData), name: activityName, activityType: activityType });
} // should push activity type as well
setPolylines(polylineArray);
//setIsLoading(false);
console.log("Polyline array = ", polylineArray);
console.log("polylines = ", polylines) // this seems to be empty????
}
return (
!isLoading ?
<MapComp activityData={{polylines}} />
: <div><p>Loading...</p></div>
)
}
export default Mapp;
single data plotting component which works:
import react from 'react';
import { useState, useEffect } from 'react';
import Card from './Card';
import axios from 'axios';
import polyline from '#mapbox/polyline';
function LandingPage() {
const [cardActivites, setCardActivities] = useState([]);
const [polylines, setPolylines] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
setActivitieData();
}, [])
useEffect(() => {
if(cardActivites.length) {
setPolylineArray();
activityCards();
}
}, [cardActivites])
const getActivityData = async () => {
const response = await axios.get(
"http://localhost:8800/api/"
);
return response.data;
};
const setActivitieData = async () => {
const activityData = await getActivityData();
setCardActivities(activityData);
};
const setPolylineArray = async () => {
const polylineArray = []
// right now activites refers to our button to show all activites
// we will eventually be using global state in redux
// for now we have a different state for card activties
for(let i = 0; i < cardActivites.length; i++) {
const polylineData = cardActivites[i].map.summary_polyline;
const activityName = cardActivites[i].name;
const activityType = cardActivites[i].type
polylineArray.push({positions: polyline.decode(polylineData), name: activityName, activityType: activityType });
} // should push activity type as well
setPolylines(polylineArray);
console.log("Polyline array = ", polylineArray);
}
const activityCards = async () => {
// set up polyline array
setCards(polylines.map((polyline, i) => {
return <Card key={i} activityData={{polyline}}/>
}))
console.log("cards = ", cards);
//return <Card activityData={{polylines}}/>
}
return (
<div>
<p>cards</p>
{cards}
</div>
)
}
export default LandingPage;
generic component: import react from 'react';
import { MapContainer, TileLayer, Popup, Polyline} from 'react-leaflet';
import polyline from '#mapbox/polyline';
import { useEffect, useState } from 'react';
function MapComp(props) {
function getInitPosition() {
console.log("props activity data = ", props);
if(!Array.isArray(props.activityData)) {
return [props.activityData.positions[0][0],props.activityData.positions[0][1]];
}
else {
return [props.activityData.poylines.positions[0][0],props.activityData.poylines.positions[0][1]];
}
}
return (
<MapContainer center={getInitPosition()} zoom={15} scrollWheelZoom={false} style={props.style}>
<TileLayer attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{!Array.isArray(props.activityData) && <Polyline positions={props.activityData.positions} >
<Popup>
<div>
<h2>{"Name: " + + props.activityData.name}</h2>
</div>
</Popup>
</Polyline>
}
{Array.isArray(props.activityData.polylines) && props.activityData.polylines.length > 1 &&
props.activityData.polylines.map((activity, idx) => (
<Polyline key={idx} positions={activity.positions}
<Popup>
<div>
<h2>{"Name: " + activity.name}</h2>
</div>
</Popup>
</Polyline>
))}
</MapContainer>
)
}
export default MapComp;
Can anyone see my issue why polylines isn't being set or how to ensure it is set before passing the data as props?
i am trying to make a system with face-api that recognizes a face on the webcam and compares it with that of an image. But when I try to print by console const detections = await faceapi.detectSingleFace(video.current) it returns the following result:
enter image description here
import React from 'react';
import * as faceapi from 'face-api.js';
import {useRef, useEffect} from 'react';
function IdBiometrica(){
const video = useRef()
useEffect(() => {
const getUserMedia = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({video: true});
video.current.srcObject = stream;
} catch (err) {
console.log(err);
}
};
getUserMedia();
}, []);
Promise.all([
faceapi.nets.ssdMobilenetv1.loadFromUri('/models'),
faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models')
]).then(recognition())
function recognition(){
setInterval(async () => {
const detections = await faceapi.detectSingleFace(video.current)
console.log(detections)
}, 10000)
}
return(
<div>
<video ref={video} id='video' width="480" height="240" autoPlay={true} muted></video>
</div>
)
}
export default IdBiometrica
This is an app component created with Create-React-App.
I don't understand why throw an error but after throwing a correct result.
Does anyone have any idea of what the problem is?
Thanks for help!
I am trying to display my stripe component, but I am getting this error:
IntegrationError: Only one element of type cardNumber can be created.
I don't know why, since I'm only using it once in my entire app
Any ideas?
This is my index
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { loadStripe } from "#stripe/stripe-js";
import { Elements } from "#stripe/react-stripe-js";
import MyComponent from './components/StripeComponent';
const promise = loadStripe("xxx-xxx-xxx");
ReactDOM.render(
<React.StrictMode>
<Elements stripe={promise}>
<MyComponent/>
</Elements>
</React.StrictMode>,
document.getElementById('root')
);
And this is my component
import React from "react";
import {
useElements,
} from "#stripe/react-stripe-js";
const MyComponent: React.FC= (props)=>{
const elements = useElements();
const cardNumberElement = elements?.create('cardNumber', {
placeholder: ''
});
const cardExpiryElement = elements?.create('cardExpiry', {
placeholder: ''
});
const cardCvvElement = elements?.create('cardCvc', {
placeholder: ''
});
cardNumberElement?.mount('#card-number-element')
cardExpiryElement?.mount('#card-expiry-element')
cardCvvElement?.mount('#card-cvv-element')
const handleSubmit = async (ev: any) => {
ev.preventDefault();
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<div id="card-number-element"></div>
<div id="card-expiry-element"></div>
<div id="card-cvv-element"></div>
</form>
);
}
export default MyComponent
Seems it is because you create and mount the card components in the functional component body they are executed on every render of the component, i.e. as an inadvertent side-effect.
Place the creation and mounting logic in an useEffect hook with an empty dependency array so that it is invoked only once when the component mounts.
import React, { useEffect } from "react";
import { useElements } from "#stripe/react-stripe-js";
const MyComponent: React.FC = (props) => {
const elements = useElements();
// Effect hook to run once on component mount
useEffect(() => {
const cardNumberElement = elements?.create("cardNumber", {
placeholder: ""
});
const cardExpiryElement = elements?.create("cardExpiry", {
placeholder: ""
});
const cardCvvElement = elements?.create("cardCvc", {
placeholder: ""
});
cardNumberElement?.mount("#card-number-element");
cardExpiryElement?.mount("#card-expiry-element");
cardCvvElement?.mount("#card-cvv-element");
}, []); // <-- empty dependency array
const handleSubmit = async (ev: any) => {
ev.preventDefault();
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<div id="card-number-element"></div>
<div id="card-expiry-element"></div>
<div id="card-cvv-element"></div>
</form>
);
};
useEffect(() => {
if (elements) {
const cardNumberElement =
elements.getElement("cardNumber") || // check if we already created element
elements.create("cardNumber", defaultInputStyles); // create if dont
cardNumberElement.mount("#numberInput");
}
}, [elements]);
I had the same problem, in my case, I had a reference to CardNumberElement in another section of my code. After removing it, everything worked fine.
I wrote a really simple unit test, but the handleChange function does not get called.
import React from 'react';
import { fireEvent, render } from '#testing-library/react';
describe('Component', () => {
test('demo', (done) => {
const handleChange = jest.fn();
const {getByRole} = render(
<input role="slider" type="range" onChange={({currentTarget}) => handleChange(currentTarget.value)}/>
);
fireEvent.change(getByRole('slider'), {currentTarget: {value: 10}});
expect(handleChange).toHaveBeenCalledWith(10);
done();
});
})
Any idea on what I'm doing wrong?
The second argument of fireEvent.change has nothing to do with the event argument of the event handler. It only has specific keywords, and currentTarget does not exist. Instead, you should use target, which will work for both target and currentTarget properties of the event :
fireEvent.change(getByRole('slider'), { target: { value: 10 } });
I am currently working on a simple web app using React, Node.js, passport-google-oauth20.
For some reason, whenever the application re-mounts, I lose the currentUser state. It's as if req.user is just lost.
The way it works is I first fetch the current user when the application mounts and set this.state.currentUser to the results. The issue is when the page refreshes. The component re-mounts and I lose the user. I tried logging the user and receive null.
Hopefully I explained this well enough... here is the code:
App component:
import React from 'react';
import List from './List';
import ListForm from './ListForm';
import * as helpers from '../helpers';
class App extends React.Component{
state = {
currentUser: '',
}
componentDidMount() {
helpers.fetchUser()
.then(data => {
this.setState({
currentUser: data
});
});
}
onSubmit = (id, item) => {
helpers.addItem(id, item);
}
render() {
return (
<div className="container">
<List
currentUser={this.state.currentUser}
onSubmit={this.onSubmit}
/>
</div>
);
}
};
export default App;
Helpers:
import axios from 'axios';
export const fetchUser = async () => {
const resp = await axios.get('/api/current_user');
return resp.data;
}
export const addItem = (id, newItem) => {
axios.post("/api/" + id + "/addItem", newItem);
}