How do you mock child component with custom HTML react jest - reactjs

Im trying to test a basic component that has a nested Modal component. How could one mock the Modal and test the Modal is successfully populated by values from extraDataInfo object (i.e extraDataInfo?.title)?
export const ExtraDataButtons = ({ extraDataInfo, containerClassName }) => {
const modalSeeMoreTrigger = {
ariaLabel: 'See more',
cssClassName: 'c-extra-data-see-more',
dataAttributes: { seeMore: 'seeMore' },
text: 'See more'
};
return (
<div className={containerClassName}>
<Modal trigger={modalSeeMoreTrigger}>
<div className="c-extra-data-info-cont">
<div className="c-extra-data-number">{extraDataInfo?.offerData}</div>
<div className="c-extra-data-detail">
<div className="c-extra-data-message">
{extraDataInfo?.text && (
<h3 className="c-extra-data-heading">{extraDataInfo?.text}</h3>
)}
{extraDataInfo?.offerDescription && (
<p className="c-extra-data-description">{extraDataInfo?.offerDescription}</p>
)}
</div>
</div>
</div>
<h4 className="c-extra-data-tc-heading" data-test-id="c-extra-data-tc-heading">
{extraDataInfo?.title}
</h4>
<Markdown text={extraDataInfo?.content} />
</Modal>
<button data-test-id="see-more-btn" className="c-extra-data-see-more" type="button">
<Icon svgSource={linearArrowRight} size={20} />
</button>
</div>
);
};

Related

Product Pop-up using React and Django

