jest can't transpile static state in react - javascript

Below code failed with jest, I got unexpected token error
export default class Search extends Component {
state = { // problem is here
q: ''
}
onChange = e => {
this.setState({
q: e.target.value
})
}
render() {
return (
<div>
<input onChange={this.onChange} placeholder="search" />
</div>
)
}
}
I'm using babel-7, any plugin I need to pull in for jest?
I'm using jest version ^23.6.0

You need to add babel-plugin-transform-class-properties if you want to use class properties. So install it then make sure you add it as a plugin in your .babelrc file like this:
"plugins": [
"#babel/plugin-proposal-class-properties"
]

Either use a constructor and define your state with this.state:
constructor(props) {
super(props)
this.state = {
q: ''
}
}
or use https://www.npmjs.com/package/babel-plugin-transform-class-properties.
Class fields are still a stage 3 proposal https://github.com/tc39/proposal-class-fields

Related

Babel React transpiling to `fileName.Component` instead of just `Component`

I am having to call my react component as component.Component, like below. Also to note, the first part is the file name. If the rename the file, I have to say (newFileName.LikeButton).
instead of
ReactDOM.render(React.createElement(LikeButton) , domContainer);
Any idea how I can resolve this? Here is my setup. My babel.config.json
{
"presets": ["#babel/preset-react", "#babel/preset-env" ],
"plugins": [ "#babel/plugin-transform-modules-umd" ]
}
my react component in likeButton.jsx
export class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
render() {
if (this.state.liked) {
return 'You liked this.';
}
return (<button onClick={() => this.setState({ liked: true }) }>
Like
</button>
);
}
}
Warning, this answer is speculative (but too long for a comment)
I suspect your imports look something like this:
import likeButton from './somePath/likeButton'
but, because you are using named exports, (as opposed to default exports), your import should actually look like:
import { LikeButton } from './somePath/likeButton'
to "destructure" LikeButton from the module.

Unexpected token = (with espree parser in module mode) in my react project using sonar-scanner

I am facing this error while using sonar-scanner.
It is unable to parse all those files in which i have used arrow functions.
import React from "react";
import { Button } from "antd";
import history from "src/components/history";
class BackButton extends React.Component {
handleClick = () => {
history.goBack();
if (this.props.onBack) {
this.props.onBack();
}
};
render() {
return <Button icon="arrow-left" onClick={this.handleClick} />;
}
}
export default BackButton;
The error at line 6.
Need a solution to fix this.
in order to use arrow functions inside a class you need to enable this plugin in your babel configuration.
{
"plugins": [
"transform-class-properties"
]
}
or you can do it like this
class BackButton extends React.Component {
constructor() {
super();
this.handleClick = (val) => {
...
};
…
}
}
I suspect the problem isn't arrow functions, it's class fields. Your handleClick is a class field (basically a property declaration) using an arrow function as its initializer. The class fields proposal is mature, but still at Stage 3, not actually in the spec yet (not even ES2020). In contrast, arrow functions have been in the language for over five years.
You'll need to be sure to enable support for class fields.

React app. Can't call setState on a component that is not yet mounted

I am getting the following warning when I try and change the value on an input field.
Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the Login component.
I cannot understand why this is happening, it is not happening on any of my other react pages.
The only difference is that this is the login page so has it's own routing to the page.
Can anyone help? I've stripped my component back to the bare bones to see if anyone can spot what I am doing wrong.
import React, { Component } from 'react';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
};
this.onChange = this.onChange.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
const { username } = this.state;
return (
<input type="text" placeholder="Email" className="form-control" name="username" autoComplete="email" value={username} onChange={this.onChange} />
);
}
}
export default Login;
The problem wasn't because of my component, it was because I had changed my webpack config to support async await es7 feature. to the following...
"presets": [ "es2017" , "stage-0" , "react" ]
instead I actually needed to do the next answer down and install
npm install --save-dev regenerator-runtime
https://stackoverflow.com/a/51650116/3284707
Doing the answer from the link above fixed my problems.

javascript private property syntax unrecognised

