jest test cannot import cesium using create react app and craco - reactjs

I am using create react app with craco, and craco-cesium to load cesium into my project. I am trying to setup jest to start creating tests but the issue is Cesium is using requireJS.
I added the following to my package.json
// package.json
...
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts"
],
"globalSetup": "<rootDir>/setupTests.js"
}
...
based on the ticket opened up here: https://github.com/facebook/jest/issues/1914
I setup the setupTests.js with the following code:
// setupTests.js
module.exports = async () => {
var cesium = require('cesium');
process.$Cesium = cesium
};
and I have the first basic test for valid rendering:
// App.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
however I get the error in one of my view inside <App /> component with the following code:
import Cesium from "cesium";
...
TypeError: Cannot read property 'Ion' of undefined
...
Cesium.Ion.defaultAccessToken = '...';
reporting Cesium as undefined when calling it's functions. I tried to use jest.config.js for jest to pick up the configuration from there with the following code:
// jest.config.js
const { createJestConfig } = require("#craco/craco");
const cracoConfig = require("../craco.config.js");
const jestConfig = createJestConfig(cracoConfig);
module.exports = jestConfig;
but create react app doesn't pick up this file so I cannot try this to verify if this would work.

encoutered the same problem.
Upgrading react-scripts to version 4.0.1 and #craco/craco# to version 6.0.0, seemed to solve these problems, and jest now recognizes all imports from cesium. No other configuration files were needed.

Related

Basic implementation of using microbundle not working

