Problem testing react component that implement react-leaflet map with jest - reactjs

I have the following issue when I tried to test a react components that implement the react-leaflet library
C:\digital-booking-ui\node_modules\react-leaflet\lib\index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { useMap, useMapEvent, useMapEvents } from './hooks.js';
^^^^^^
SyntaxError: Unexpected token 'export'
1 | import React from "react";
2 | import { makeStyles } from "#material-ui/core";
> 3 | import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
| ^
4 |
5 | const Map = () => {
6 | const classes = useStyles();
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (src/components/accomodation/Map.js:3:1)
I search the problem on the internet and the recommendations I found don't work for me.
This error happen when I tried to render any component that has a relation with that library, for example, App.test.js
import { render, screen, prettyDOM } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect'
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '#material-ui/core';
import theme from "./theme";
let component = null;
beforeEach(() => {
component = render(
<BrowserRouter>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</BrowserRouter>
);
}
);
test('render App', () => {
expect(component).toBeTruthy();
});
How could I fix this? It seems a problem of Jest not recognizing the export of the components

In your package.json add these lines
"jest": {
"moduleNameMapper": {
"react-leaflet": "<rootDir>/mocks/reactLeafletMock.js"
}
}
Then in a "mocks" folder (or whatever you want) add a reactLeafletMock.js module that return an empty object
module.exports = {}
It should be ok (it worked for me)
You could eventually add "react-leaflet" hooks within the object to avoid other errors from Jest
module.exports = {
useMapEvents: () => {}
}

Related

Re Exporting everything is not working as expected - issue while import in another file

I am writing the custom render for test files in react project which is using react testing library so that i can avoid the boiler plate for every test file where i have wrapped it with the Tag.
So in the custom render file test-util.tsx I am exporting everything from #testing-library/react so that I can import my custom render function and all the other React Testing Library functionality (fireEvent , screen etc.) from the same place.
but while doing so i can not import other RTL functions like fireEvent, screen, waitFor etc.
Below is my code :
test-utils.tsx:
import React, {FC, ReactElement} from 'react';
import {render} from '#testing-library/react';
import {Provider} from 'react-redux';
import {BrowserRouter as Router} from 'react-router-dom';
import configureStore from 'redux-mock-store';
const mockStore = configureStore([]);
const customRender = (
ui: ReactElement,
{initialState = {}, store = mockStore(initialState), ...renderOptions} = {}
) => {
const ProviderWrapper: FC = ({children}) => {
return (
<Router>
<Provider store={store}>{children}</Provider>
</Router>
);
};
return render(ui, {wrapper: ProviderWrapper, ...renderOptions});
};
export * from '#testing-library/react';
export {customRender as renderWithProviders};
test file -- abc.test.tsx
import {renderWithProviders, screen, fireEvent, waitFor} from 'test-utils';
errors :
has no exported member 'fireEvent'
has no exported member 'waitFor'
to avoid the relative import i have done below config set up:
jest.config.json :
test-utils is under src/utils/test-utils
module.exports = {
...
moduleDirectories: ['src', 'node_modules', '<rootDir>/src/utils'],
...
}
**tsconfig.json: **
"compilerOptions" : {
...,
"baseUrl": "./src",
"paths": {
"^/*": ["../*"],
"#/*": ["*"],
"test-utils": ["./utils/test-utils"]
}
...
}

Unit testing Chakra UI with Jest

Currently I am trying to unit test my application that is built with Create-React-App with typescript, and it is styled with chakraui. Chakrui includes a component ThemeProvider that must wrap the entire application as such.
This is my index.tsx file
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { ThemeProvider, CSSReset } from "#chakra-ui/core/dist";
import { theme } from "#chakra-ui/core/dist";
ReactDOM.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<CSSReset />
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById("root")
For every unit test that I write, I am having to wrap the component with ThemeProvider for the test to pass:
import React from "react";
import { render } from "#testing-library/react";
import { ThemeProvider } from "#chakra-ui/core/dist";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
render(
<ThemeProvider>
<App />
</ThemeProvider>
);
});
});
But this is very verbose, and must be done for every test that I write. Is there a way to do this just once in each .test.tsx file?
You could create your own theme wrapper function
import React from "react";
import { ThemeProvider } from "#chakra-ui/core/dist";
export const ThemeWrapper = ({ children }) => (
<ThemeProvider>{children}</ThemeProvider>
);
And then specify the wrapper in the test
import React from "react";
import { render } from "#testing-library/react";
import { ThemeWrapper } from "../testUtils";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
render(<App />, { wrapper: ThemeWrapper });
});
});
This marginally reduces the code for testing. You may be able to also go the route of creating a custom render function (following the steps for redux).
It could look something like
import React from "react";
import { render } from "#testing-library/react";
import { ThemeProvider } from "#chakra-ui/core/dist";
export const renderWithTheme = ui => {
const Wrapper = ({ children }) => (
<ThemeProvider>{children}</ThemeProvider>
);
return render(ui, { wrapper: Wrapper });
};
Basically the same as the wrapper above, but more integrated into a test render function. You can adjust the function signature a bit as well if you need to pass in a theme object, or other render options, this is just a simple example.
Now the test looks like
import React from "react";
import { renderWithTheme } from "../testUtils";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
renderWithTheme(<App />);
});
It might be the case that Jest might be mocking your imports from #chakra-ui/core/dist (depending on your jest configuration) which might be resulting your imported chakra-ui components to be undefined.
Importing the Theme Provider and wrapping it everytime with your renders might be one way to do it. The problem might arise when you have multiple components in your index.tsx. So, you might not want to import each and every component.
In that case, you will want to import the actual components from #chakra-ui/core.
The best way (according to me) to do so in Jest is:
jest.mock("#chakra-ui/core", () => {
const ui = jest.requireActual("#chakra-ui/core");
return {
...ui,
customKey: 'customValue',
};
})
This way you can even add custom function and key-values to the imported module.

