Testing React app with Jest: Unexpected token - reactjs

I'm building a React/Redux/ReactRouter/Jest boilerplate but I'm having an issue when testing a component with react-test-renderer.
I have put in place two kind of tests: unit tests for my redux actions and snapshot tests as a form of functional tests for my components.
First of all, my unit tests work perfectly. Here's one:
import mockStore from 'redux-mock-store';
import {fetchWordDefinitions} from '../src/actions';
describe('Async fetch of word definitions', () => {
it('fetches a word definitions', async () => {
const mockedResponse = [
{text: 'First definition'},
{text: 'Second definition'},
{text: 'Third definition'}
];
fetch.mockResponse(JSON.stringify(mockedResponse));
const store = mockStore({});
await store.dispatch(fetchWordDefinitions('whatever'));
expect(store.getActions()).toEqual([
{type: 'ERROR', error: null},
{type: 'FETCHING', fetching: true},
{
type: 'WORD_DEFINITIONS',
word: 'whatever',
definitions: [
"First definition",
"Second definition",
"Third definition"
]
},
{type: 'FETCHING', fetching: false}
]);
});
});
As you can see I'm using ES6 there (both in the test and in the tested action) and everything works fine.
The problem is when I try to test a component by creating it with react-test-renderer. Here's the broken test:
import React from 'react';
import {Provider} from 'react-redux';
import renderer from 'react-test-renderer';
import mockStore from 'redux-mock-store';
import Home from './../src/containers/Home';
test('test', () => {
const store = mockStore({});
const container = renderer.create(
<Provider store={store}>
<Home/>
</Provider>
);
// some assertions - execution does not get here
});
Here's what I get in the CLI:
FAIL __tests__/Home.test.js
● Test suite failed to run
/data/src/containers/Home.js: Unexpected token (8:11)
6 |
7 | class Home extends ReduxComponent {
> 8 | search = (value) => {
| ^
9 | if (value !== this.status().selectedWord) {
10 | this.dispatch(fetchRelatedWords(value));
11 | }
And this is my .babelrc file (which is sitting in the root of my project folder):
{"presets": ["es2015", "react"]}
And finally the packages.json file:
{
"name": "vocabulary",
"version": "0.1.0",
"author": "Francesco Casula <fra.casula#gmail.com>",
"license": "MIT",
"private": false,
"dependencies": {
"prop-types": "^15.5.8",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^4.1.1",
"react-router-dom": "^4.1.1",
"redux": "^3.6.0",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel-jest": "^19.0.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"jest-fetch-mock": "^1.0.8",
"react-scripts": "^0.9.5",
"react-test-renderer": "^15.5.4",
"redux-logger": "^3.0.1",
"redux-mock-store": "^1.2.3",
"regenerator-runtime": "^0.10.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"test": "jest"
},
"jest": {
"verbose": true,
"setupFiles": [
"./config/jest/setup.js"
]
}
}
By looking at the error it seems like babel may not be doing its magic?
What I find weird though is that is transpiling correctly in the other tests (the action ones).
Hope you guys can help me figure this out :-)

You will need the class-properties transform. Class properties are not yet in the ECMAScript spec but there are Babel plugins to allow this behavior.

Related

Gatsby - Build - WebpackError : Invariant failed

I'm having troubles building my gatsby project.
Development is working fine, but when i try to build, I get an error :
ERROR #95313
Building static HTML failed for path "/Components/Layout/Footer/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
7 |
8 | if (isProduction) {
9 | throw new Error(prefix);
| ^
10 | } else {
11 | throw new Error(prefix + ": " + (message || ''));
12 | }
WebpackError: Invariant failed
- tiny-invariant.esm.js:9 invariant
[front-gatsby]/[tiny-invariant]/dist/tiny-invariant.esm.js:9:1
- react-router-dom.js:172 Object.children
[front-gatsby]/[react-router-dom]/esm/react-router-dom.js:172:132
- static-entry.js:240 Module.../../../../../front-gatsby/.cache/static-entry.js.__webpack_exports__.default
/front-gatsby/.cache/static-entry.js:240:18
- api-runner-ssr.js:19 MappingPromiseArray.PromiseArray._iterate
/front-gatsby/.cache/api-runner-ssr.js:19:1
I have no idea where to start debugging this. My website is pretty simple with some static pages and redux.
Below is my code.
I have basically a static website using redux and react router dom to navigate.
I had previously an error when building : "couldn't find the store" which is why I had to create both gatsby-browser and gatsby-ssr to enclose the Provider :
index.js:
import React, { Component } from 'react';
import './App.css';
import Navigation from './Components/Navigation'
import { library } from '#fortawesome/fontawesome-svg-core'
import { faStroopwafel, faStar, faCircle, faCheckCircle,faTimesCircle} from '#fortawesome/free-solid-svg-icons'
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends Component {
render() {
library.add(faStroopwafel, faStar, faCircle, faCheckCircle, faTimesCircle)
return (
<div className="App">
<Navigation/>
</div>
);
}
}
export default App;
ReduxWrapper :
import React, { Component } from 'react';
import shop from './reducers/shop.reducer'; // importation du shop
import erreur from './reducers/erreur.reducer'; // importation du erreur
import panier from './reducers/panier.reducer'; // importation du erreur
import {Provider} from 'react-redux'; // importation du provider
import createEngine from 'redux-storage-engine-localstorage';
import {createStore, combineReducers, applyMiddleware} from 'redux'; // importation du reduceur
import * as storage from 'redux-storage'; // storage
const reducer = storage.reducer(combineReducers({shop, erreur,panier}));
const engine = createEngine('my-save-key');
const middleware = storage.createMiddleware(engine);
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore);
const store = createStoreWithMiddleware(reducer);
const load = storage.createLoader(engine);
load(store);
export default ({ element }) => (
<Provider store={store}>{element}</Provider>
);
gatsby-browser & gatsby-ssr (identicals)
export { default as wrapRootElement } from './src/pages/ReduxWrapper';
My Package.json :
{
"name": "gatsby-starter-hello-world",
"private": true,
"description": "",
"version": "0.1.0",
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing \""
},
"dependencies": {
"#feathersjs/feathers": "^4.3.0-pre.1",
"#feathersjs/rest-client": "^4.3.0-pre.1",
"#fortawesome/fontawesome-svg-core": "^1.2.18",
"#fortawesome/free-solid-svg-icons": "^5.8.2",
"#fortawesome/react-fontawesome": "^0.1.4",
"bootstrap": "^4.3.1",
"emailjs-com": "^2.4.0",
"express": "^4.17.0",
"express-favicon": "^2.0.1",
"fs": "0.0.1-security",
"gatsby": "^2.15.28",
"gatsby-plugin-mailchimp": "^5.1.2",
"gatsby-plugin-react-helmet": "^3.1.10",
"gatsby-plugin-stripe": "^1.2.3",
"react": "^16.10.1",
"react-bootstrap": "^1.0.0-beta.10",
"react-dom": "^16.10.1",
"react-helmet": "^5.2.1",
"react-redux": "^7.0.3",
"react-responsive-carousel": "^3.1.49",
"react-router-dom": "^5.0.0",
"react-router-hash-link": "^1.2.1",
"react-router-hash-link-offset": "^1.0.1",
"react-scripts": "2.1.8",
"react-scroll-to-component": "^1.0.2",
"react-stripe-checkout": "^2.6.3",
"react-stripe-elements": "^4.0.0",
"reactstrap": "^7.1.0",
"redux": "^4.0.1",
"redux-storage": "^4.1.2",
"redux-storage-engine-localstorage": "^1.1.4",
"uuid": "^3.3.3"
},
"devDependencies": {
"prettier": "^1.18.2"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-hello-world"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
This doesn't work when running "gatsby build", it stops at the step "Building static HTML for pages" and the error above is shown
I'd bet the problem is your use of redux-storage. Gatsby can't access any browser APIs during build, so you'll need to wrap a conditional check to make sure localstorage is available (per the html debugging page that has already been suggested).
I'm not familiar with redux usage in gatsby, but I would rewrite your redux wrapper to be closer to the official example, and put the redux-storage setup in a if (typeof window !== 'undefined') block

Redux Usage Issue #connect [duplicate]

I'm new to using React and Redux, I'm building a simple todos application. I am writing my application using the create-react-app tool in the command line.
The issue
I went to other blogs and post and others have mentioned that I am missing an npm plugin to transform decorators "transform-decorators-legacy", I added this to my dependencies along with Babel, but I am still receiving the same error.
Syntax error: Unexpected token (9:0)
7 | import './App.css';
8 |
> 9 | #connect((store) => {
| ^
10 | return {
11 | user: store.user.user
12 | }
My code
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Todos from './components/Todos';
import Todo from './components/Todo';
import './App.css';
#connect((store) => {
return {
user: store.user.user
}
})
class App extends Component {
constructor(){
super()
this.state = {
name: 'Brad',
todos: [
{
id: '001',
name: 'Take out trash',
completed: false
},
{
id: '002',
name: 'Meeting with boss',
completed: false
},
{
id: '003',
name: 'Go out to dinner',
completed: false
}
]
}
}
render() {
return (
<div className="App">
<h1>Hello</h1>
<Todos name={this.state.name} todos={this.state.todos}/>
<Todo/>
</div>
);
}
}
export default App;
My dependencies
package.json
{
"name": "react-redux-project",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.16.2",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-promise-middleware": "^4.3.0",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel": "^6.23.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"react-scripts": "1.0.11"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Any help/knowledge will be appreciated thanks!
First I'd note that I agree with #markerikson's answer, use the function instead of the decorator.
If you did want to use decorators though, there would be a couple more steps involved. You've added the plugin to your dependencies, but not told Babel to use it.
Create React App uses Webpack with Babel under the hood, namely, in react-scripts. You need to adjust that Babel configuration. The "Create React App" way to do this is to eject from Create React App and then edit .babelrc - see https://babeljs.io/docs/plugins/transform-decorators/#usage-via-babelrc-recommended-
Please note that both the React and Redux teams generally discourage the use of decorators. Instead, in this case you should use connect() as a function:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
Try like this:
const stateMap = (state) => {
console.log('state', state);
return {
//something from state
};
};
export default connect(stateMap)(App);

SPFx react cannot read property 'shape' of undefined

Hi I am creating an SPFX weather webpart and i am getting this error:
there are no errors when i run gulp build. i am not sure how to debug my issue. this is the snippet of the proptypes.shape() where i am getting my issue:
import * as React from 'react';
import PropTypes from 'prop-types';
export const Day: React.SFC<any> = props => {
const date = props.day.dt;
const icon = getIcon(props.day.weather[0].id);
const animate = true;
const iconSize = 64;
const iconColor = 'black';
return (
<div className={appClasses.dayContainer} onClick={props.onClick} role="link">
<h2 className={appClasses.date}>{(new Date(date * 1000)).toDateString()} - {(new Date(date * 1000)).toLocaleTimeString()}</h2>
<ReactAnimatedWeather
icon={icon}
color={iconColor}
size={iconSize}
animate={animate}
/>
</div>
);
};
Day.defaultProps = {
onClick: () => {},
};
Day.propTypes = {
day: PropTypes.shape({
dt: PropTypes.number.isRequired,
weather: PropTypes.array.isRequired,
}).isRequired,
onClick: PropTypes.func,
};
I'd like to note that i created the webpart first using react and it is working perfectly, but when i created an SPFX app, and transferred my existing codes into it. I had encountered these errors.
This is my package.json
{
"name": "spfx-weather-2",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"#microsoft/sp-core-library": "~1.1.0",
"#microsoft/sp-webpart-base": "~1.1.1",
"#types/react": "0.14.46",
"#types/react-addons-shallow-compare": "0.14.17",
"#types/react-addons-test-utils": "0.14.15",
"#types/react-addons-update": "0.14.14",
"#types/react-dom": "0.14.18",
"#types/webpack-env": ">=1.12.1 <1.14.0",
"prop-types": "^15.6.1",
"react": "15.4.2",
"react-animated-weather": "^1.0.3",
"react-dom": "15.4.2",
"react-router-dom": "^4.2.2"
},
"devDependencies": {
"#microsoft/sp-build-web": "~1.1.0",
"#microsoft/sp-module-interfaces": "~1.1.0",
"#microsoft/sp-webpart-workbench": "~1.1.0",
"gulp": "~3.9.1",
"#types/chai": ">=3.4.34 <3.6.0",
"#types/mocha": ">=2.2.33 <2.6.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
}
}
Check my answer here [SPLoaderError.loadComponentError]: ***Failed to load component
You very likely have the same issue. If you were to post your github link for me to clone I could confirm for you.
TL;DR
You likely have a circular reference between your factories. You need to move any code that is required from your top level factory to the bottom of said factory.
Let me know if you don't quite understand after reading my other answer.

