Jest and Enzyme with React: Mock method with Translate - reactjs

I am doing some unit tests for a project I'm working on, and I have the following Modal on React. Note that I usually pass t for translation, which I am attempting to do in the test but it's working:
import React, { Component } from 'react'
import { Modal, Button } from 'react-bootstrap'
import {translate} from 'react-polyglot'
class MessageModal extends Component {
render () {
const {messageModal: {message, isOpen}, closeMessageModal, t} = this.props
return (
<Modal show={isOpen}>
<Modal.Body>
{message ? t(`MESSAGE_MODAL.${message}`) : ''}
</Modal.Body>
<Modal.Footer>
<Button onClick={closeMessageModal}>Close</Button>
</Modal.Footer>
</Modal>
)
}
}
export default translate()(MessageModal)
and the following test:
import React from 'react'
import MessageModal from './MessageModal'
import { shallow } from 'enzyme'
import { shallowToJson } from 'enzyme-to-json'
// import {translate} from 'react-polyglot'
describe('Testing MessageModal', () => {
const tree = shallow(
<MessageModal t={jest.fn()} messageModal={{message: 'message', isOpen: true}}/>
)
it('Renders correctly', () => {
expect(shallowToJson(tree.dive().setProps({t: jest.fn()}))).toMatchSnapshot()
})
})
And I'm getting two main errors:
TypeError: t is not a function
and
Warning: Failed context type: The context `t` is marked as required in `_translate`, but its value is `undefined`.
I have tried everything to get this solved but I wasn't able to make it work. If you could help me that'd be great.

What you could do is also exporting the not decorated MessageModal component.
import React, { Component } from 'react'
import { Modal, Button } from 'react-bootstrap'
import {translate} from 'react-polyglot'
export class MessageModal extends Component {
render () {
const {messageModal: {message, isOpen}, closeMessageModal, t} = this.props
return (
<Modal show={isOpen}>
<Modal.Body>
{message ? t(`MESSAGE_MODAL.${message}`) : ''}
</Modal.Body>
<Modal.Footer>
<Button onClick={closeMessageModal}>Close</Button>
</Modal.Footer>
</Modal>
)
}
}
export default translate()(MessageModal)
This way you can import the not decorated component in your test so you don't have to deal with the higher order component part.
import { MessageModal } from './MessageModal'

Related

SyntaxError: Cannot use import statement outside a module with dynamic import of Nextjs

I followed the doc of SunEditor, it's like:
import React from 'react';
import dynamic from "next/dynamic";
import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
const SunEditor = dynamic(() => import("suneditor-react"), {
ssr: false,
});
const MyComponent = props => {
return (
<div>
<p> My Other Contents </p>
<SunEditor />
</div>
);
};
export default MyComponent;
It works well, but when I add setOptions into SunEditor:
import { buttonList } from "suneditor-react";
...
<SunEditor
setOptions={{buttonList:buttonList.complex}}
/>
I got this error:
SyntaxError: Cannot use import statement outside a module
Am I missing something, and how can I fix it?
For the same reason you have to dynamically import SunEditor, you also have to dynamically import buttonList.
One approach is to create a custom component where you add all the suneditor code.
import React from 'react';
import SunEditor, { buttonList } from 'suneditor-react';
const CustomSunEditor = () => {
return <SunEditor setOptions={{ buttonList: buttonList.complex }} />;
};
export default CustomSunEditor;
Then, dynamically import that component with next/dynamic where needed.
const CustomSunEditor = dynamic(() => import('../components/CustomSunEditor'), {
ssr: false,
});
const MyComponent = props => {
return (
<div>
<p> My Other Contents </p>
<CustomSunEditor />
</div>
);
};

default is not a function React Type error