I am working through a tutorial on React and creating an ecommerce store with a Django backend.
I am new to React.
I have been able to get the React "FrontEnd" home page to display the products from the Django "products.py" which is a simple JSON file stored in the Django file system using the React Axios library.
There is a product pop-up which displays the product information when the use clicks on the view button.
I can't work out how to direct the pop-up to the "products.py" file.
It is still drawing its information from the products.js in the React "FrontEnd" file system.
The code is below. Any assistance would be appreciated.
The code for the product page is below.
Bestsellershop.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { handleOutofStock } from '../../../helper/shopHelper';
import { RatingShop } from '../../../helper/helper';
import Quickview from '../../layouts/Quickview';
import { Modal } from 'react-bootstrap';
import axios from 'axios'
class Bestsellershop extends Component {
constructor(props) {
super(props);
this.state = {
error:null,
modalshow: false,
lastActiveBox: -1,
data:[]
}
this.modalShow = this.modalShow.bind(this);
this.modalClose = this.modalClose.bind(this);
}
componentDidMount(){
var str = "GeeksforGeeks";
this.setState({loading:true});
axios
.get('/api/products/')
.then(res=>{
console.log(res.data);
this.setState({data:res.data, loading:false});
})
.catch(err =>{
console.log(str)
this.setState({error:err, loading:false});
});
}
// Modal
modalShow(index) {
this.setState({ modalshow: true, lastActiveBox: index });
}
modalClose() {
this.setState({ modalshow: false });
}
render() {
const{data,error,loading}=this.state;
return (
<div className="section section-padding">
<div className="container">
<div className="section-title centered">
<span className="subtitle">SuperPharmacy Compounding</span>
<h3 className="title mb-0">Our Products</h3>
</div>
<div className="row">
{error && (
<
error
header="There was some error"
content={JSON.stringify(error)}
/>
)}
{/* Data */}
{data.map((item, i) => (
<div className="col-lg-3 col-md-6" key={i}>
<div className="sigma_product style-6">
<div className="sigma_product-thumb">
<Link to={"/product-single/" + item.id}>
<img src={process.env.PUBLIC_URL + "/" + item.image[0]} alt={item.title} />
</Link>
</div>
<div className="sigma_product-body">
<h5 className="sigma_product-title"> <Link to={"/product-single/" + item.id}>{item.title}</Link>
</h5>
<div className="sigma_rating">
{RatingShop(item.rating)}
</div>
<div className="sigma_product-price">
<span>${new Intl.NumberFormat().format((item.price * (100 - item.discount) / 100).toFixed(2))}</span>
{item.discount > 0 || item.discount !== '' ?
<span>${new Intl.NumberFormat().format((item.price).toFixed(2))}</span>
: ''}
</div>
{/* Cart */}
{item.stock === true ?
<Link to="#" className="sigma_btn btn-sm">Add to Cart</Link>
:
<Link to="#" className="sigma_btn btn-sm" onClick={handleOutofStock}> Add to Cart</Link>
}
{/* Quick view */}
<Link to="#" className="sigma_btn btn-sm light" onClick={(e) => this.modalShow(item.id)}> Quick View </Link>
</div>
</div>
</div>
))}
{/* Data */}
{/* Modal (Quick View) */}
<Modal size="lg" show={this.state.modalshow} className="sigma_quick-view-modal" onHide={this.modalClose} aria-labelledby="contained-modal-title-vcenter" centered>
<Modal.Body className="sigma_modal-sec">
<div className="sigma_close" onClick={this.modalClose}>
<span />
<span />
</div>
<Quickview productId={this.state.lastActiveBox} />
</Modal.Body>
</Modal>
</div>
</div>
</div>
);
}
}
export default Bestsellershop;
The code for the modal pop-up is below.
Quickview.js
import React, { Component } from 'react';
import { getProduct, handleOutofStock } from '../../helper/shopHelper';
import { RatingShop, socialShare, getTags } from '../../helper/helper';
import { Link } from 'react-router-dom';
class Quickview extends Component {
constructor(props) {
super(props)
this.state = {
qty: 1
}
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
this.openSocialPopup = this.openSocialPopup.bind(this);
}
increment() {
this.setState({
qty: this.state.qty + 1
});
}
decrement() {
this.setState({
qty: this.state.qty > 1 ? this.state.qty - 1 : 1
});
}
handleChange(event) {
this.setState({ qty: event.target.value });
}
// Open window
openSocialPopup(social) {
window.open(social.link, "MsgWindow", "width=600,height=600")
// alert(social.title)
}
render() {
const productId = this.props.productId;
const modalContent = getProduct(productId);
return (
<div className="row sigma_product-single">
<div className="col-md-6">
<div className="sigma_product-single-thumb">
<img src={process.env.PUBLIC_URL + "/" + modalContent.image[0]} alt={modalContent.title} className="w-100" />
</div>
</div>
<div className="col-md-6">
<div className="sigma_product-single-content">
<h3>{modalContent.title}</h3>
<div className="sigma_product-price">
<span>${new Intl.NumberFormat().format((modalContent.price * (100 - modalContent.discount) / 100).toFixed(2))}</span>
{modalContent.discount > 0 || modalContent.discount !== '' ?
<span>${new Intl.NumberFormat().format((modalContent.price).toFixed(2))}</span>
: ''}
</div>
<div className="sigma_rating-wrapper">
<div className="sigma_rating">
{RatingShop(modalContent.rating)}
</div>
<span>{modalContent.reviews.length} Reviews</span>
</div>
<hr />
<p className="sigma_product-excerpt">
{modalContent.shorttext}
</p>
<div className="sigma_product-meta">
<p><strong>Product SKU: <span>#{modalContent.sku}</span></strong></p>
<p><strong>Availablity:
{modalContent.stock === true ?
<span>In Stock</span>
:
<span>Out of Stock</span>
}
</strong></p>
<p><strong>Tags: </strong>
{getTags(modalContent.tags).map((tag, i) => (
<Link to={"/shop/tag/" + tag.id} key={i}>{tag.title} ,</Link>
))}
</p>
</div>
<hr />
<form className="sigma_product-atc-form">
<div className="sigma_product-buttons d-block">
{/* Cart */}
{modalContent.stock === true ?
<button type="button" className="ml-0 btn-block sigma_btn">Add To
Cart <i className="far fa-shopping-basket" /></button>
:
<button type="button" onClick={handleOutofStock} disabled className="ml-0 btn-block sigma_btn">Add To Cart <i className="far fa-shopping-basket" /></button>
}
{/* Wishlist */}
<Link to="#" className="ml-0 btn-block sigma_btn light">Add To Wishlist <i className="far fa-heart" /> </Link>
<Link to="#" className="ml-0 btn-block sigma_btn light">Compare <i className="far fa-compress" />
</Link>
</div>
</form>
{/* Post Meta Start */}
<div className="sigma_post-single-meta">
<div className="sigma_post-single-meta-item sigma_post-share">
<h5>Share</h5>
<ul className="sigma_sm">
{/* Data */}
{socialShare(modalContent.title).map((social, i) => (
<li key={i}>
<Link to="#" onClick={(e) => this.openSocialPopup(social, i)}>
<i className={social.iconClass} />
</Link>
</li>
))}
{/* Data */}
</ul>
</div>
</div>
{/* Post Meta End */}
</div>
</div>
</div>
);
}
}
export default Quickview;
Update - I have located a helper function file called 'ShopHelper.js'. It contains a function getProduct(id). That function refers to an internal json 'shop.json'.
How do I redirect the shopBlock variable to the Django file?! I am very lost
import shopblock from '../data/shop/shop.json';
import category from '../data/shop/category.json';
// Product details
function getProduct(id) {
return shopblock.filter(product => { return product.id === parseInt(id) })[0];
}
// Count Category

