Test Conditionally Rendered component in React Js - javascript

I'm new to testing and I'm writing test cases for a react app.
I've a table with atoms in it.
<Table.Cell style={{ cursor: "pointer" }}>
<Icons
data-test="nameDeleteTable"
name="trash"
onClick={() =>
ConfirmBox({
title: "Confirm Deleting?",
message:
"Are you sure you want to delete this entry permanently?",
onClick: () => props.handleDelete(cell.name),
})
}
/>
</Table.Cell>
ConfirmBox has the following code
function ConfirmBox(props) {
return (
<div data-test="confirmboxAtom">
{confirmAlert({
title: `${props.title}`,
message: `${props.message}`,
buttons: [
{
label: "YES",
onClick: props.onClick,
},
{
label: "NO",
},
],
})}
</div>
);
}
confirmAlert is from a library named react-confirm-alert
The current attempt to test the table button click, gets to the onClick of <Icons ... /> using the code
const wrapper = getWrapper(component, "nameDeleteTable");
console.log("Wrapper " , wrapper);
wrapper.props().onClick();
expect(wrapper.length).toBe(1);
While checking the coverage for this, I'm able to get the onClick function to be covered but not the onClick of the ConfirmBox and I have no clue how to make it work.

You have to invoke a onClick() on whatever this react-confirm-alert renders to (I mean the html element).

Related

how to use onClick in react slick

I am using react slick in my Websites. I have 4 slides. Every Slide, I want a onClick Function to get the value. But When I click on the Slide, I am getting the last value only. I searched Stack Overflow but can't find solutions.
Here's the Code:
const productSlideImg = [
{ Img: prodImg1, ImgName: "img1", pageLink: "/home" },
{ Img: prodImg2, ImgName: "img2", pageLink: "/about" },
{ Img: prodImg3, ImgName: "img3", pageLink: "/contact" }
];
const handleClickSlide = (item) => {
console.log(item); // getting "img3" only on every slide click
};
<Slider
autoplay={true}
slidesToShow={1}
slidesToScroll={1} >
{productSlideImg.map((item, index) => (
<div >
<img
style={{ borderRadius: "50px" }}
width={"100%"}
src={item.Img}
onClick={() => {handleClickSlide(item.ImgName) }}
/>
</div>
))}
</Slider>
Please help me with some solutions
you have created a different function handleClickProduts
and using different function on img onClick
onClick={() => {handleClickProduts (item.ImgName) }}
CodeBox link: working code

Popover does not show up in React