React IE11 async causes Expected } error

I'm trying a tutorial for a basic react web app and it works perfectly in chrome. Here is my code:
import React, {Component} from 'react';
export default class App extends Component {
async componentDidMount() {
const [r1,r2] = await Promise.all([
fetch('http://api.mywebsite.com/content/cars'),
fetch('http://api.mywebsite.com/content/aircrafts'),
]);
this.setState({content:await r1.json(),content2: await r2.json()});
}
render() {
if(this.state) {
console.log(this.state);
}
return (
<div>hello</div>
)
}
}
This works exactly as I expect in Chrome - load up the react component, fetch some data, set the state, and print the state to console.
However, this code will not run in Internet Explorer 11. All I get is a blank page, and in my developer tools, I get the error
Expected '}'
When I click on the link to the error, it highlights this segment of code:
_createClass(App, [{
key: 'componentDidMount',
value: async function componentDidMount() {
var _ref = await Promise.all([fetch('http://new.evermight.com/content/index'), fetch('http://new.evermight.com/content/index')]),
_ref2 = _slicedToArray(_ref, 2),
With an arrow pointing to the line value: async function componentDidMount() {.
How do I make this work in Internet Explorer 11? I only want setState to fire after the fetch calls and such are complete. I need the await behaviour.
EDIT
I am using webpack to compile my project. And if it helps, here is my package.json file:
{
"name": "scroll",
"version": "0.1.0",
"private": true,
"dependencies": {
"animated": "^0.2.1",
"es2015": "0.0.0",
"gsap": "^1.20.3",
"history": "^4.7.2",
"jquery": "^3.2.1",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react-ga": "^2.4.1",
"react-router-dom": "^4.2.2",
"react-scripts": "0.9.5",
"react-transition-group": "^1.2.0",
"scrollmagic": "^2.0.5",
"video-element": "^1.0.3"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.17",
"css-loader": "^0.25.0",
"eslint": "^4.13.0",
"eslint-config-aqua": "^2.0.1",
"eslint-plugin-react": "^7.5.1",
"file-loader": "^0.9.0",
"node-sass": "^3.10.1",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"uglifyjs-webpack-plugin": "^1.1.6",
"url-loader": "^0.5.7",
"webpack": "^3.8.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
And here is my webpack.config.js
var webpack = require('webpack');
var CleanPlugin = require('clean-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: {app:'./src/Index.js'},
output: {
filename: '[name].bundle.js',
chunkFilename: '[id].[hash].bundle.js',
path: '/var/www/html/public/build',
publicPath: '/build/'
},
plugins: [
// This plugin minifies all the Javascript code of the final bundle
new UglifyJsPlugin({
uglifyOptions:{
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
},
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'main', // Move dependencies to our main file
children: true, // Look for common dependencies in all children,
minChunks: 2, // How many times a dependency must come up before being extracted
})
],
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' },
{ test: /\.scss$/, loaders: [ 'style-loader', 'css-loader', 'sass-loader' ]},
{ test: /\.(jpg|gif|png|otf|eot|woff|svg|ttf)(\?.*)?$/, loader: "file-loader" }
]
}
}
Actually, I did get async and await to work in IE11. In my question, I also had a problem with fetch not being supported in IE11. Here's what I did to solve both problems. I went to my bash terminal and typed this
npm install --save es6-promise
npm install --save-dev babel-polyfill
npm install --save-dev babel-plugin-transform-async-to-generator
npm install --save isomorphic-fetch
Next, I added these two lines to the very beginning of my src/Index.js before any other code because it is my entry point:
import "babel-polyfill";
import "isomorphic-fetch";
Then I ran the webpack command, and now my IE11 supports the code I created with async await and it supports the fetch command.
async-await is not supported in IE.
Check the MDN docs
You need to use Promises instead like
componentDidMount() {
Promise.all([
fetch('http://api.mywebsite.com/content/cars'),
fetch('http://api.mywebsite.com/content/aircrafts'),
]).then(([r1, r2]) => {
this.setState({content:r1.json(),content2: r2.json()});
})
}
Also in order to support promises in IE, you need to use a 3rd party Polyfill libraries like BlueBird or use babel-polyfill

React-Redux #connect syntax error

I'm new to using React and Redux, I'm building a simple todos application. I am writing my application using the create-react-app tool in the command line.
The issue
I went to other blogs and post and others have mentioned that I am missing an npm plugin to transform decorators "transform-decorators-legacy", I added this to my dependencies along with Babel, but I am still receiving the same error.
Syntax error: Unexpected token (9:0)
7 | import './App.css';
8 |
> 9 | #connect((store) => {
| ^
10 | return {
11 | user: store.user.user
12 | }
My code
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Todos from './components/Todos';
import Todo from './components/Todo';
import './App.css';
#connect((store) => {
return {
user: store.user.user
}
})
class App extends Component {
constructor(){
super()
this.state = {
name: 'Brad',
todos: [
{
id: '001',
name: 'Take out trash',
completed: false
},
{
id: '002',
name: 'Meeting with boss',
completed: false
},
{
id: '003',
name: 'Go out to dinner',
completed: false
}
]
}
}
render() {
return (
<div className="App">
<h1>Hello</h1>
<Todos name={this.state.name} todos={this.state.todos}/>
<Todo/>
</div>
);
}
}
export default App;
My dependencies
package.json
{
"name": "react-redux-project",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.16.2",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-promise-middleware": "^4.3.0",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel": "^6.23.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"react-scripts": "1.0.11"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Any help/knowledge will be appreciated thanks!
First I'd note that I agree with #markerikson's answer, use the function instead of the decorator.
If you did want to use decorators though, there would be a couple more steps involved. You've added the plugin to your dependencies, but not told Babel to use it.
Create React App uses Webpack with Babel under the hood, namely, in react-scripts. You need to adjust that Babel configuration. The "Create React App" way to do this is to eject from Create React App and then edit .babelrc - see https://babeljs.io/docs/plugins/transform-decorators/#usage-via-babelrc-recommended-
Please note that both the React and Redux teams generally discourage the use of decorators. Instead, in this case you should use connect() as a function:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
Try like this:
const stateMap = (state) => {
console.log('state', state);
return {
//something from state
};
};
export default connect(stateMap)(App);

Resources