Test map function with jest - javascript

I have a problem with testing this component that has a map function for rendering various icontype:
import { FaSwimmer, FaWifi, FaCoffee, FaUtensils, FaSnowflake, FaSmokingBan, FaCocktail, FaPaw, FaCar, FaConciergeBell, FaDumbbell, FaSpa, FaTv } from "react-icons/fa";
import "./Characteristics.css";
function Characteristics(props) {
const { productCharacteristics, page } = props;
function parseIcons(icon) {
case 'FaWiFi':
return <FaWifi className="service-icon-home" />
case 'FaSwim':
return <FaSwimmer className="service-icon-home swimmer-icon" />
case 'FaCoffee':
return <FaCoffee className="service-icon-home" />
case 'FaUtensils':
return <FaUtensils className="service-icon-home" />
case 'FaSnowflake':
return <FaSnowflake className="service-icon-home" />
case 'FaSmokingBan':
return <FaSmokingBan className="service-icon-home" />
case 'FaCocktail':
return <FaCocktail className="service-icon-home" />
case 'FaPaw':
return <FaPaw className="service-icon-home" />
case 'FaCar':
return <FaCar className="service-icon-home" />
case 'FaConciergeBell':
return <FaConciergeBell className="service-icon-home" />
case 'FaDumbbell':
return <FaDumbbell className="service-icon-home" />
case 'FaSpa':
return <FaSpa className="service-icon-home" />
case 'FaTv':
return <FaTv className="service-icon-home" />
}
}
};
if (page === "home") {
return (
<ul className="services-icons">
{productCharacteristics.map((characteristic) => (
<li className="service-icon" key={characteristic.id}>
{parseIcons(characteristic.icon)}
</li>
))}
</ul>
)
} else {
return (
<ul className="services">
{productCharacteristics.map((characteristic) => (
<li className="service" key={characteristic.id}>
{parseIcons(characteristic.icon)}
<span>{characteristic.name}</span>
</li>
))}
</ul>
);
};
};
export default Characteristics;
The test in jest for render list of characteristics is
import React from 'react'
import {screen, render, within} from '#testing-library/react'
import Characteristics from './Characteristics'
beforeEach(() => render(<Characteristics />));
describe('Test for Characteristics', () => {
test('Render list of characteristics"', () => {
const list = screen.getByRole("list", {
name: "",
})
const {getAllByRole} = within(list)
const items = getAllByRole("listitem")
expect(items.length).toBe(13)
});
});
The error in this line {productCharacteristics.map((characteristic) and console is:
TypeError: Cannot read property 'map' of undefined

Related

Elegant ways of handling conditional rendering of multiple components

Say I have a wizard-like view with an arbitrary number of steps:
const StepsComponent = () => {
const [stage, setStage] = useState(1);
const stageProps = {stage, setStage};
const stageMachine = () => {
switch (stage) {
case 1:
return <One {...stageProps} />;
case 2:
return <Two {...stageProps} />;
case 3:
return <Three {...stageProps} />;
default:
return <One {...stageProps} />;
}
};
return (
<>
{stageMachine()}
</>
);
}
Are there more elegant ways of handling such cases, other than switch statements or ternary expressions?
If I would have wizards with 10+ steps, then it'd be a real mess to manage it.
Probably I could do something like this but this seems hacky, doesn't it?
const stageMachine = Object.freeze({
1: <One {...stageProps} />,
2: <Two {...stageProps} />,
3: <Three {...stageProps} />
});
Also I don't like the idea of invoking stageMachine function in return, it is considered a bad practice?
You can try this
const StepsComponent = () => {
const [stage, setStage] = useState(1);
return (
<>
{stage === 1 && <One />}
{stage === 2 && <Thow />}
{stage === 3 && <Three />}
</>
);
}

using if-else statements in React JSX

I'm trying to display react component based on what the pair name is, but I am not sure how to get that to happen. This is the code I have so far, any suggestions?
class App extends React.Component {
state = {
bases: ['EUR', 'AUD', 'CAD', 'JPY', 'NZD'],
selectedBase: 'USD',
};
displayGraph = () => {
if(document.getElementById('pairName').innerText === 'USD/EUR'){
<Graph defaultBase={"EUR"} />
} else if (document.getElementById('pairName').innerText === 'USD/CAD'){
<Graph defaultBase={"CAD"} />
} else if(document.getElementById('pairName').innerText === 'USD/AUD'){
<Graph defaultBase={"NZD"}/>
} else if(document.getElementById('pairName').innerText === 'USD/NZD'){
<Graph defaultBase={"AUD"}/>
} else if (document.getElementById('pairName').innerText === 'USD/JPY') {
<Graph defaultBase={"JPY"}/>
}
}
render(){
return (
<div id="three">
<h2 id="pairName">USD/EUR</h2>
{/* GOAL: show graphs when correct pairs are selected */}
{this.displayGraph}
</div>
}
}
export default App;
In your code I think you are missing return before the <Graph... />.
However another way you could do this could also be like this:
class App extends React.Component {
state = {
bases: ['EUR', 'AUD', 'CAD', 'JPY', 'NZD'],
selectedBase: 'USD',
};
displayGraph = () => {
switch(document.getElementById('pairName').innerText) {
case 'USD/EUR':
return <Graph defaultBase={"EUR"} />;
case 'USD/CAD':
return <Graph defaultBase={"CAD"} />;
case 'USD/AUD':
return <Graph defaultBase={"NZD"}/>;
case 'USD/NZD':
return <Graph defaultBase={"AUD"}/>;
case 'USD/JPY':
return <Graph defaultBase={"JPY"}/>;
}
render(){
return (
<div id="three">
<h2 id="pairName">USD/EUR</h2>
{this.displayGraph}
</div>
}
}
export default App;
P.s. As a side note, I would look at converting the React class to a function and using the useState hook as it is the newer way of writing react code. You can read more about it here.

I got this this error >> Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null

I want to render Modal componen if data.alarmMode === EMERGENCY, however, I am not able to rendering anything and getting this error. I have tried to fix this problem but I am not able to fix this problem. I don't know why react cannot render Modal componenet.
return (
<Modal key={hash} hash={hash} data={alarmData[hash]} onClickAlarmOff={onClickAlarmOff} clockMode={clockMode} onClickCloseModal={onClickCloseModal} />
)
in case
import React, { useState } from 'react';
import CurrentTimeBox from './CurrentTimeBox';
import AlarmList from './AlarmList';
import AddAlarm from './AddAlarm';
import styles from './ClockBox.module.css';
import ModalEvent from '../containers/ModalEvent';
import { EMERGENCY, NIGHT } from '../constants';
import Modal from '../components/Modal';
import ClockModeBox from './ClockModeBox';
const ClockBox = ({ timeString, onClickCloseModal, makeModalvisible, currentTime, clockMode, modal, alarmData, onClickAlarmOn, onClickAlarmOff, ClockModeFunctionLists }) => {
return (
<div className={styles.ClockBox}>
<CurrentTimeBox currentTime={currentTime} />
<ClockModeBox ClockModeFunctionLists={ClockModeFunctionLists} clockMode={clockMode}/>
<div className={styles.AlarmLists}>
{Object.keys(alarmData).length > 1 && alarmData.dataLists.map((hash) =>{
const data = alarmData[hash]
return (
<AlarmList key={hash} hash={hash} data={data} onClickAlarmOn={onClickAlarmOn} onClickAlarmOff={onClickAlarmOff}/>
)
})
}
</div>
<AddAlarm />
{timeString.length > 0 && Object.keys(alarmData).length > 1 ? alarmData.dataLists.map((hash) => {
const data = alarmData[hash]
if (data.time === timeString && data.on) {
if (clockMode === NIGHT) {
if (data.alarmMode === EMERGENCY) {
makeModalvisible();
return (
<Modal key={hash} hash={hash} data={alarmData[hash]} onClickAlarmOff={onClickAlarmOff} clockMode={clockMode} onClickCloseModal={onClickCloseModal} />
)
} else {
return null;
}
}
makeModalvisible();
// if (modal) {
return (
<Modal key={hash} hash={hash} data={alarmData[hash]} onClickAlarmOff={onClickAlarmOff} clockMode={clockMode} onClickCloseModal={onClickCloseModal} />
)
// }
}
}) : null
}
</div>
)
};
export default ClockBox;
updated code
return (
<div className={styles.ClockBox}>
<CurrentTimeBox currentTime={currentTime} />
<ClockModeBox ClockModeFunctionLists={ClockModeFunctionLists} clockMode={clockMode}/>
<div className={styles.AlarmLists}>
{Object.keys(alarmData).length > 1 && alarmData.dataLists.map((hash) =>{
const data = alarmData[hash]
return (
<AlarmList key={hash} hash={hash} data={data} onClickAlarmOn={onClickAlarmOn} onClickAlarmOff={onClickAlarmOff}/>
)
})
}
</div>
<AddAlarm />
{timeString.length > 0 && Object.keys(alarmData).length > 1 ? alarmData.dataLists.map((hash) => {
const data = alarmData[hash]
if (data.time === timeString && data.on) {
debugger;
if (clockMode === NIGHT) {
if (data.alarmMode === EMERGENCY) {
makeModalvisible();
return (
<Modal key={hash} hash={hash} data={alarmData[hash]} onClickAlarmOff={onClickAlarmOff} clockMode={clockMode} onClickCloseModal={onClickCloseModal} />
)
} else {
return null;
}
}
makeModalvisible();
// if (modal) {
return (
<Modal key={hash} hash={hash} data={alarmData[hash]} onClickAlarmOff={onClickAlarmOff} clockMode={clockMode} onClickCloseModal={onClickCloseModal} />
)
// }
} else {
return null;
}
}) : null
}
</div>
)
modal component
import React from 'react';
import { VIBRATION, NORMAL, NIGHT } from '../constants';
import styles from "./Modal.module.css";
const Modal = ({ onClickCloseModal, data, clockMode, hash, onClickAlarmOff }) => {
const SOUND_EFFECT = 'https://pp.netclipart.com/pp/s/35-354079_jpg-transparent-library-hotel-front-desk-service-bell.png';
const VIBRATION_EFFECT = 'https://st2.depositphotos.com/4520249/7558/v/950/depositphotos_75586693-stock-illustration-vibration-mode-phone-icon.jpg';
let imgComponent = null;
switch(clockMode) {
case NORMAL:
imgComponent = <img src={SOUND_EFFECT} />
break;
case VIBRATION:
imgComponent = <img width="200px" height="200px" src={VIBRATION_EFFECT} />
break;
default:
return;
}
return (
<div className={styles.Modal} >
<div className={styles.ModalOverLay}></div>
<div className={styles.ModalContent}>
{imgComponent}
<p>{data.label}</p>
<button className={styles.CloseButton} onClick={() => {
onClickCloseModal();
onClickAlarmOff(hash);
console.log(33333)
}}>close</button>
</div>
</div>
)
}
export default Modal;
If the clockMode is not 'emergency the component do render Modal component correctly. However, what I want to do is render Modal component in case if (data.alarmMode === EMERGENCY)
I don't know why it cannot render in this condition even if I used return statement.
update
const modalOn = () => ({ type: MODAL_ON });
makeModalvisible: () => dispatch(modalOn())
there was no problem with mpodalOn, I checked modal status was changed
I debugged and debugger went inside of if (data.alarmMode === EMERGENCY)
the problem is when ClockBox component can't render Modal component....
if if I used return statement
I think this could be because you do not have an else statement after the following if statement: if (data.time === timeString && data.on).
So when this requirement is not met, React will not know what to render.

How to make React slick slider work with icons?

There is a code that displays icons
switch (name) {
case Header.Arrows.name:
return <ArrowsComponent key={name} color={color}/>;
case Header.Zoom.name:
return <ZoomTool key={name} color={color}/>;
default:
return null;
}
I want to not just display them but do it using the react slick slider. ArrowsComponent and ZoomTool are the components for icons. How to properly wrap this code in <Slider> .. </Slider>?
Here are my two ways
Method 1:
switch (name) {
case Header.Arrows.name:
return (
<Slider>
<ArrowsComponent key={name} color={color}/>
</Slider>
);
case Header.Zoom.name:
return (
<Slider>
<ZoomTool key={name} color={color}/>
</Slider>
);
default:
return null;
}
Method 2
const renderSlider = (child) => {
return (
<Slider>
{child}
</Slider>
);
};
switch (name) {
case Header.Arrows.name:
renderSlider(<ArrowsComponent key={name} color={color}/>);
case Header.Zoom.name:
renderSlider(<ZoomTool key={name} color={color}/>);
default:
return null;
}
Hope that helps.

How can I test a switch case that depends on a parameter?

I have this:
const renderComponents = () => {
switch (selectedService) {
case 'otherservices':
return <SoftLayerCancellationRequests />;
case 'dedicatedhosts':
return <GetDedicatedHostsCancellations />;
case 'virtualguestsservers':
return <SoftLayerGetVirtualGuests />;
case 'baremetalservers':
return <GetBareMetalServersCancellations />;
default:
return null;
}
};
Which at the end is called on the return statement of the component:
return (
<>
<Header pageTitle={t('cancellations.header')} />
{accountId ? (
<>
<TableToolbarComp />
{renderComponents()}
</>
) : (
<UpgradeMessage />
)}
</>
);
And the selectedService parameter is coming from a store:
export default compose(
connect(store => ({
accountId: store.global.softlayerAccountId,
selectedService: store.cancellations.selectedService,
})),
translate(),
hot(module),
)(Cancellations);
What can I do to test that switch case?
The function under renderComponents should accept selectedService as a parameter:
const renderComponents = (selectedService) => {
switch (selectedService) {
// ...
}
};
By not relying on a closure, the function becomes pure and is way easier to unit test :
it('renders a SoftLayerCancellationRequests when passed "otherservices" as parameter', () => {
const wrapper = shallow(renderComponents('otherservices'));
expect(wrapper.find(SoftLayerCancellationRequests)).toHaveLength(1);
})
Yet, I see little value in such tests. This is because the function basically acts as a simple map :
const serviceToComponent : {
otherservices: SoftLayerCancellationRequests,
dedicatedhosts: GetDedicatedHostsCancellations,
virtualguestsservers: SoftLayerGetVirtualGuests,
baremetalservers: GetBareMetalServersCancellations
}
which seems a bit dull to test.
A more meaningful test would be to test the behaviors of the component that uses such a mapping.

Categories