Please see example repo
https://github.com/inspiraller/webpack-and-microbundle
Microbundle code
mymicrobundle/src/index.js
import React from 'react'
const MyMicroBundle = ({session}) => {
return (
<div>Session = {session}</div>
)
}
export default MyMicroBundle
microbundle/package.json - for output
{
...
"source": "src/index.js",
"main": "dist/index.umd.js",
"module": "dist/index.module.js",
"exports": "dist/index.modern.js",
"unpkg": "dist/index.umd.js"
}
Importing Microbundle code
webpack-loads-microbundle/package.json
{
"dependencies": {
"#mymicrobundle/example": "file:../mymicrobundle",
}
}
webpack-load-microbundle/src/index.tsx
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
import MyMicroBundle from '#mymicrobundle/example'
import './index.scss'
const App = () => {
const [session, setSession] = useState('')
return (
<div>
<h1>Hello</h1>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
Note: The microbundle package is bundled as javascript, but I'm using typescript to import it.
Though shouldn't make any difference. I'm also using pnpm instead of npm but also this should be fine as all other imports work.
Something about my path is wrong maybe.
Error
Module not found: Error: Can't resolve '#mymicrobundle/example' in 'C:\baps\react_all\webpack-and-microbundle\webpack-loads-microbundle\src'
webpack resolves modules from its process.cwd()/node_modules by default.
So in your case it is looking for #mymicrobundle/example in webpack-and-microbundle(the current working directory) which is your app directory.
You need to let webpack know, where it needs to search in addition to your project's node_modules.
This can be done using the resolve.modules key. See docs: https://webpack.js.org/configuration/resolve/#resolvemodules
So your webpack config should have something like:
resolve: {
modules: ['node_modules', 'path/to/#mymicrobundle/example'],
},

Jest cannot find module from file in the same folder

I'm trying to set up a very basic test with Jest which tests whether App.js renders correctly. I am getting the error
Cannot find module './App' from 'App.test.js'
However, Jest was able to find:
'./App.js'
'./App.test.js'
However, if I try to write import App from "./App.js"; instead of ... from "./App";, I get
Cannot find module './App.js' from 'App.test.js'
How can I make Jest find modules properly?
The project was set up using Create React App, and App.js and App.test.js are located within the same folder (src/components).
App.js
import React, { Component } from "react";
class App extends Component {
render() {
return <div />;
}
}
export default App;
App.test.js
import React from "react";
import { shallow } from "enzyme";
import App from "./App.js";
const app = shallow(<App />);
it("renders correctly", () => {
expect(app).toMatchSnapshot();
});
I think Jest needs to set up itself before rendering components (so don't call <App /> outside of test cases):
it("renders correctly", () => {
const app = shallow(<App />);
expect(app).toMatchSnapshot();
});
However, if the problem is on the import line, assuming you use an up-to-date version and don't pass any CLI options yourself, I would recommend to replace whole content of App.test.js with:
it('', () => console.log(process.env))
and search for the listed environment variables in https://jestjs.io/docs/en/configuration to see if any can affect Jest.

react-script compatibility issue with third party node module

I am working with react-script 2.1.8 version. I have got an issue while integrating third party node-module as it throws syntax(babel) related error.
react-script is no config library which means i can't define plugin/preset for bable(.babelrc and webpack config does not work.)
please suggest me some solution which can resolve babel issue by defining config or suggest some other way to integrate this library with my project
I've tried to resolve the issue with 'react-app-rewired'and for configuration 'arackaf/customize-cra'. but still errors persist.
import React from 'react';
import ReactDOM from 'react-dom';
import Vr from './vr/Vr.jsx';
const MOUNT_NODE = document.getElementById('root');
const render = () => {
ReactDOM.render(
<div/>,
MOUNT_NODE
);
};
export Vr from './vr/Vr.jsx';
render();
ERROR 1:
Unexpected token (10:3)
ReactDOM.render(
<div/>,
^
MOUNT_NODE
);
};
ERROR 2:
};
export Vr from './vr/Vr.jsx';
^
render();
Add #babel/plugin-proposal-export-default-from (https://git.io/vb4yH) to the 'plugins' section of your Babel config to enable transformation.
Note: this error is related to react preset and babel plugin respectively . But somehow babel config is not working with this third party module(node-module).

SyntaxError: Unexpected token import with Jest

I'm trying to setup a jest snapshot test with redux-persist in my react-native project. I don't think its an es2015 imports problem as my test code looks something like this:
import React from "react"
import "react-native"
// Note: test renderer must be required after react-native.
import renderer from "react-test-renderer"
import App from "../App"
it("renders correctly", () => {
const app = renderer.create(<App />).toJSON()
expect(app).toMatchSnapshot()
})
I ran this exact same test before I added redux-persist and it was working.
Error thrown by jest:
● Test suite failed to run
/Users/a_050313/Documents/dev/scheduling/node_modules/redux-persist/es/integration/react.js:9
import React, { PureComponent } from 'react'; // eslint-disable-line import/no-unresolved
^^^^^^
SyntaxError: Unexpected token import
1 | import React, { Component } from "react"
2 | import { Provider } from "react-redux"
> 3 | import { PersistGate } from "redux-persist/es/integration/react"
4 |
5 | import "./__debug__/ReactotronConfig" // Run Reactron Tools config
6 |
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:318:17)
at Object.<anonymous> (App.js:3:13)
at Object.<anonymous> (__tests__/App.js:7:10)`
The error was related to es2015 imports but It is on jest end. By default jest only transpiles project code and react-native code. So the added libs which aren't already transpilled would error out by jest.
(as mentioned on jest docs)
By default the jest-react-native preset only processes the project's own source files and react-native
Solution provided on the official docs seems a bit hacky but thats the only thing I found:
Add following in your package.json jest: { } section or in jest.config.js file.
"transformIgnorePatterns": [
"node_modules/(?!(react-native|my-project|redux-persist)/)"
]
where the bit redux-persist is the thing that solves the problem. If you have problem with other libs just add their names. My list looks something like this:
"jest": {
"preset": "react-native",
"transformIgnorePatterns": [
"node_modules/(?!(react-native|my-project|redux-persist|react-native-linear-gradient|react-native-vector-icons|react-navigation)/)"
]
}
Additional Note just for redux-persist if you import PersistGate from
import { PersistGate } from "redux-persist/lib/integration/react"
instead
import { PersistGate } from "redux-persist/es/integration/react"
(reference)
you'll get the compiled version but for other libs still you got to this the above mentioned solution.

Invalid Chai property: toMatchSnapshot -- React.js Jest testing

I'm getting an error: Invalid Chai property: toMatchSnapshot when I try to use Jest + Enzyme's snapshot testing. I've updated my React version to 16.2 and I use enzyme-to-json library with Enzyme 3.
Code is below:
import React from 'react';
import ReactDOM from 'react-dom';
import ConnectedApp, { App } from './App';
import { ConnectedRouter } from 'react-router-redux';
import { Provider } from 'react-redux';
import { expect } from 'chai';
import { mount, shallow } from 'enzyme';
import createHistory from 'history/createMemoryHistory'
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import toJson from 'enzyme-to-json';
describe('App tests', () => {
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
let store, container, history, wrapper;
const initialState = {
output: true
}
beforeEach(() => {
store = mockStore(initialState);
history = createHistory();
wrapper = mount(
<Provider store={store}>
<ConnectedRouter history={history}>
<ConnectedApp />
</ConnectedRouter>
</Provider>
)
});
it('+++capturing Snapshot of App', () => {
expect(toJson(wrapper)).toMatchSnapshot();
});
})
I've also tried this with Jest's render like so:
import renderer from 'react-test-renderer';
it('renders correctly', () => {
var component = <Provider store={store}>
<ConnectedRouter history={history}>
<ConnectedApp />
</ConnectedRouter>
</Provider>
const tree = renderer
.create(component)
.toJSON();
expect(tree).toMatchSnapshot();
});
But I still get the Invalid Chai property: toMatchSnapshot error. Anyone know what's up?
This isn't an issue with the renderer you are using. The problem is that you are using chai expectations instead of the expectation library that ships with jest. The chai API has no toMatchSnapshot method. To fix it you can do the following:
Stop using chai and use the jest expectations exclusively. This may simply be a matter of removing line 6: import { expect } from 'chai'
However, if you need to continue to use chai (i.e. you have a lot of chai tests already written and you don't want to do a major overhaul all at once) you can do two things:
Alias either the the chai or jest expect functions in your test setup file e.g. global.chaiExpect = chai.expect
Monkey-patch the global expect function so that you can use both the chai and the jest API like in this blog post: https://medium.com/#RubenOostinga/combining-chai-and-jest-matchers-d12d1ffd0303
The relevant bit is this:
// Make sure chai and jasmine ".not" play nice together
const originalNot = Object.getOwnPropertyDescriptor(chai.Assertion.prototype, 'not').get;
Object.defineProperty(chai.Assertion.prototype, 'not', {
get() {
Object.assign(this, this.assignedNot);
return originalNot.apply(this);
},
set(newNot) {
this.assignedNot = newNot;
return newNot;
},
});
// Combine both jest and chai matchers on expect
const originalExpect = global.expect;
global.expect = (actual) => {
const originalMatchers = originalExpect(actual);
const chaiMatchers = chai.expect(actual);
const combinedMatchers = Object.assign(chaiMatchers, originalMatchers);
return combinedMatchers;
};
For those transitioning away from chai (which would be hijacking expect() from jest in the top level setupTests.js file) the simpler solution is to load jest's expect() again on top of the current test file like so:
import { expect } from "#jest/globals";
That is, until you can't fully do away with any
global.expect = chai.expect;
somewhere in the code, setupTests.js for example.
Its Simple.Just write your test scripts (something.spec.js) in to another file without importing 'chai' . It will work like a charm. No need for messy stuffs.Keep it Simple !
This is partially related to this post & root cause given by other authors are quite accurate and very informative.
I also faced same problem as discussed in this post, when I was trying to use expect(container).toHaveLength(1);
I solved this issue by changing my way to write assertion in Jest way like,
expect(container).to.have.length(1);
So basically we need to find way to change our assertion to write in Jest way, if we are using Jest.
Hope it may help someone.

Resources