Question clarification:
Specifically, Id like to know how the example below can be written without typescript. Understanding how to declare properties on classes etc. would be useful to me. I believe it should be possible to use blueprintjs (which is written in typescript), without using typescript in my implementations.
I'm following docs at:http://blueprintjs.com/docs/#components.toaster.js.react
There is sample code like this:
import { Button, Position, Toaster } from "#blueprintjs/core";
class MyComponent extends React.Component {
private toaster: Toaster;
private refHandlers = {
toaster: (ref: Toaster) => this.toaster = ref,
};
public render() {
return (
<div>
<Button onClick={this.addToast} text="Procure toast" />
<Toaster position={Position.TOP_RIGHT} ref={this.refHandlers.toaster} />
</div>
)
}
private addToast = () => {
this.toaster.show({ message: "Toasted!" });
}
}
But I get Syntax Error: Unexpected token, expected ( (5:16) which is the 'toaster' after 'private'. I am not precompiling typescript. I'm using es6 with webpack. How would I re-write this sample code to work with my environment?
Thanks.
blueprintjs is implemented using typescript, and that example is using typescript syntax.
See: http://blueprintjs.com/docs/#TypeScript
Here's how I did it. I got a bit of help from webpack based on this tutorial: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html. I set the target in the tsconfig.json configuration file to es6, and this is what webpack compiled to (more or less).
Any manual improvements to this solution welcome.
import {Button, Position, Toaster} from "#blueprintjs/core";
class ToastLauncher extends React.Component {
constructor(props) {
super(props);
this.refHandlers = {
toaster: (ref) => this.toaster = ref,
};
this.addToast = () => {
this.toaster.show({ message: "Toasted!" });
};
}
render() {
return (
<div>
<Button onClick={this.addToast} text="Procure toast" />
<Toaster position={Position.TOP_RIGHT} ref={this.refHandlers.toaster} />
</div>
)
}
}
export default ToastLauncher

How to test decorated React component with shallow rendering

I am following this tutorial: http://reactkungfu.com/2015/07/approaches-to-testing-react-components-an-overview/
Trying to learn how "shallow rendering" works.
I have a higher order component:
import React from 'react';
function withMUI(ComposedComponent) {
return class withMUI {
render() {
return <ComposedComponent {...this.props}/>;
}
};
}
and a component:
#withMUI
class PlayerProfile extends React.Component {
render() {
const { name, avatar } = this.props;
return (
<div className="player-profile">
<div className='profile-name'>{name}</div>
<div>
<Avatar src={avatar}/>
</div>
</div>
);
}
}
and a test:
describe('PlayerProfile component - testing with shallow rendering', () => {
beforeEach(function() {
let {TestUtils} = React.addons;
this.TestUtils = TestUtils;
this.renderer = TestUtils.createRenderer();
this.renderer.render(<PlayerProfile name='user'
avatar='avatar'/>);
});
it('renders an Avatar', function() {
let result = this.renderer.getRenderOutput();
console.log(result);
expect(result.type).to.equal(PlayerProfile);
});
});
The result variable holds this.renderer.getRenderOutput()
In the tutorial the result.type is tested like:
expect(result.type).toEqual('div');
in my case, if I log the result it is:
LOG: Object{type: function PlayerProfile() {..}, .. }
so I changed my test like:
expect(result.type).toEqual(PlayerProfile)
now it gives me this error:
Assertion Error: expected [Function: PlayerProfile] to equal [Function: withMUI]
So PlayerProfile's type is the higher order function withMUI.
PlayerProfile decorated with withMUI, using shallow rendering, only the PlayerProfile component is rendered and not it's children. So shallow rendering wouldn't work with decorated components I assume.
My question is:
Why in the tutorial result.type is expected to be a div, but in my case isn't.
How can I test a React component decorated with higher order component using shallow rendering?
You can't. First let's slightly desugar the decorator:
let PlayerProfile = withMUI(
class PlayerProfile extends React.Component {
// ...
}
);
withMUI returns a different class, so the PlayerProfile class only exists in withMUI's closure.
This is here's a simplified version:
var withMUI = function(arg){ return null };
var PlayerProfile = withMUI({functionIWantToTest: ...});
You pass the value to the function, it doesn't give it back, you don't have the value.
The solution? Hold a reference to it.
// no decorator here
class PlayerProfile extends React.Component {
// ...
}
Then we can export both the wrapped and unwrapped versions of the component:
// this must be after the class is declared, unfortunately
export default withMUI(PlayerProfile);
export let undecorated = PlayerProfile;
The normal code using this component doesn't change, but your tests will use this:
import {undecorated as PlayerProfile} from '../src/PlayerProfile';
The alternative is to mock the withMUI function to be (x) => x (the identity function). This may cause weird side effects and needs to be done from the testing side, so your tests and source could fall out of sync as decorators are added.
Not using decorators seems like the safe option here.
Use Enzyme to test higher order / decorators with Shallow
with a method called dive()
Follow this link, to see how dive works
https://github.com/airbnb/enzyme/blob/master/docs/api/ShallowWrapper/dive.md
So you can shallow the component with higher order and then dive inside.
In the above example :
const wrapper=shallow(<PlayerProfile name={name} avatar={}/>)
expect(wrapper.find("PlayerProfile").dive().find(".player-profile").length).toBe(1)
Similarly you can access the properties and test it.
You can use 'babel-plugin-remove-decorators' plugin. This solution will let you write your components normally without exporting decorated and un-decorated components.
Install the plugin first, then create a file with the following content, let us call it 'babelTestingHook.js'
require('babel/register')({
'stage': 2,
'optional': [
'es7.classProperties',
'es7.decorators',
// or Whatever configs you have
.....
],
'plugins': ['babel-plugin-remove-decorators:before']
});
and running your tests like below will ignore the decorators and you will be able to test the components normally
mocha ./tests/**/*.spec.js --require ./babelTestingHook.js --recursive
I think the above example is confusing because the decorator concept is used interchangeably with idea of a "higher order component". I generally use them in combination which will make testing/rewire/mocking easier.
I would use decorator to:
Provide props to a child component, generally to bind/listen to a flux store
Where as I would use a higher order component
to bind context in a more declarative way
The problem with rewiring is I don't think you can rewire anything that is applied outside of the exported function/class, which is the case for a decorator.
If you wanted to use a combo of decorators and higher order components you could do something like the following:
//withMui-decorator.jsx
function withMUI(ComposedComponent) {
return class withMUI extends Component {
constructor(props) {
super(props);
this.state = {
store1: ///bind here based on some getter
};
}
render() {
return <ComposedComponent {...this.props} {...this.state} {...this.context} />;
}
};
}
//higher-order.jsx
export default function(ChildComp) {
#withMui //provide store bindings
return class HOC extends Component {
static childContextTypes = {
getAvatar: PropTypes.func
};
getChildContext() {
let {store1} = this.props;
return {
getAvatar: (id) => ({ avatar: store1[id] });
};
}
}
}
//child.js
export default Child extends Component {
static contextTypes = {
getAvatar: PropTypes.func.isRequired
};
handleClick(id, e) {
let {getAvatar} = this.context;
getAvatar(`user_${id}`);
}
render() {
let buttons = [1,2,3].map((id) => {
return <button type="text" onClick={this.handleClick.bind(this, id)}>Click Me</button>
});
return <div>{buttons}</div>;
}
}
//index.jsx
import HOC from './higher-order';
import Child from './child';
let MyComponent = HOC(Child);
React.render(<MyComponent {...anyProps} />, document.body);
Then when you want to test you can easily "rewire" your stores supplied from the decorator because the decorator is inside of the exported higher order component;
//spec.js
import HOC from 'higher-order-component';
import Child from 'child';
describe('rewire the state', () => {
let mockedMuiDecorator = function withMUI(ComposedComponent) {
return class withMUI extends Component {
constructor(props) {
super(props);
this.state = {
store1: ///mock that state here to be passed as props
};
}
render() {
//....
}
}
}
HOC.__Rewire__('withMui', mockedMuiDecorator);
let MyComponent = HOC(Child);
let child = TestUtils.renderIntoDocument(
<MyComponent {...mockedProps} />
);
let childElem = React.findDOMNode(child);
let buttons = childElem.querySelectorAll('button');
it('Should render 3 buttons', () => {
expect(buttons.length).to.equal(3);
});
});
I'm pretty sure this doesn't really answer your original question but I think you are having problems reconciling when to use decorators vs.higher order components.
some good resources are here:
http://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
https://github.com/badsyntax/react-seed/blob/master/app/components/Menu/tests/Menu-test.jsx
https://github.com/Yomguithereal/baobab-react/blob/master/test/suites/higher-order.jsx
In my case decorators are very useful and I dont want to get rid of them (or return wrapped and unwrapped versions) im my application.
The best way to do this in my opinion is to use the babel-plugin-remove-decorators (which can be used to remove them in tests) has Qusai says, but I wrote the pre-processor differently like below:
'use strict';
var babel = require('babel-core');
module.exports = {
process: function(src, filename) {
// Ignore files other than .js, .es, .jsx or .es6
if (!babel.canCompile(filename)) {
return '';
}
if (filename.indexOf('node_modules') === -1) {
return babel.transform(src, {
filename: filename,
plugins: ['babel-plugin-remove-decorators:before']
}).code;
}
return src;
}
};
Take notice of the babel.transform call that im passing the babel-plugin-remove-decorators:before element as an array value, see: https://babeljs.io/docs/usage/options/
To hook this up with Jest (which is what I used), you can do it with settings like below in your package.json:
"jest": {
"rootDir": "./src",
"scriptPreprocessor": "../preprocessor.js",
"unmockedModulePathPatterns": [
"fbjs",
"react"
]
},
Where preprocessor.js is the name of the preprocessor.

Categories

Resources