Handling Browserify externals in Jest - reactjs

I have a React project which uses Browserify externals. What's the best approach for testing components which reference external dependencies in Jest? For example - I have something like this...
import React from 'react';
import someExternal from 'someExternal';
class MyClass extends React.Component {
methodToTest() {
...
someExternal.doStuff();
...
}
}
This works as expected in the browser, the bundle which exposes someExternal is available, so someExternal's path can be resolved.
However in my unit test, the path to someExternal can't be resolved, because the bundle which contains someExternal is not available.
Sooo what's the best approach here?

OK solved. You can use manual mocks, which Jest loads before it tries to load the actual module.
https://facebook.github.io/jest/docs/manual-mocks.html

Related

Can I make Reason+React import react module from CDN?

Building a component with Reason and React always gives me an module import statement for "react", which cannot be found if React is included from a CDN. Is there a solution for this? I've tried to define window.react = React in index.html without success. es6-global setting does not change anything.
I'm not using a bundling program like webpack.
Edit: Possibly relevant thread from Reason forum: https://reasonml.chat/t/can-one-load-reasonml-es6-modules-without-a-bundler/2219
Similar issue (not resolved): can one load reasonml es6 modules without a bundler
importmap (not yet implemented in browsers) could be another solution for this: Using ES6 Modules without a Transpiler/Bundler step
Technically, yes you can, but it's not going to be as easy as going with the npm flow and using a bundler.
The ReasonReact bindings are written in a way that produces output JavaScript that imports modules like:
import * as React from "react";
(If using ES6 module style.)
If using a CDN you would probably want an output that looks like this:
import * as React from "https://some.cdn/react";
The syntax (from the ReasonReact repo) that controls the output JS is:
[#bs.module "react"]
external createElement: (component('props), 'props) => element = "createElement";
If you changed it to:
[#bs.module "https://some.cdn/react"]
external createElement: (component('props), 'props) => element = "createElement";
...then you'd get the desired output. But the problem is then you need to change the sources ... i.e. maintain or find forked bindings for React for that CDN. Or set up some code automation that does a find-and-replace of [#bs.module "react"] with [#bs.module "https://some.cnd/react"]. So either way, it's not as simple as using a bundler.

Is it possible to override jest configuration defined in node_modules library from project configuration?

We are using some custom client library (added as dev dependencies in our package.json) which has all configurations related to jest and react JS. However, we are facing some issues while executing the test cases in which its failing because of images import in the source code. On further investigation, we saw that we need to mock the image import as a jest by default does not understand image import.
To mock the image import we need to add transform in package.json and add some script like below link:
Jest + Enzyme: How to test an image src?
However, this config is not present in the library and we cannot edit package.json of libraries.
Is there any way to override that jest configuration in the project itself?
You can probably override it within your apps jest.config.js
const getJestConfig = require('')
module.exports = {
...getJestConfig(),
// do your bits
}
}

React lazy loading javascript file

I am trying to make my application more performant with React.lazy. As the Ethereum lightwallet is a huge file, I would like to put it into a separate bundle. The currently working import is the following:
import lightwallet from 'eth-lightwallet/dist/lightwallet.min.js';
When I try to import using the lazy syntax
const lightwallet = React.lazy(() => import('eth-lightwallet/dist/lightwallet.min.js'));
Only a React.lazy object ($$typeof: Symbol(react.lazy)) is returned instead of the lightwallet object. I think this is due to the fact that lightwallet doesn't have a default export. How could I get around this problem? Thanks!
I suggest following the example here:
https://reacttraining.com/react-router/web/guides/code-splitting
react-loadable is an npm package that makes code-splitting (a.k.a lazy loading) quite easy and also provides you the ability to render a loading component until the lazy load has finished.
The only gotcha is that if you're using Babel to transpile your code bundles, you'll have to add support for the Dynamic Import syntax, webpack already has this by default, but Babel doesn't.
The Babel Plugin:
#babel/plugin-syntax-dynamic-import
will make this possible by adding support for the syntax.
I recommend react-loadable over React.lazy as it makes displaying a loading component while the lazy-load happens VERY easy, and provides you hooks to display an error component and retry the import in the case that it fails.
Read more about react-loadable here:
https://github.com/jamiebuilds/react-loadable
Your code would look something like this:
import Loadable from 'react-loadable';
import Loading from './YOUR-LOADING-COMPONENT';
const LoadableWallet = Loadable({
loader: () => import('eth-lightwallet/dist/lightwallet.min.js'),
loading: Loading,
});
export default class Wallet extends React.Component {
render() {
return <LoadableWallet/>;
}
}
Make sure that your react version is up to date in React v16.6.0. And also the core idea behind the React. lazy is React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component. But is this scenario min.js won't give any promise. Most probably That didn't work.

Using own React npm component - appropriate loader issues

I have made a component in my React app that I would like to publish to NPM. It's consists of just one file index.js
import React from 'react'
import PropTypes from 'prop-types';
export default class Test extends React.Component {
//I seem to be getting a specific issue with the lines below
//Do I need a special loader for these?
static displayName = 'Test'
static defaultProps = {
live: true,
}
}
Originally the component was in a components directory of my main app and I include it using:
import Test from './components/Test'
Since then I have created a new folder (not part of my main app) and added a package.json file and the index.js file. I have also published it to NPM which worked fine but when I try to use it after installing...
npm i -S package-name
import Test from 'package-name'
I get an error: You may need an appropriate loader to handle this file type...
My package.json file doesn't have any dependencies or devDependencies at the moment. Do I need to do something with Webpack and Babel?
Do I need to do something with Webpack and Babel?
Most likely. If you are using ES6 syntax in package-name then babel needs to transcode that library as well. When I have encountered that error this has always been the case. I suggest updating your Webpack / Babel configuration to include that library.

"Define is not defined" in Jest when testing es6 module with RequireJS dependency

I have a Jest test suite that fails to run because the component it's trying to test depends on a RequireJS module. Here's the error I'm seeing:
FAIL __tests__/components/MyComponent.test.js
● Test suite failed to run
ReferenceError: define is not defined
at Object.<anonymous> (node_modules/private-npm-module/utils.js:1:90)
The component has the following import:
import utils from 'private-npm-module';
And the private-npm-module is set up like so:
define('utils', [], function() {
return {};
});
When MyComponent is transpiled with babel and run in the browser, the dependency operates correctly. This issue only affects the unit test. How can I get my test suite to run on a component with a RequireJS dependency?
I'm using babel-jest as my scriptPreprocessor in package.json's jest config. I'm using jest v0.15.1.
So, RequireJS is not supported by Jest. In my particular case, it was easiest and most appropriate to mock my dependency at the top of MyComponent.test.js:
jest.mock('private-npm-module', () => {
// mock implementation
})
import MyComponent from '../../components/MyComponent';
This way, when MyComponent is loaded, its dependency is already mocked, so it won't try to load the RequireJS module.
If you really do need to load your RequireJS module for your test, it may be possible to use jest's transform configuration to wrap your implementation in a RequireJS to ES6 converter.

Resources