How to set intellisense for react testing library using typescript

I just downloaded Create-React-App which uses react testing library. I do not get intellisense when I use it's methods (Example : toBeInTheDocument) . How to set intellisense ? Do we have any type definitions for RTL?
import React from 'react';
import { render } from '#testing-library/react';
import App from './App';
test('renders learn react link', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
You need to import '#testing-library/jest-dom'

Jest - unexpected identifier - Component testing w Jest react-native

I keep getting this error when trying to test a button component. I have changed Jest's config settings here and there but nothing has worked, can anyone tell me the answer so I can stop pulling my hair out?
I am using expo to demo the app, the problem seems to lie within the font that it's trying to render on the nav button, Jest/React doesn't understand it.
The failure:
FAIL tests/Components/NavigationButton.test.js
● Test suite failed to run
C:\..\node_modules\#expo\vector-icons\Zocial.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Zocial from './build/Zocial';
^^^^^^
SyntaxError: Unexpected identifier
at ScriptTransformer._transformAndBuildScript (node_modules/#jest/transform/build/ScriptTransformer.js:537:17)
at ScriptTransformer.transform (node_modules/#jest/transform/build/ScriptTransformer.js:579:25)
at Object.<anonymous> (node_modules/react-native-elements/src/helpers/getIconType.js:1:1)
NavigationButton.js:
import React from "react";
import { StyleSheet } from "react-native";
import { Button } from "react-native-elements";
import Icon from "react-native-vector-icons/FontAwesome";
import { withNavigation } from 'react-navigation';
const NavigationButton =(props) => {
return (
<Button data-test="nav_button"
icon={<Icon name={props.icon} size={30} color="white" style={styles.iconStyle} />}
raised
color="white"
buttonStyle={styles.button}
title={props.title}onPress={() => props.navigation.navigate(props.navName)}
/>
);
};
const styles = StyleSheet.create({
button: {
minWidth:150,
alignSelf:'center',
},
iconStyle:{
marginHorizontal:10
}
});
export default withNavigation(NavigationButton);
NavigationButton.test.js:
/**
* #format
*/
import 'react-native';
import React from 'react';
import { shallow } from 'enzyme';
import { findByTestAtt } from '../../Utils/test_utils';
import NavigationButton from '../../src/Components/NavigationButton'
// Note: this is just for use with Jest snapshot testing
// and comes packaged with react-native init project.
// You do not need this if using Enzyme 'toMatchSnapshot' etc.
import renderer from 'react-test-renderer';
// setup for shallow rendering component, saves having to do it in every test in this file
const setup = (props = {}) => {
const component = shallow(<NavigationButton {...props} />);
return component;
};
describe('NavigationButton tests: ', () => {
let component;
beforeEach(() => {
component = setup();
});
it('Button renders correctly: ', () => {
console.log(component.debug());
const wrapper = findByTestAtt(component, 'nav_button');
expect(wrapper.length).toBe(1);
});
});
Using the jest-expo preset solved the problem for me. The documentation explains it well: https://www.npmjs.com/package/jest-expo. The issue seemed to be that the import keyword wasn't being transformed, I'm not clear on why but it came up in an issue here: https://github.com/expo/expo/issues/5296

mount() fails because target container is not dom element

I'm getting error message Target container is not a DOM element. Using webpack.
Full Error:
FAIL src/App.test.js
● Test suite failed to run
Invariant Violation: Target container is not a DOM element.
at invariant (node_modules/fbjs/lib/invariant.js:42:15)
at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:17238:34)
at Object.render (node_modules/react-dom/cjs/react-dom.development.js:17317:12)
at Object.<anonymous> (src/index.js:32:20)
at Object.<anonymous> (src/App.test.js:5:14)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:169:7)
App.js
import React, { Component } from 'react';
import './App.scss';
import Tables from './containers/Tables/Tables'
class App extends Component {
render() {
return (
<Tables />
);
}
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import aaaApi from '#aaa/aaajs';
import './index.css';
import App from './App';
import tableBuilderReducer from './store/reducers/tableBuilder'
import registerServiceWorker from './registerServiceWorker';
const aaa = new aaaApi('xxx');
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const reducers = {
platforms: tableBuilderReducer('platforms'),
regions: tableBuilderReducer('regions'),
playback: tableBuilderReducer('playback')}
export const store = createStore(
combineReducers(reducers),
composeEnhancers(
applyMiddleware(thunk.withExtraArgument(aaa)),
),
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
registerServiceWorker();
App.test.js
import React from 'react'
import Enzyme, { mount, shallow } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import App from './App'
import { store } from './index.js'
Enzyme.configure({ adapter: new Adapter() })
function setup() {
const props = {
sortColumnHandler: jest.fn()
}
const enzymeWraper = mount(<App />)
return {
props,
enzymeWraper
}
}
describe('components', ()=> {
describe('Tables', () => {
it('should render self and sub-components', () => {
const { enzymeWraper } = setup()
})
})
})
The issue is being caused by index.js being included in the test and is failing at ReactDOM.render() when root is not found in the document created by the jsdom environment in Jest.
import { store } from './index.js' is not needed in App.test.js so removing that will fix the initial error.
Using mount from enzyme does a full DOM rendering and requires that everything be set up for a full render. It should only be used to unit test components that use lifecycle methods, interact with the DOM, etc. It will fully render the component being tested and all children components. In this case the children of App use the redux store so a store would need to be provided in a wrapping Provider in order to do a full render using mount.
In most cases, React components should be unit tested using shallow. It does a shallow rendering of just the component being tested. In this case App is a simple stateless component that contains Tables so using shallow is the right approach.
bonus tip:
Install enzyme-to-json as a dev dependency, add it to Jest as a snapshot serializer, and App.test.js gets simplified to this:
import { shallow } from 'enzyme';
import * as React from 'react';
describe("App", () => {
it('renders as expected', () => {
const component = shallow(<App />);
expect(component).toMatchSnapshot();
});
});

Resources