Creating a modal in React JS on pre-existing button

I want a modal to open when I click on an info circle on the product info button. I can't figure out how to do this in react after the export default statement.
The export default is important to other events in my code so I wanted to keep that as it is.
export default ({ product, addToBasket, removeFromBasket, openModal}) => {
return (
<div className={styles.tile}>
<div className={styles.tileGrid}>
<div className={styles.imageContainer}>
<FontAwesomeIcon icon={faCamera} />
</div>
<h3 className={styles.shortDescription}>{product.shortDescription}</h3>
<p className={styles.price}>£{product.price}</p>
{product.quantity && (
<p className={styles.quantity}>Quantity: {product.quantity}</p>
)}
{
<div className={styles.modal} onClick={() => openModal(product)}>
<FontAwesomeIcon icon={faInfoCircle} /> Product Info
</div>}
{addToBasket && (
<button className={styles.cta} onClick={() => addToBasket(product)}>
<FontAwesomeIcon icon={faShoppingBasket} /> Add to Basket
</button>
)}
{removeFromBasket && (
<button
className={styles.secondaryButton}
onClick={() => removeFromBasket(product)}
>
Remove from Basket
</button>
)}
</div>
</div>
);
};
Have used the following link but can't get it working in my code: https://www.pluralsight.com/guides/how-to-trigger-modal-for-react-bootstrap

react js button hide while click in button

here is my reactjs button code how can hide while clicking in button
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)
})
}
</div>
</div>
</div>
you can do someting like this, at first set showButton field true and onClick make it false
buttonSubmit = ()=> {
this.setState({ showButton: false });
},
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
{showButton && (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)}
)
})
}
</div>
</div>
</div>
buttonSubmit = ()=> {
this.setState({ showButton: !this.state.showButton });
},
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
{showButton && (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)}
)
})
}
</div>
</div>
</div>
A small change to the above answer. You can enable and disable it onclick

Reactjs: Antd Table onRowClick trigger all event