Hi guys i want to make speech to text in React component. But when i run it I get this error:
react_speech_recognition__WEBPACK_IMPORTED_MODULE_1___default(...) is not a function
Can someone show me what to do?
import React, { Component } from 'react'
import SpeechRecognition from 'react-speech-recognition'
class Mic extends Component {
render() {
const { transcript, resetTranscript, browserSupportsSpeechRecognition } = this.props
if (!browserSupportsSpeechRecognition) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
}
export default SpeechRecognition(Mic)
In app.js i run it like this (if this is necessary):
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Container from './components/container/Container';
import Database from './components/database/Database';
import Mic from './components/mic/Mic';
import Test from './components/test/Test';
function App() {
return (
<Mic/>
//<Test/>
);
}
export default App;
It is because of this line SpeechRecognition(Mic) . The Error states that the default export from your module is not a function which means that SpeechRecognition is not a function so you cannot call it .
change your code as
import React from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition'
const Mic = () => {
const { transcript, resetTranscript } = useSpeechRecognition()
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
export default Mic
Looks like you have installed the latest version, but trying to use it in old way.
Please take a look at this Migration Guide

Why Enzyme test unworking in React?

I need to test Button component
it's Button :
import React from "react";
import './Button.css'
const Button = props => {
return(
<button className={"Button"}
onClick={props.onClick}
disabled={props.disabled}
>
{props.children}
</button>
)
}
export default Button
It's my Button.test.js:
import React from 'react';
import {shallow} from 'enzyme';
import Button from "./Button";
it('has a title class', () => {
const wrapper = shallow(<Button/>);
expect(wrapper.hasClass('Button')).to.equal(true);
I'm add enzyme to react. In the console I has an error:
enter image description here
tell me how to solve the problem, i'm new in React.
You need to call hasClass on the button element instead of the wrapper:
expect(wrapper.find('button').hasClass('Button')).to.equal(true);

React typescript test on enzyme doesn't simulate click

I'm trying to simulate a click on a button but the test always fails and I have no idea why. It seems that enzyme can't select the DOM element to trigger a click on it, because the calls are always 0. I am using enzyme 3.7.0 and jest 23.6.0
Button.tsx
import * as React from 'react';
import './button.scss';
export interface IButton {
value: string;
onClick: () => void;
}
class Button extends React.Component<IButton, {}> {
render() {
return (
<div className="Button">
<button id="btn" onClick={this.props.onClick} className="Button__btn" type="button">
{this.props.value}
</button>
</div>
);
}
}
export default Button;
Button.test.tsx
import * as React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';
test.only('Button test', () => {
const myMock = jest.fn();
const mockedButton = shallow(<Button value="testvalue" onClick={() => myMock} />);
console.log(mockedButton.debug());
// Interaction demo
expect(mockedButton.text()).toEqual('testvalue');
mockedButton.find('button').simulate('click');
mockedButton.find('.Button__btn').simulate('click');
mockedButton.find('button.Button__btn').simulate('click');
expect(myMock.mock.calls.length).toBe(0); // !! Should be 3 ?
// Snapshot demo
expect(mockedButton).toMatchSnapshot();
});
However, the snapshot generated could allow me to select the right element (button)
exports[`Button test 1`] = `
<div
className="Button"
>
<button
className="Button__btn"
onClick={[Function]}
>
testvalue
</button>
</div>
`;
The reason is this part:
onClick={() => myMock}
Here you describe click handler that returns your mock instead of calling it. It should be onClick={() => myMock()} or better just onClick={myMock}
instead. There React will call your myMock on .simulate('click')

React exporting withRouter and withStyles error

I am using react along with redux and material-ui to make a component. I am attempting to write an export statement export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
However, this doesn't seem to work I get an error that says
TypeError: Cannot set property 'props' of undefined
this.props = props;
This error is referencing one of my node_modules.
Here is my full code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {withRouter} from 'react-router-dom'
import { withStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
const styles = theme =>({
root: {
maxWidth: 345,
},
})
class FirstPage extends Component {
state = {
feeling: ''
}
//This function will dispatch the users response to index.js
//The dispatch type here is 'SET_FEELING'
submitData=(event) => {
event.preventDefault();
this.props.dispatch({type: 'SET_FEELING', payload: this.state})
this.changeLocation();
}
//This function will update the local state with the users response
handleChange= (event) => {
this.setState({
feeling: event.target.value
})
}
//This function will change the current url when a button is clicked
changeLocation= ()=> {
this.props.history.push('/secondPage')
}
render(){
const { classes } = this.props;
return(
<div>
<Card >
<CardContent className={classes.root}>
<form>
<input onChange={this.handleChange} placeholder='How are you feeling' value={this.state.feeling} />
</form>
</CardContent>
<CardActions>
<Button onClick={this.submitData}>Submit</Button>
</CardActions>
</Card>
</div>
)
}
}
//this export connects the component to the reduxStore as well as allowing us to use the history props
export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
I believe the following code should work:
export default withRouter(connect()(withStyles(styles)(FirstPage)))
Instead of
export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
First of all, connect() returns a function that only accepts an argument. Second, connect() should be wrapped inside withRouter(). This problem is stated in the github docs of React Router.
without using react-redux :
export default (withStyles(styles), withRouter)(FirstPage);

Resources