I'm using react-hook-media-query in my project but the test is failing because of it.
This is the code:
import React from 'react';
import useMediaQuery from 'react-hook-media-query';
const MyCompp = (props) => {
const minWidth1200 = useMediaQuery('(min-width: 1200px)');
...
}
test file:
import React from 'react';
import App from './App';
import { render } from '#testing-library/react';
import { WrapIntlProvider, WrapStore } from '../testsHelper';
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: () => ({
locale: 'en-US',
messages: {}
})
}));
describe('<App />', function () {
it('should render <App />', () => {
const { container } = render(
<WrapStore>
<WrapIntlProvider>
<App />
</WrapIntlProvider>
</WrapStore>
);
expect(container).toMatchSnapshot();
});
});
and when I run the tests it throws this error message:
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config
option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
/.../node_modules/react-hook-media-query/dist/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import
{ useState, useEffect } from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
> 2 | import useMediaQuery from 'react-hook-media-query';
| ^
Any ideas how to get rid of it?
Recently I'm working on upgrading my project from webpack 3 (v. 3.3.0) to webpack 4 (v. 4.44.2). Compiling and building worked perfectly, but it turned out to render nothing on the screen.
After I compared the parameters passed to RouterContext between two projects of webpack 3 and of webpack 4, I narrowed down the root cause to dynamic imported components.
The following script is how I use react-router 3 (v. 3.0.5) getComponent to import component, which is workable before I upgrade to webpack 4:
const loadRoute = callback => module => callback(null, module);
const forceToReload = (err) => {
Logger.error(err);
window.location.reload();
};
export default (loadRoute, forceToReload) => (
<Route name="Subscribe" path={appUtils.getRoutePath('/sample')}
getComponent={(location, callback) => import('./index.jsx').then(loadRoute(callback)).catch(forceToReload)}/>
);
Fortunately, after days of trials & errors, I finally made my project render correctly.
In webpack 4 version, I have to append .default to module in loadRoute as follows:
const loadRoute = callback => module => callback(null, module.default);
The Question is
Even though the problem is solved, I still wonder if someone can provide an explanation about when to add .default. Does webpack 4 compile differently on dynamic import? Any ideas?
After days of research, I finally found the answer to my question, hoping I can somehow help those with the same question in the future.
Webpack official website (Code-Splitting: Dynamic Import) has a description as follows:
The reason we need default is that since webpack 4, when importing a CommonJS module, the import will no longer resolve to the value of module.exports, it will instead create an artificial namespace object for the CommonJS module.
Out of curiosity, I did some experiment logging out things I dynamic imports:
// exportObject.js
export default {a: 1, b: 2};
export const c = 3;
// exportString.js
export default "TEST_STRING";
// exportComponent.js
import React, {Component} from "react";
export default class exportComponent extends Component {
constructor(props) {
super(props);
this.a = 1;
this.b = 2;
}
}
// exportFunction.js
export default () => ({a: 1, b: 2});
// index.js
componentDidMount() {
import('./exportObject').then(module => {
console.group('Object');
console.warn('module', module);
console.warn('module.a:', module.a);
console.warn('module.b:', module.b);
console.warn('module.default', module.default);
console.warn('module.c', module.c);
console.groupEnd();
});
import('./exportString').then(module => {
console.group('String');
console.warn('module', module);
console.warn('module.default', module.default);
console.groupEnd();
});
import('./exportComponent').then(module => {
console.group('Component');
console.warn('module', module);
console.warn('module.default', module.default);
console.groupEnd();
});
import('./exportFunction').then(module => {
console.group('Function');
try {
console.warn('module()', module());
} catch (e) {
console.warn('module()', e);
}
try {
console.warn('module.default()', module.default());
} catch (e) {
console.warn('module.default()', e);
}
console.groupEnd();
});
}
This is the result from Webpack 3 Project:
While from Webpack 4 Project:
As you can see, non-objects have different results. This finding matches the description of this article (which is provided by webpack official)
It’s not that problematic when exporting an object. But you’ll get into trouble when using module.exports with non-objects.
I use export default in my code rather than module.exports, then why I still got the result?
Actually, Babel#6 will do the transform as below: (reference)
Babel#6 transforms the following file
export default 'foo'
into
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = 'foo';
Now, things are crystal clear.
The packages I used was:
node: 11.15.0
babel-core: "^6.23.1",
babel-loader: "7.1.4",
webpack: "4.44.2",
webpack-cli: "^4.2.0",
I am trying to figure out how to write a Component in a MERN app.
This is my best effort, taking account of this advice on how to go about it?
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactBootstrap from 'react-bootstrap'
var GreeterMessage = require('GreeterMessage');
var GreeterForm = require('GreeterForm');
class Greeter extends React.Component {
getDefaultProps: function () {
return {
name: 'React',
message: 'This is the default message!'
};
},
getInitialState: function () {
return {
name: this.props.name,
message: this.props.message
};
},
handleNewData: function (updates) {
this.setState(updates);
},
render: function () {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
When I save this and run web pack in my terminal to check everything, I get this feedback:
ERROR in ./app/components/Greeter.jsx
Module build failed: SyntaxError: Unexpected token (9:19)
7 |
8 | class Greeter extends React.Component {
> 9 | getDefaultProps: function() {
| ^
10 | return {
11 | name: 'React',
12 | message: 'This is the default message!'
# ./app/app.jsx 19:14-32
I can't find any resources to help me figure out what a token is, let alone when they are expected or unexpected.
Can anyone see where I'm getting this wrong? I've just finished 5 separate udemy courses that are supposed to be an intro to react and MERN, and I can't get the first step to work.
It looks like your mixing the older React.createClass syntax with the latest ES6 class notation. You can't mix and match :)
You're also using both CommonJS and ES6 versions of importing code into your file. Although this won't break the code (unless you're using a setup that doesn't support import, I would advise dine consistently wouldn't go amiss.
Here is an example of an amended version of your code to use the ES6 syntax:
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactBootstrap from 'react-bootstrap'
import GreeterMessage from 'GreeterMessage');
import GreeterForm from 'GreeterForm');
// sets the default values for props
Greeter.defaultProps = {
name: 'React',
message: 'This is the default message!'
};
class Greeter extends React.Component {
constructor(){
super();
// sets the initial state
this.state = {
name: this.props.name,
message: this.props.message
};
// due to this not being bound intrinsically to event handlers,
// it's advisable to do it here so that the reference to
// this.setState works as expected:
this.handleNewData = this.handleNewData.bind(this);
}
handleNewData(updates) {
// `this` is not automatically bound to event handlers in ES6
// Ensure that it is bound by using `.bind` (see constructor)
// OR with ES6 arrow functions
this.setState(updates);
}
render() {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
Issue is you are mixing es5 and es6 way of writing the react component. I will suggest you to write in es6. Pasted useful links in the last, refer those links for more details.
Write it like this:
class Greeter extends React.Component {
constructor(){
super();
this.state = {
name: this.props.name,
message: this.props.message
}
this.handleNewData = this.handleNewData.bind(this);
}
handleNewData (updates) {
this.setState(updates);
}
render () {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
Greeter.defaultProps = {
name: 'React',
message: 'This is the default message!'
};
Links:
DefaultProps
es6 class
React DOC
No Autobinding of methods
I am trying to write the test case for my jsx file...
i took the sample test case from another jsx file...
that file doesnt have connect method...
but his file has connect method..
I think because of this its breaking my test case...
can you guys tell me how to fix it..
providing my code below...
clear code below
https://gist.github.com/js08/d590e78e8923e68b191a
SyntaxError: C:/codebase/sports/test/sports-tests.js: Unexpected token (20:73)
18 |
19 | it('should render correctly', () => {
20 | shallowRenderer.render();
| ^
21 | /*let renderedElement = shallowRenderer.getRenderOutput();
22 |
test case
import {expect} from 'chai';
import React from 'react';
import TestUtils from 'react-addons-test-utils';
import sportsPageDefault from '../src/sports-Page-Default';
import initializeJsDom from './test-utils/dom.js';
import {getGridLayoutClasses} from 'sports-css-grids';
//import _difference from 'lodash/array/difference';
describe('shallow renderer tests for sports-Page-Default ', function() {
let shallowRenderer = TestUtils.createRenderer();
console.log("shallowRenderer" + JSON.stringify(shallowRenderer));
it('should render correctly', () => {
shallowRenderer.render(<sportsPageDefault headerClass='8887' layout= {id: 100, text: 'hello world'} sidebar= {id: 100, text: 'hello world'} title="Demo" />);
let renderedElement = shallowRenderer.getRenderOutput();
console.log(renderedElement);
/* let actualTitleEl = renderedElement.props.children[0].props.children[0];
let expectedTitleEl = <h1 className="transactionalPageHeader-appName font-serif">Demo</h1>;
expect(actualTitleEl).to.deep.equal(expectedTitleEl);*/
});
});
actual code
import './css/sports-bottom-layout.css';
import './css/sports-Page.css';
import './css/sports-leftCornerLayout.css';
import React from 'react';
import PageHeader from './components/page-header/page-header';
import MainContent from './components/main-content';
import sports-bottom-layout from './components/sports-bottom-layout/sports-bottom-layout';
import {getPanelLayoutState} from './util/PageLayout';
import {getGridLayoutClasses} from 'sports-css-grids/lib/js/gridLayout';
import PagePureRenderMixin from './util/PagePureRenderMixin';
import {connect} from 'react-redux';
import {setHeaderPanelState, setRightPanelState} from './redux/layout/layout-actions';
console.log("inside");
let customMixin = PagePureRenderMixin({
state: {
mainPanelGridClassList: function(classArray) {
return classArray.length;
console.log("classArray.length" + classArray.length);
}
}
});
let PT = React.PropTypes;
let sportsPageDefault = React.createClass({
propTypes: {
headerClass: React.PropTypes.string,
layout: PT.object.isRequired,
sports-leftCornerLayout: PT.oneOfType([
PT.func,
PT.object
]),
title: PT.string.isRequired
},
//cpomponent m,ount code
});
function sportsShallow(itemA, itemB) {
for (let i in itemA) {
if (itemA[i] !== itemB[i]) {
return false;
}
}
return true;
}
export default connect(state => ({
layout: state.Page.layout
}))(sportsPageDefault);
Error:
ts throwing an error since not sure how to pass in onof types for function....
shallowRenderer.render(<sportsPageDefault headerClass='8887' layout= {{id: 100, text: 'hello world'}} sidebar= {[{onAppExit},{id: 100, text: 'hello world'}]} title={"Demo"} />);
propTypes: {
headerClass: React.PropTypes.string,
layout: PT.object.isRequired,
sports-leftCornerLayout: PT.oneOfType([
PT.func,
PT.object
]),
title: PT.string.isRequired
},
TypeError: Cannot read property 'propTypes' of undefined
at [object Object].ReactCompositeComponentMixin._processProps (\node_modules\react\lib\ReactCompositeComponent.js:352:20)
at [object Object].ReactCompositeComponentMixin.mountComponent (\node_modules\react\lib\ReactCompositeComponent.js:129:28)
at [object Object].wrapper as mountComponent
at [object Object].ReactShallowRenderer._render (\node_modules\react\lib\ReactTestUtils.js:362:14)
at [object Object].ReactShallowRenderer.render (\node_modules\react\lib\ReactTestUtils.js:344:8)
at Context. (C:/codebase/usaa-template-standard/test/usaa-template-standard-tests.js:23:25)
I would start by cleaning up your code a bit, it looks like a mess; you have some characters in there that would break your code but I assume you put for presentation purposes, and putting all the code into one code block makes it look very wrong.
Regardless, there is the big real issue that most people have when trying to test connected react-redux components. There is beautiful documentation in their library explaining a great way to test them, I'll summarize.
You can't render a connected component unless there is a Provider in an ancestor. You could always render one of those in your tests but the recommended solution is to export both the connected and not connected components. In your case, you would do it like this:
export let sportsPageDefault = React.createClass({
propTypes: {
headerClass: React.PropTypes.string,
layout: PT.object.isRequired,
sports-leftCornerLayout: PT.oneOfType([
PT.func,
PT.object
]),
title: PT.string.isRequired
},
});
export default connect(state => ({
layout: state.Page.layout
}))(sportsPageDefault);
Notice that I'm exporting a default as well as the class itself. This allows you to import the component the usual way in your production code, but in your tests, import as follows:
import { sportsPageDefault } from 'path/to/component';
What we do here is imported the not connected component. You have now decoupled redux from your component.
That error you're getting is hard to pinpoint given the state of your code. If you clean it up and provide more info we might be able to help, but this is a good starting point to testing redux components.
With ES6, I can import several exports from a file like this:
import {ThingA, ThingB, ThingC} from 'lib/things';
However, I like the organization of having one module per file. I end up with imports like this:
import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';
I would love to be able to do this:
import {ThingA, ThingB, ThingC} from 'lib/things/*';
or something similar, with the understood convention that each file contains one default export, and each module is named the same as its file.
Is this possible?
I don't think this is possible, but afaik the resolution of module names is up to module loaders so there might a loader implementation that does support this.
Until then, you could use an intermediate "module file" at lib/things/index.js that just contains
export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';
and it would allow you to do
import {ThingA, ThingB, ThingC} from 'lib/things';
Just a variation on the theme already provided in the answer, but how about this:
In a Thing,
export default function ThingA () {}
In things/index.js,
export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'
Then to consume all the things elsewhere,
import * as things from './things'
things.ThingA()
Or to consume just some of things,
import {ThingA,ThingB} from './things'
The current answers suggest a workaround but it's bugged me why this doesn't exist, so I've created a babel plugin which does this.
Install it using:
npm i --save-dev babel-plugin-wildcard
then add it to your .babelrc with:
{
"plugins": ["wildcard"]
}
see the repo for detailed install info
This allows you to do this:
import * as Things from './lib/things';
// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;
again, the repo contains further information on what exactly it does, but doing it this way avoids creating index.js files and also happens at compile-time to avoid doing readdirs at runtime.
Also with a newer version you can do exactly like your example:
import { ThingsA, ThingsB, ThingsC } from './lib/things/*';
works the same as the above.
You now can use async import():
import fs = require('fs');
and then:
fs.readdir('./someDir', (err, files) => {
files.forEach(file => {
const module = import('./' + file).then(m =>
m.callSomeMethod();
);
// or const module = await import('file')
});
});
Great gugly muglys! This was harder than it needed to be.
Export one flat default
This is a great opportunity to use spread (... in { ...Matters, ...Contacts } below:
// imports/collections/Matters.js
export default { // default export
hello: 'World',
something: 'important',
};
// imports/collections/Contacts.js
export default { // default export
hello: 'Moon',
email: 'hello#example.com',
};
// imports/collections/index.js
import Matters from './Matters'; // import default export as var 'Matters'
import Contacts from './Contacts';
export default { // default export
...Matters, // spread Matters, overwriting previous properties
...Contacts, // spread Contacts, overwriting previosu properties
};
// imports/test.js
import collections from './collections'; // import default export as 'collections'
console.log(collections);
Then, to run babel compiled code from the command line (from project root /):
$ npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node
(trimmed)
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'Moon',
something: 'important',
email: 'hello#example.com' }
Export one tree-like default
If you'd prefer to not overwrite properties, change:
// imports/collections/index.js
import Matters from './Matters'; // import default as 'Matters'
import Contacts from './Contacts';
export default { // export default
Matters,
Contacts,
};
And the output will be:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
Contacts: { hello: 'Moon', email: 'hello#example.com' } }
Export multiple named exports w/ no default
If you're dedicated to DRY, the syntax on the imports changes as well:
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
This creates 2 named exports w/ no default export. Then change:
// imports/test.js
import { Matters, Contacts } from './collections';
console.log(Matters, Contacts);
And the output:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
Import all named exports
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
// imports/test.js
// Import all named exports as 'collections'
import * as collections from './collections';
console.log(collections); // interesting output
console.log(collections.Matters, collections.Contacts);
Notice the destructuring import { Matters, Contacts } from './collections'; in the previous example.
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: [Getter], Contacts: [Getter] }
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
In practice
Given these source files:
/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js
Creating a /myLib/index.js to bundle up all the files defeats the purpose of import/export. It would be easier to make everything global in the first place, than to make everything global via import/export via index.js "wrapper files".
If you want a particular file, import thingA from './myLib/thingA'; in your own projects.
Creating a "wrapper file" with exports for the module only makes sense if you're packaging for npm or on a multi-year multi-team project.
Made it this far? See the docs for more details.
Also, yay for Stackoverflow finally supporting three `s as code fence markup.
Similar to the accepted answer but it allows you to scale without the need of adding a new module to the index file each time you create one:
./modules/moduleA.js
export const example = 'example';
export const anotherExample = 'anotherExample';
./modules/index.js
// require all modules on the path and with the pattern defined
const req = require.context('./', true, /.js$/);
const modules = req.keys().map(req);
// export all modules
module.exports = modules;
./example.js
import { example, anotherExample } from './modules'
If you are using webpack. This imports files automatically and exports as api namespace.
So no need to update on every file addition.
import camelCase from "lodash-es";
const requireModule = require.context("./", false, /\.js$/); //
const api = {};
requireModule.keys().forEach(fileName => {
if (fileName === "./index.js") return;
const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ""));
api[moduleName] = {
...requireModule(fileName).default
};
});
export default api;
For Typescript users;
import { camelCase } from "lodash-es"
const requireModule = require.context("./folderName", false, /\.ts$/)
interface LooseObject {
[key: string]: any
}
const api: LooseObject = {}
requireModule.keys().forEach(fileName => {
if (fileName === "./index.ts") return
const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ""))
api[moduleName] = {
...requireModule(fileName).default,
}
})
export default api
I've used them a few times (in particular for building massive objects splitting the data over many files (e.g. AST nodes)), in order to build them I made a tiny script (which I've just added to npm so everyone else can use it).
Usage (currently you'll need to use babel to use the export file):
$ npm install -g folder-module
$ folder-module my-cool-module/
Generates a file containing:
export {default as foo} from "./module/foo.js"
export {default as default} from "./module/default.js"
export {default as bar} from "./module/bar.js"
...etc
Then you can just consume the file:
import * as myCoolModule from "my-cool-module.js"
myCoolModule.foo()
Just an other approach to #Bergi's answer
// lib/things/index.js
import ThingA from './ThingA';
import ThingB from './ThingB';
import ThingC from './ThingC';
export default {
ThingA,
ThingB,
ThingC
}
Uses
import {ThingA, ThingB, ThingC} from './lib/things';
Nodejs ? Do like this:
Create a folder with index.js, in index file, add this:
var GET = require('./GET');
var IS = require('./IS');
var PARSE = require('./PARSE');
module.exports = { ...GET, ...IS, ...PARSE};
And, in file GET.js, or IS.js export as normal:
module.exports = { /* something as you like */}
ANd now, you need only including index.js like:
const Helper = require('./YourFolder');
Helper will include all of function in YourFolder.
Good day!
This is not exactly what you asked for but, with this method I can Iterate throught componentsList in my other files and use function such as componentsList.map(...) which I find pretty usefull !
import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';
import StepFour from './StepFour';
import StepFive from './StepFive';
import StepSix from './StepSix';
import StepSeven from './StepSeven';
import StepEight from './StepEight';
const componentsList= () => [
{ component: StepOne(), key: 'step1' },
{ component: StepTwo(), key: 'step2' },
{ component: StepThree(), key: 'step3' },
{ component: StepFour(), key: 'step4' },
{ component: StepFive(), key: 'step5' },
{ component: StepSix(), key: 'step6' },
{ component: StepSeven(), key: 'step7' },
{ component: StepEight(), key: 'step8' }
];
export default componentsList;
You can use require as well:
const moduleHolder = []
function loadModules(path) {
let stat = fs.lstatSync(path)
if (stat.isDirectory()) {
// we have a directory: do a tree walk
const files = fs.readdirSync(path)
let f,
l = files.length
for (var i = 0; i < l; i++) {
f = pathModule.join(path, files[i])
loadModules(f)
}
} else {
// we have a file: load it
var controller = require(path)
moduleHolder.push(controller)
}
}
Then use your moduleHolder with dynamically loaded controllers:
loadModules(DIR)
for (const controller of moduleHolder) {
controller(app, db)
}
I was able to take from user atilkan's approach and modify it a bit:
For Typescript users;
require.context('#/folder/with/modules', false, /\.ts$/).keys().forEach((fileName => {
import('#/folder/with/modules' + fileName).then((mod) => {
(window as any)[fileName] = mod[fileName];
const module = new (window as any)[fileName]();
// use module
});
}));
if you don't export default in A, B, C but just export {} then it's possible to do so
// things/A.js
export function A() {}
// things/B.js
export function B() {}
// things/C.js
export function C() {}
// foo.js
import * as Foo from ./thing
Foo.A()
Foo.B()
Foo.C()