I am trying to make a webapplication with Treeviz dependency. The goal is to place a popover button to each node of the tree and if user clicks to the button he/she can see the description of the node,and after it should be editable. I tried in many ways but for me popover does not work in React.
There is an example for what I would like to do. You can see I have to insert React component to HTML therefor I am using renderToString. All you have to look is the renderNode property of the tree. I am referencing to React component in renderNode like: ${tooltip} ${popover}.
import React from "react";
import { TreevizReact } from "treeviz-react";
import { renderToString } from "react-dom/server";
const data_1 = [
{
id: 1,
text_1: "Chaos",
description: "Void",
father: null,
color: "#FF5722"
},
{
id: 2,
text_1: "Tartarus",
description: "Abyss",
father: 1,
color: "#FFC107"
},
{ id: 3, text_1: "Gaia", description: "Earth", father: 1, color: "#8BC34A" },
{ id: 4, text_1: "Eros", description: "Desire", father: 1, color: "#00BCD4" }
];
export const App = () => {
return (
<div style={{ marginLeft: 10 }}>
<div style={{ display: "flex" }}>
<TreevizReact
data={data_1}
relationnalField={"father"}
nodeWidth={120}
nodeHeight={80}
areaHeight={500}
areaWidth={1000}
mainAxisNodeSpacing={2}
secondaryAxisNodeSpacing={2}
linkShape={"quadraticBeziers"}
renderNode={(data) => {
const nodeData = data.data;
const settings = data.settings;
let result = "";
const tooltip = renderToString(
<strong
data-toggle="tooltip"
data-placement="top"
title={nodeData.description}
>
{nodeData.text_1}
</strong>
);
const popover = renderToString(
<button
type="button"
className="btn btn-secondary"
data-container="body"
data-toggle="popover"
data-placement="top"
data-content={nodeData.description}
>
Popover on top
</button>
);
if (data.depth !== 2) {
result = `<div className="box"
style='cursor:pointer;height:${settings.nodeHeight}px; width:${settings.nodeWidth}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${nodeData.color};border-radius:5px;'>
<div>
${tooltip}
${popover}
</div></div>`;
} else {
result = `<div className="box" style='cursor:pointer;height:${
settings.nodeHeight
}px; width:${
settings.nodeHeight
}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${
nodeData.color
};border-radius:${settings.nodeHeight / 2}px;'><div><strong>
${nodeData.text_1}
</strong></div></div>`;
}
return result;
}}
duration={600}
isHorizontal
linkWidth={(node) => 10}
/>
</div>
</div>
);
};
export default App;
Tooltip is working but popover does not show up.
You can try it: https://codesandbox.io/s/zealous-orla-4bq5f?file=/src/App.js
Also tried
const popover = renderToString(
<Popup
trigger={<button> Trigger</button>}
position="right center"
>
<form onSubmit={saveHandler}>
<ContentEditable
html={text.current}
onChange={handleChange}
/>
<button type="submit">Save</button>
<button>Cancel</button>
</form>
</Popup>
const popoverContent = (
<Popover id="popover-basic">
<Popover.Header as="h3">Popover right</Popover.Header>
<Popover.Body>
And here's some <strong>amazing</strong> content. It's very
engaging. right?
</Popover.Body>
</Popover>
);
const popover = renderToString(
<OverlayTrigger
trigger="click"
placement="right"
overlay={popoverContent}
>
<Button variant="success">Click me to see</Button>
</OverlayTrigger>
);
None of them worked for me.
Probably your approach doesn't work because the dom elements in the tree are created dynamically, and bootstrap doesn't set them up.
A more react-ish way to do it would be using react-bootstrap lib and managing every UI aspect in states. To implement the tooltip, the Overlay component actually as a prop called target that allows you to change over what element the tooltip is shown.
<Overlay target={tooltipTarget} show={showTooltip} placement="right">
{(props) => (
<Tooltip id="overlay-example" {...props}>
{tooltipNode?.data.text_1}
</Tooltip>
)}
</Overlay>
Then you only need to manage all these states in the onNodeMouseEnter and onNodeMouseLeave handlers in the TreevizReact component.
onNodeMouseEnter={(_event, node) => {
const t = document.querySelector(`#node-${node.id}`);
setTooltipTarget(t);
setShowTooltip(true);
setTooltipNode(node);
}}
onNodeMouseLeave={(_event, node) => {
setTooltipTarget(null);
setShowTooltip(false);
setTooltipNode(null);
}}
The popup follows the same logic with another set of states.
<div ref={ref}>
<Overlay
show={!!selectedNode.current}
target={target}
placement="bottom"
container={ref.current}
containerPadding={20}
>
<Popover id="popover-contained">
{/* hack to avoid weird blinking (due mutable state) */}
{!!selectedNode.current && (
<>
some form based on node data
{JSON.stringify(selectedNode.current?.data)}
</>
)}
</Popover>
</Overlay>
</div>
and in onNodeClick handler
onNodeClick={(_event, node) => {
const t = document.querySelector(`#node-${node.id}`);
// unselect if already selected
if (selectedNode.current?.id === node.id) {
selectedNode.current = null;
setTarget(null);
} else {
selectedNode.current = node;
setTarget(t);
}
}}
You might notice this time I used a mutable variable via a ref (selectedNode.current), for some reason using a state caused some issues, maybe due to D3 and react having different rendering cycles, reason why you'll probably encounter some other glitches in this implementation.
https://codesandbox.io/s/quizzical-buck-slofh?file=/src/App.js

Change Button Color Dynamically in Ant Design pro table

I am using ant design pro to generate a table. Now I want to implement button in one column and change the color of button depending on the value. But I am struggling how to implement this.
Similar like the image. When false I can use danger to create a red button. But how can I disable danger depending on cell value.
My Code for this-->
const columns = [
{
title: 'News Reported',
dataIndex: 'newsReported',
hideInForm: true,
hideInSearch:true,
sorter: true,
},
{
title: 'Trustworthy',
dataIndex: 'trustworthy',
hideInForm: true,
sorter: true,
valueEnum: {
0: {
text: 'False',
status: 'False',
},
1: {
text: 'True',
status: 'True',
},
},
render: (_) => (
<Button
type="primary" danger
onClick={() => {
console.log("Option Clicked",_)
}}
>
{_}
</Button>
),
},
]
return (
<PageHeaderWrapper>
<ProTable
rowKey="key"
actionRef={actionRef}
request={(params, sorter, filter) => queryRule({ ...params, sorter, filter })}
columns={columns}
rowSelection={false}
scroll={{ x: 700 }}
/>
</PageHeaderWrapper>
);
If any way I could set danger to false depending on the cell value, I could achieve my goal. But how can I do this?
Thanks in advance.
If your column value is boolean then you can use the following:
render: (value) => (
<Button
type="primary" danger={value}
onClick={() => {
console.log("Option Clicked",_)
}}
>
{value}
</Button> ),
So, found the problem. As I am using value enum, when passing a parameter in render it was taking the text value of enum. Found out render has another parameter record which has the row values. Using that I can get the output I want. Is this the best way, that I don't know. So the working code is for me now -->
render: (_,record) => (
<Button
type="primary" danger={!record.status}
onClick={() => {
console.log("Option Clicked",_,record.status)
}}
>
{_}
</Button>
),

How to pass one state value to another state on initialization in react js

I am trying to pass one state value that is imagesArray to another state that is tabData, but it is coming as undefined, PFB the code, please tell what i am doing wrong here?
constructor(props) {
super(props);
this.state = {
imagesArray: [
{
default: '/images/volImage1.png',
active: 'images/volImage1.png'
},
{
default: '/images/volImage2.png',
active: 'images/volImage2-Active.png'
},
{
default: '/images/volImage3.png',
active: 'images/volImage3.png'
},
{
default: '/images/volImage4.png',
active: 'images/volImage4.png'
},
{
default: '/images/volImage5678.png',
active: 'images/volImage5678.png'
},
],
tabData: [
{
title: 'Knowledge and experience',
content: <VolunteerTabContent1 imagesArray={this.state.imagesArray} />
//Here I am passing above imagesArray state, and this is coming as undefined and throwing error
},
{
title: 'Practical and hands on',
content: 'Tab 2 Content'
},
{
title: 'Management and leadership',
content: 'Tab 3 Content'
},
]
}
}
You cannot use this.state when setting the state itself. This won't work at all.
In your case, if imagesArray is not going to be changed during the execution and it's only some data you need, maybe you don't need to set it as part of the component's state.
You could define imagesArray as a constant outside the class or something similar, and just reference it when setting the tabData.
EDIT:
Even more. If tabData is just data you will need afterwards but it's not going to change, you don't need to set that as state either.
EDIT 2:
If this two arrays really need to be in the state, a way to achieve the desired results would be to define only the component name in the 'content' property of each tabData item, and then use that to instantiate it in the render method:
tabData: [
{
title: 'Knowledge and experience',
content: VolunteerTabContent1
},
...
and then in the render method you can do:
// Let's suppose you want the first one as an example. Do this as you need.
const item = this.state.tabData[0];
render() {
<item.content imagesArray={this.state.imagesArray} />
}
This way you'll correctly get the imagesArray form the state. JSX will get item.content's value (the VolunteerTabContent1 component in this case) and render it.
I will show in functional component it will useful for someone.
import "./styles.css";
import image1 from '../image/man.png';
import image2 from '../image/woman.png';
import React,{useState} from 'react';`enter code here`
import Avatar from '#mui/material/Avatar';
export default function App() {
const [choose,setChoose] =useState("")
const [avatar,setAvatar] = useState(image);
return (
<div className="App">
<Avatar
alt="D S"
src={avatar}
sx={{ width: 44, height: 44 }}
/>
<div>
<Avatar className='Avatars' onClick={()=> setChoose(image1)} alt="Guest"
src={image1} sx={{ width: 30, height: 30 }}/>
<label>Guest</label>
</div>
<div>
<Avatar className='Avatars' onClick={()=> setChoose(image2)} alt="Other"
src={image2} sx={{ width: 30, height: 30 }}/>
<label>Other</label>
</div>
<div>
<button className="avatar_btn1" onClick={()=>setAvatar(choose)} >OK</button>
</div>
</div>
);
}
from my code first you can choose a avatar it will not change in frontend when you click ok button it will show avatar changed one.

Uncaught SyntaxError: Unexpected token < in React

I'm working on a react project and trying to display a dialog with react-bootstrap. I just copied a working react-bootstrap snippet in a js file but it's not working for me, I'm having Uncaught SyntaxError: Unexpected token < next to the <div className='static-modal'> line.
Here is the content of the js file:
(function (context) {
// notification view
TheGraph.Notification = React.createFactory( React.createClass({
//TheGraph.Notification = React.createClass({
componentDidMount: function () {
},
handleHide: function () {
alert('Close me!');
},
render: function () {
return (
<div className='static-modal'>
<Modal title='Modal title' bsStyle='primary' backdrop={false} animation={false} container={mountNode} onRequestHide={handleHide}>
<div className='modal-body'>
One fine body...
</div>
<div className='modal-footer'>
<Button>Close</Button>
<Button bsStyle='primary'>Save changes</Button>
</div>
</Modal>
</div>
);
}
});
})(this);
When I put use " in return line as follows:
return ("<div className='static-modal'><Modal title='Modal title' bsStyle='primary' backdrop={false} animation={false} container={mountNode} onRequestHide={handleHide}><div className='modal-body'>One fine body...</div><div className='modal-footer'><Button>Close</Button><Button bsStyle='primary'>Save changes</Button></div></Modal></div>");
I get this error:
Uncaught Error: Invariant Violation: ReactCompositeComponent.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object
Any idea what is the mistake here?
The code that you are using inside render is JSX , browsers as of now doesn't understand jsx . So we need transpilers to convert them to pure JavaScript .
You need to have a build process that transpiles your jsx code into javascript and then you should load that transpiled js in your HTML.
But if you just quickly want to play with react without setting up the build process , you can go here and do that manually every time and paste that inside render
React.createElement(
'div',
{ className: 'static-modal' },
React.createElement(
Modal,
{ title: 'Modal title', bsStyle: 'primary', backdrop: false, animation: false, container: mountNode, onRequestHide: handleHide },
React.createElement(
'div',
{ className: 'modal-body' },
'One fine body...'
),
React.createElement(
'div',
{ className: 'modal-footer' },
React.createElement(
Button,
null,
'Close'
),
React.createElement(
Button,
{ bsStyle: 'primary' },
'Save changes'
)
)
)
);

Categories