I'm importing a child component and rendering it in my app.js file. The component has a console.log for debugging but it keeps running the log, seemingly without end. Worried something might be wrong, new to ReactJS and wondering if this is a common issue and how to resolve it.
App.js:
import React, { Component } from 'react';
import {BrowserRouter as Router, Link} from 'react-router-dom';
import './App.css';
import axios from 'axios'
import Header from './components/header';
import Page from './components/page';
class App extends Component {
constructor(props) {
super(props);
this.state = {
title: 'John Doe',
nav: {},
currentPage: "",
pageContent: "",
pageTitle: "",
pageTemplate: "",
pageId: 0,
pageCustomMeta: {},
archiveData: []
}
}
getMainMenu(){
axios.get('http://admin.sitedata.co/menus/5')
.then((response) => {
this.setState({nav:response.data});
})
.catch((error) => {
console.log(error);
});
}
isHome(){
//console.log(document.location.pathname);
if(document.location.pathname === "/") {
document.body.classList.add('home');
} else {
document.body.classList.remove('home');
}
}
componentDidMount(){
/*
* get current page content
* get the main menu
* allow pageChange function to be ran
* allow isHome to be ran
*/
var slug = "";
if(document.location.pathname === "/") {
slug = "home";
} else {
slug = document.location.pathname.substr(1);
}
this.getPageData(slug);
this.getMainMenu();
this.pageChange = this.pageChange.bind(this);
this.isHome = this.isHome.bind(this);
this.triggerMenu = this.triggerMenu.bind(this);
this.triggerHire = this.triggerHire.bind(this);
this.navigate = this.navigate.bind(this);
this.setArchiveData = this.setArchiveData.bind(this);
this.resetArchiveData = this.resetArchiveData.bind(this);
this.madeChange = this.madeChange.bind(this);
//document.getElementById('loadingOverlay').classList.add('remove');
}
getPageData(slug){
console.log(this.state);
axios.get('http://admin.sitedata.co/pages?slug='+slug)
.then((response) => {
console.log(response.data);
this.setState({
pageContent:response.data[0].content.rendered,
currentPage:slug,
pageTitle:response.data[0].title.rendered,
pageTemplate:response.data[0].template,
pageId:response.data[0].id,
pageCustomMeta:response.data[0].post_meta,
archiveData:[]
},function(){
console.log(this.state);
/*
* set the page title
* check if the page is at home
* get page custom meta
*/
document.title = this.state.pageTitle;
this.isHome();
});
})
.catch((error) => {
console.log(error);
});
}
pageChange(e){
var slug = e.target.getAttribute('data-link');
var classes = e.target.classList.contains('trigger-hire');
if(classes){
this.triggerHire();
e.preventDefault();
} else {
this.getPageData(slug);
}
}
setArchiveData(archives) {
this.setState({archiveData:archives});
}
resetArchiveData() {
}
navigate (event) {
event.preventDefault()
console.log(event.target.tagName);
if (event.target.tagName === 'A') {
this.props.router.push(event.target.getAttribute('href'));
console.log('boom');
}
event.preventDefault();
}
triggerMenu(e){
var menuOverlay = document.getElementById('menuOverlay');
if(menuOverlay.classList.contains('active')){
menuOverlay.classList.remove('active');
} else {
menuOverlay.classList.add('active');
}
}
triggerHire(e){
var hireOverlay = document.getElementById('hireOverlay');
if(hireOverlay.classList.contains('active')){
hireOverlay.classList.remove('active');
} else {
hireOverlay.classList.add('active');
}
e.stopPropagation();
e.preventDefault();
}
madeChange(){
alert('changed');
}
render() {
return (
<div className="App">
<Header nav={this.state.nav} pageChange={this.pageChange} triggerMenu={this.triggerMenu} triggerHire={this.triggerHire}/>
<Page madeChange={this.madeChange}
currentPage={this.state.currentPage}
nav={this.state.nav}
pageChange={this.pageChange}
isHome={this.isHome}
pageContent={this.state.pageContent}
pageTitle={this.state.pageTitle}
pageTemplate={this.state.pageTemplate}
pageId={this.state.pageId}
pageCustomMeta={this.state.pageCustomMeta}
archiveData={this.state.archiveData}
triggerHire={this.triggerHire}
navigate={this.navigate}
setArchiveData={this.setArchiveData}
/>
</div>
);
}
}
export default App;
Page.js
import React, { Component } from 'react';
import {BrowserRouter as Router, Link} from 'react-router-dom';
import axios from 'axios'
class Page extends Component {
render() {
if(this.props.currentPage){
var currentPage = this.props.currentPage;
var pageChange = this.props.pageChange;
var customMeta = this.props.pageCustomMeta;
var pageTempalate = this.props.pageTemplate.substr(0,this.props.pageTemplate.length-4);
var pageTitle = this.props.pageTitle;
var newTitle = <h1><span><i>{pageTitle}</i></span></h1>;
var isArchive = "";
var archiveName = "";
var firstSpace = pageTitle.indexOf(' ');
if(firstSpace > -1){
var firstWord = pageTitle.substr(0, firstSpace);
var titleLast = pageTitle.substr(firstSpace);
newTitle = <h1><span><i>{firstWord}</i>{titleLast}</span></h1>
}
if(currentPage === "home"){
if(this.props.nav.items){
var navData = this.props.nav;
var navHomeItems = navData.items.map(function(navItem){
return <li key={navItem.id}><Link to={'/'+navItem.object_slug} className={navItem.classes} onClick={pageChange} data-link={navItem.object_slug}>{navItem.title}</Link></li>;
});
}
}
document.title = this.props.pageTitle;
var isArchive = customMeta.isArchive;
var archiveName = customMeta.archiveName
var worksArchive = "";
if(customMeta.isArchive && customMeta.isArchive == "true"){
if(customMeta.archiveName) {
axios.get('http://admin.sitedata.co/'+customMeta.archiveName)
.then((response) => {
var archivePages = response.data;
console.log(archivePages);
if(archiveName == "works"){
worksArchive = archivePages.map(function(work){
//console.log(worksArchive);
return <Link key={work.id} className="work-item" to="/" ><img src={work.post_meta.targetimg} /></Link>;
});
this.props.setArchiveData(worksArchive);
}
})
.catch((error) => {
console.log(error);
});
}
}
if(customMeta.pageColor){
document.body.classList.add(customMeta.pageColor);
}
if(customMeta.bgimg){
document.body.setAttribute('style', "background-image:url('"+customMeta.bgimg+"');");
}
}
return (
<Router onEnter={this.props.madeChange}>
<div className="container">
<div className={(pageTempalate !== "") ? pageTempalate : ''}>
{newTitle}
<div dangerouslySetInnerHTML={{__html:this.props.pageContent}}></div>
{this.props.archiveData}
</div>
</div>
</Router>
);
}
}
export default Page;
Distilling your code down to the essential, it looks like this:
class Page extends Component {
render() {
axios.get(url).then(response=> {
this.setState({archiveData: response.data})
})
return (
<div className="container">
{this.state.archiveData}
</div>
)
}
}
(You are doing it differently with a callback that causes the parents to send new props, but the effect is the same).
You should be able to see problem now: the render method causes a delayed change to state (or props) which in react triggers a new render. So you now have an infinite loop, just delayed by the time taken for an ajax request.
To fix this, you need to remove the ajax request from the render method. In your case, it should probably be in the parent App component.
Related
I learn Reactjs and javascript and wanted to call this withFetching Component but don't understand how to set the arguments correctly. I understand overall logic but still learning the details
Here is the switch where I call the withFetching
render() {
const theFile = encodeURI(`./images/${fileData}`);
switch (mediaType) {
case 'xlsx': {
const newProps = { ...this.props, responseType: 'arraybuffer' };
return (
<div className="pg-viewer-wrapper">
<div className="pg-viewer" id="pg-viewer">
<{withFetching(XlsxViewer, newProps, fileType="xlsx", filePath={theFile} )}/>
</div>
</div>
);
}
.........
I try like this also:(making WithFetching camel-case even it's a function)
return (
<div className="pg-viewer-wrapper">
<div className="pg-viewer" id="pg-viewer">
<WithFetching XlsxViewer={XlsxViewer} newProps={newProps} />
</div>
</div>
);
But the WithFetching constructor never firers!
I try like this:
case 'xlsx': {
const newProps = { ...this.props, responseType: 'arraybuffer', fileType: 'xlsx', filePath: { theFile } };
// return withFetching(XlsxViewer, newProps);
return (
<div className="pg-viewer-wrapper">
<div className="pg-viewer" id="pg-viewer">
{WithFetching(XlsxViewer, newProps)};
</div>
</div>
);
}
But still the WithFetching constructor never firers!
Error: (yea I know the way I use brackets are my mistake it's hard to learn)
And this is the withFetching that is in its own file called fetch-wrapper.jsx. The WrappedComponent argument is the above XlsxViewer that is the final "On-screen" Component!
import React, { Component } from 'react';
import Error from './error';
import Loading from './loading';
function withFetching(WrappedComponent, props) {
return class FetchComponent extends Component {
constructor(props) {
// eslint-disable-line no-shadow
super(props);
this.state = {};
this.xhr = this.createRequest(props.filePath);
}
componentDidMount() {
try {
this.fetch();
} catch (e) {
if (this.props.onError) {
this.props.onError(e);
}
this.setState({ error: 'fetch error' });
}
}
componentWillUnmount() {
this.abort();
}
createRequest(path) {
let xhr = new XMLHttpRequest();
if ('withCredentials' in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open('GET', path, true);
// } else if (typeof XDomainRequest !== 'undefined') {
// // XDomainRequest for IE.
// xhr = new XDomainRequest();
// xhr.open('GET', path);
} else {
// CORS not supported.
xhr = null;
return null;
}
if (props.responseType) {
xhr.responseType = props.responseType;
}
xhr.onload = () => {
if (xhr.status >= 400) {
this.setState({ error: `fetch error with status ${xhr.status}` });
return;
}
const resp = props.responseType ? xhr.response : xhr.responseText;
this.setState({ data: resp });
};
return xhr;
}
fetch() {
this.xhr.send();
}
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
render() {
if (!this.xhr) {
return <h1>CORS not supported..</h1>;
}
if (this.state.error) {
return <Error {...this.props} error={this.state.error} />;
}
if (this.state.data) {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
return <Loading />;
}
};
}
export default withFetching;
And this the final XlxsViewer Component that will be visible.
Thanks to Copyright (c) 2017 PlanGrid, Inc.
import React, { Component } from 'react';
import XLSX from 'xlsx';
import CsvViewer from './csv-viewer';
class XlxsViewer extends Component {
constructor(props) {
super(props);
this.state = this.parse();
}
parse() {
const dataArr = new Uint8Array(this.props.data);
const arr = [];
for (let i = 0; i !== dataArr.length; i += 1) {
arr.push(String.fromCharCode(dataArr[i]));
}
const workbook = XLSX.read(arr.join(''), { type: 'binary' });
const names = Object.keys(workbook.Sheets);
const sheets = names.map(name => XLSX.utils.sheet_to_csv(workbook.Sheets[name]));
return { sheets, names, curSheetIndex: 0 };
}
renderSheetNames(names) {
const sheets = names.map((name, index) => (
<input
key={name}
type="button"
value={name}
onClick={() => {
this.setState({ curSheetIndex: index });
}}
/>
));
return <div className="sheet-names">{sheets}</div>;
}
renderSheetData(sheet) {
const csvProps = Object.assign({}, this.props, { data: sheet });
return <CsvViewer {...csvProps} />;
}
render() {
const { sheets, names, curSheetIndex } = this.state;
return (
<div className="spreadsheet-viewer">
{this.renderSheetNames(names)}
{this.renderSheetData(sheets[curSheetIndex || 0])}
</div>
);
}
}
export default XlxsViewer;
I have a Landing component and a NewsLatest component. I am hitting on an api and trying to find the article with the latest timestamp but iam unable to get it done in reactJS.I checked the js code its working fine but in react it is not rendering. Kindly suggest something.
import React, { Component } from 'react'
import NewsSearch from '../NewsSearch/NewsSearch';
import NewsLatest from '../NewsLatest/NewsLatest';
import './Landing.css';
import axios from 'axios';
class Landing extends Component {
state={
newsList: []
}
componentDidMount(){
axios.get(`https://api.nytimes.com/svc/topstories/v2/home.json?api-key=7cK9FpOnC3zgoboP2CPGR3FcznEaYCJv`)
.then(res=> {
this.setState({newsList: res.data.results});
});
}
render() {
// console.log(this.state.newsList);
return (
<div className="landing text-center text-white">
<h1>News Portal</h1>
<div className="news-search">
<NewsSearch />
</div>
<div className="news-latest">
<NewsLatest newsList={this.state.newsList}/>
</div>
</div>
)
}
}
export default Landing;
import React, { Component } from 'react';
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props){
super(props);
this.state = {
newsTitle:'',
abstract:'',
newsUrl:'',
}
// this.newsLatest = this.newsLatest.bind(this);
}
newsLatest = (e)=>{
// e.preventDefault();
const {newsList} = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function (el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
if(latestnews){
this.setState({newsTitle: latestnews.title});
return (<h4>{this.state.newsTitle}</h4>);
}
}
newsTitle = () => (
this.props.newsList.map(item => (<h2 key={item.title}>{item.title}</h2>))
)
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
{this.newsLatest()}
</div>
);
}
}
export default NewsLatest;
There is some issue in rendering in NewsLatest component. KIndly suggest something.
Try this:
You must probably be getting a maximum depth error, use a lifecycle method instead like componentDidUpdate. Update your component state only if the previous props are different from the newer ones.
Read more here: https://reactjs.org/docs/react-component.html
import React, { Component } from "react";
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props) {
super(props);
this.state = {
newsTitle: "",
abstract: "",
newsUrl: ""
};
// this.newsLatest = this.newsLatest.bind(this);
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.newsList !== this.props.newsList) {
const { newsList } = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function(el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
this.setState({ newsTitle: latestnews.title });
}
}
// newsLatest = e => {
// // e.preventDefault();
// const { newsList } = this.props;
// let maxTime = newsList.map(function(o) {
// return new Date(o.updated_date);
// });
// let maximumValue = Math.max(...maxTime);
// let latestnews = newsList.filter(function(el) {
// return maximumValue === new Date(el.updated_date).getTime();
// })[0];
// console.log(latestnews)
// if (latestnews && latestnews.hasOwnProperty('length') && latestnews.length>0) {
// return <h4>{this.state.newsTitle}</h4>;
// }
// };
newsTitle = () =>
this.props.newsList.map(item => <h2 key={item.title}>{item.title}</h2>);
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
<h4>{this.state.newsTitle}</h4>
</div>
);
}
}
export default NewsLatest;
Also, a sandbox: https://codesandbox.io/s/hungry-frog-z37y0?fontsize=14
Here on button click event I am uploading some data in server . I am using mutation for this . And after the response I have to navigate to previous screen and I don't want to refresh the page or re-render the any life cycle methods of the screen where i am directing .
I have used this.props.navigation.navigate("pagename") ,but by using this some function is getting call .
So I have used "this.props.navigation.goBack()" ,but again same .
I have to go back to previous screen after submitting request to server.
import React, { Component } from 'react';
import { View } from 'native-base';
import {withApollo } from 'react-apollo';
import gql from 'graphql-tag';
import _ from 'lodash';
import OverlaySpinner from '../ui/overlaySpinner';
import AddNoteSection from '../../components/tabs/requestTab/AddNoteSection';
import { handleErrors } from '../../services';
class AddNoteSectionContainer extends Component {
constructor(props) {
super(props);
this.state = {
categoryList: [],
isOpenClose: false,
notes: "",
notesResponse:[]
};
}
addNoteChange = (event) => {
this.setState({
notes: event
}, () => {
});
};
statusTextModification = (currentstatus) => {
var status ="";
if (currentstatus === "Pending"){
status = "P"
}else if(currentstatus === "Close"){
status = "C"
}else{
status = "A"
}
return status;
}
OnButtonClick = async (data) => {
var status = "";
const{navigation}=this.props;
const{workFlowDetails,troubleTicketDetails} =
navigation.state.params.ticketDetailsInfo;
const workAgent_ID = workFlowDetails.currentNextActivity;
const currentStepPosition = workAgent_ID.filter((item) => {
return item._activityStatus === "I"
});
const workAgentID = currentStepPosition.map(currentStepPosition => {
return currentStepPosition._workAgent;
});
let workAgent_id=workAgentID[0];
console.log("Props for note notes",workAgent_id);
if (navigation.state.params.currentStatus === "Pending"){
status = "P"
}else if(navigation.state.params.currentStatus === "Close"){
status = "C"
}else{
status = "A"
}
const mutationObj = `
mutation createIncidentNote{
createIncidentNote(
input:{
status: "${status}",
incidentInitiator: "${data}",
notes: "${this.state.notes}",
userId: "${troubleTicketDetails.LoggedBy}",
workAgentID: "${workAgent_id}",
referenceNumber: "${navigation.state.params.referenceNumber}",
}){
REQUEST_STATUS
ABILLITY_REF_NUM
SUCCESS_MESG_LANG_1
SUCCESS_MESG_LANG_2
}
}
`;
try {
const { data } = await this.props.client.mutate({
mutation: gql(mutationObj)
});
// Here below is the code I am using .
this.props.navigation.goBack()
} catch (e) {
handleErrors(e, this.props.navigation);
console.log('Error in Adding note', e);
}
};
render(){
return(
<View>
<AddNoteSection
{...this.props}
addNoteChange={(text) => this.addNoteChange(text)}
OnButtonClick={(data) => this.OnButtonClick(data)}
/>
{/* {<OverlaySpinner color="#00678F" />} */}
</View>
)
}
}
export default withApollo(AddNoteSectionContainer);
I have a react-select component with options from a axios GET, I want my Car component to display an image from a url stored in the component state when the option is selected.
I am using componentDidMount and componentDidUpdate, however, in componentDidUpdate, this.getImage(capID); keeps firing, how can I prevent this and evoke it once?
import React from "react";
import axios from "axios";
import { Panel } from "react-bootstrap";
export default class CarList extends React.Component {
constructor(props) {
super(props);
this.state = {
imageSrc: ""
};
this.getImage = this.getImage.bind(this);
}
getImage(id) {
axios
.get(`xxx${id}`)
.then(response => {
this.setState({
imageSrc: response.data.url
});
})
.catch(error => {
console.log(error);
});
}
componentDidMount() {
const {
agrNo,
balloon,
bpid,
capID,
dealer,
derivative,
id,
make,
model,
name
} = this.props.car;
this.getImage(capID);
}
componentDidUpdate() {
const {
agrNo,
balloon,
bpid,
capID,
dealer,
derivative,
id,
make,
model,
name
} = this.props.car;
this.getImage(capID);
}
render() {
let car = this.props.car;
const {
agrNo,
balloon,
bpid,
capID,
dealer,
derivative,
id,
make,
model,
name
} = this.props.car;
return (
<div className="car-details">
<Panel header={name}>
<div className="flex-container">
<div className="flex-item">
{this.state.imageSrc && (
<img
src={this.state.imageSrc}
alt={model}
className="car-details__image"
/>
)}
</div>
<div className="flex-item">
<p>{car.Plot}</p>
<div className="car-info">
<div>
<span>Genre:</span> {car.Genre}
</div>
</div>
</div>
</div>
</Panel>
</div>
);
}
}
App:
import React, { Component } from "react";
import logo from "./logo.svg";
import axios from "axios";
import { Alert } from "react-bootstrap";
import AsyncSelect from "react-select/lib/Async";
import CarList from "./CarList";
import "react-select/dist/react-select.css";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
car: {}
};
}
getCars(e) {
return axios
.get(`xxx${e}`)
.then(response => {
var arr = [];
if (response.data !== undefined) {
var searchResults = response.data.length;
for (var i = 0; i < searchResults; i++) {
arr.push({
label: `${response.data[i].name} - ${response.data[i].id}`,
value: response.data[i].id
});
}
}
return {
options: arr
};
})
.catch(error => {
console.log(error);
});
}
getCar(e) {
axios
.get(`xxx}`)
.then(response => {
this.setState({
car: response.data
});
})
.catch(error => {
console.log(error);
});
}
render() {
const {
car: { id }
} = this.state;
return (
<div className="container">
<AsyncSelect
name="carOwner"
value="ABC"
cacheOptions
defaultOptions
loadOptions={this.getCars}
onChange={this.getCar.bind(this)}
/>
{id ? (
<CarList car={this.state.car} />
) : (
<Alert bsStyle="info">
<p>Enter a surname above to begin...</p>
</Alert>
)}
</div>
);
}
}
export default App;
componentDidUpdate will fire whenever any prop or state for this component has changed (checkout the official docs for more info).
You're changing the state inside the getImage(id) function, and every time that happens, the componentDidUpdate function will fire in your case, which will call the getImage function again, which will then became an infinite loop.
You need to check if the capID prop has changed, in order to decide if you should make the call again or not:
componentDidUpdate(oldProps) {
const {
agrNo,
balloon,
bpid,
capID,
dealer,
derivative,
id,
make,
model,
name
} = this.props.car;
const oldCapID = oldProps.capID;
if (capID !== oldCapID) {
this.getImage(capID);
}
}
I need the help with testing this component using expect library with karma and mocha.
import React from 'react';
import {Clock} from 'Clock';
import {CountdownForm} from "CountdownForm";
import {Controls} from "Controls";
export class Countdown extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
countdownStatus: 'stopped'
}
}
componentDidUpdate(prevProps, prevState) {
if(prevState.countdownStatus !== this.state.countdownStatus) {
switch (this.state.countdownStatus) {
case 'started':
this.timerID = setInterval(
this.tick,
1000
);
break;
case 'stopped':
console.log('stopped fireeed');
this.setState({count: 0});
case 'paused':
console.log('paused fireeed');
clearInterval(this.timerID)
this.timerID = undefined;
break;
}
}
}
componentWillUnmount() {
clearInterval(this.timerID)
this.timerID = undefined;
}
handleSetCountdown = (seconds) => {
this.setState({
count: seconds,
countdownStatus: 'started'
});
}
tick = () => {
console.log('tick fireeeed');
let newMoment = this.state.count - 1;
let newState = 'started'
if(newMoment === 0) {
newState = 'stopped'
}
this.setState(() => {
return {
count: newMoment >= 0 ? newMoment : 0,
countdownStatus: newState
}
})
}
handleStatusChange = (newStatus) => {
this.setState({
countdownStatus: newStatus,
})
}
render() {
const renderControlArea = () => {
if(this.state.countdownStatus !== 'stopped') {
return <Controls countdownStatus={this.state.countdownStatus} onStatusChange={this.handleStatusChange}/>
} else {
return <CountdownForm onSetCountdown={this.handleSetCountdown}/>
}
}
const count = this.state.count
return (
<div>
<Clock totalSeconds={count}/>
{renderControlArea()}
{/* <CountdownForm onSetCountdown={this.handleSetCountdown}/> */}
</div>
);
}
}
const Controls = (props) => {
const renderStartStopButton = (countdownStatus) => {
if(countdownStatus === 'started') {
return <button className="button secondary" onClick={() => props.onStatusChange('paused')}>Pause</button>
}
else if (countdownStatus === 'paused'){
return <button className="button primary" onClick={() => props.onStatusChange('started')}>Start</button>
}
}
return (
<div className="controls">
{renderStartStopButton(props.countdownStatus)}
<button className="button alert hollow" onClick={() => props.onStatusChange('stopped')}>Clear</button>
</div>
)
}
export {Controls}
I tried something like this but it didn't work, it seems like I should test if the function is called when countdownStatus is passed. Here is the error log:
import React from 'react';
import ReactDOM from 'react-dom';
import expect from 'expect';
import $ from 'jQuery';
import TestUtils from 'react-addons-test-utils';
import { Controls } from "Controls"
describe('Controls', () => {
it('should exist', () => {
expect(Controls).toExist()
});
describe('render', () => {
it('should render pause button when started', () => {
var controls = TestUtils.renderIntoDocument(<Controls countdownStatus={'started'}/>);
var $el = $(ReactDOM.findDOMNode(controls));
var $PauseBtn = $el.find('button:contains(Pause)');
expect($PauseBtn.length).toBe(1);
});
it('should render start button when paused', () => {
var controls = TestUtils.renderIntoDocument(<Controls countdownStatus={'paused'}/>);
var $el = $(ReactDOM.findDOMNode(controls));
var $StartBtn = $el.find('button:contains(Start)');
expect($StartBtn.length).toBe(1);
});
});
})
Well, the issue was that I couldn't node into the document before it got returned from the Control function. I figured it out, just in case someone is dealing with the similar issue keep in mind you are testing function not Class here is the code that fixes problem
import React from 'react';
import ReactDOM from 'react-dom';
import expect from 'expect';
import $ from 'jQuery';
import TestUtils from 'react-addons-test-utils';
import { Controls } from "Controls"
describe('Controls', () => {
it('should exist', () => {
expect(Controls).toExist()
});
describe('render', () => {
it('should render pause button when started', () => {
var controls = TestUtils.renderIntoDocument(Controls({countdownStatus:'started'}));
var $el = $(ReactDOM.findDOMNode(controls));
var $PauseBtn = $el.find('button:contains(Pause)');
expect($PauseBtn.length).toBe(1);
});
it('should render start button when paused', () => {
var controls = TestUtils.renderIntoDocument(Controls({countdownStatus:'paused'}));
var $el = $(ReactDOM.findDOMNode(controls));
var $StartBtn = $el.find('button:contains(Start)');
expect($StartBtn.length).toBe(1);
});
});
})