So i'm new to reactjs, im doing a table that when you click on 1 row it will render a detail description for that row. I have some button to trigger some event on that description table. But when i'm click the row on the table the description still render but the problem is, all the event in the descroption is trigger when i click on the row table not the button. Help pls
Here is my code:
const [displayCoursesDescription, setDisplayCoursesDescription] = useState({ coursesDescription: [] });
const handleCloseCoursesDescription = () => setDisplayCoursesDescription({ coursesDescription: [] });
const handleReloadCourse = () => {
setDisplayCoursesDescription({ coursesDescription: [] });
dispatchStudentCourses();
};
<div className="studentDashboardContent">
<div className="TableHeader">
<img className="courseIcon" src={courseActive} alt="courseActive" role="presentation" />
<p className="courseText">Courses</p>
<div className="ToolBar">
<OutlinedButton
icon={<ReloadOutlined style={{ width: '32px' }} />}
color={COLOR}
backgroundColor={BACKGROUND_COLOR}
display="inline"
onClick={handleReloadCourse}
/>
<SearchBox
placeholder="Search for courses"
color={COLOR}
backgroundColor={BACKGROUND_COLOR}
display="inline" // inline || none
/>
</div>
</div>
{courses && courses.status === API_STATUS.LOADING ? (
<LoadingIndicator />
) : (
<Table
className="studentTable"
columns={columns}
dataSource={coursesSource}
pagination={{ hideOnSinglePage: true }}
onRow={(record) => ({
onClick: (event) => {
setDisplayCoursesDescription({ coursesDescription: record });
getDepartmentById(record.department);
},
})}
/>
)}
</div>
{displayCoursesDescription.coursesDescription.key ? (
<div className="CourseDescription">
<div className="HeaderButton">
<a
href={displayCoursesDescription.coursesDescription.hostname}
className="courseUrl"
rel="noreferrer"
target="_blank"
>
<div className="forwardBtn" role="presentation">
<p className="forwardText">Go to course</p>
<img className="forwardImg" src={forward} alt="forward" />
</div>
</a>
<Button className="closeBtn" type="primary" icon={<CloseOutlined />} onClick={console.log('click1')} />
</div>
<div className="courseCodeName">
<p className="courseCode">{displayCoursesDescription.coursesDescription.code}</p>
<p className="courseName">{displayCoursesDescription.coursesDescription.name}</p>
</div>
<p className="departmentTitle">DEPARTMENT</p>
<div className="courseDepartment">
<img className="departmentImg" src={departmentIcon} alt="department" />
<p className="departmentName">{departments.name}</p>
</div>
<div className="courseDescription">
<p className="descriptionTitle">COURSE DESCRIPTION</p>
<p className="description">{displayCoursesDescription.coursesDescription.description}</p>
</div>
<Button className="unassignCourse" type="primary" danger onClick={console.log('click2')}>
Exit course <LoginOutlined />
</Button>
</div>
) : (
<div className="studentBackground">
<div className="dashboardContainer">
<p className="hiText">Hi {user.name}. How are you today?</p>
<img className="dashboardIMG" src={dashboardIMG} alt="dashboardimg" />
</div>
</div>
)}
Here is the console log that 2 onClick event were trigger when i click on the table Row
enter image description here

How to push new FieldArray from outside render function?

I have this code to push new FieldArray every time I click the button, but it is only applicable inside renderContract FieldArray component.
const renderContact = ({ fields, meta: { error } }) => (
<div>
{fields.map((contact, index) => (
<div key={index}>
<div className="row form-pad">
<div className="col-md-3">
<span>Country Code {index + 1}:<span className="requiredField text-danger"> * </span>: </span>
</div>
<div className="col-md-7">
<Field name={`${contact}.landlineCountryCode`} component={renderField}type="text"/>
</div>
</div>
</div>
))}
<button className="btn btn-primary" onClick={() => fields.push({})}>
Add Contact
</button>
</div>
)
and render it like this on parent form component:
<FieldArray name="contact" component={renderContact} />
How can I use fields.push({}) outside fieldArray?
EDIT:
I tried this but to no avail:
<button type="button" onClick={() => props.dispatch(arrayPush('PersonalInfoForm', 'contact', [{}]))}> Add Contact</button>
You can dispatch an action arrayPush with the form and the fieldname to effect a fields.push({}) from outside the FieldArray
import { arrayPush } from 'redux-form';
// ...
dispatch(arrayPush('myForm', 'contact', {}));

Resources