Testing react-bootstrap with mocha and ES6/babel - javascript

I am trying to write a unit test of React and React-bootstrap components using Mocha.
All of my javascript is written in ES6, and I am using babel to transpile to ES5.
The files I am using are below.
After running npm install, I run npm test. This fails with the following output:
$ npm test
> # test /Users/tda0106/test/npm
> mocha --compilers jsx:babel-register simple-test.jsx
A simple test
1) "before all" hook: render and locate element
0 passing (34ms)
1 failing
1) A simple test "before all" hook: render and locate element:
AssertionError: expected null to exist
at Context.<anonymous> (simple-test.jsx:21:9)
npm ERR! Test failed. See above for more details.
TestUtils.renderIntoDocument is returning null for no reason that I can see. The TestUtil docs indicate that window and document must be defined before importing React, which is the point of test-dom.jsx.
I am certain that test-dom.jsx is loaded before React, because before I added the line setting global.navigator, React was throwing an error deep in its code trying to access that variable.
Any idea what I need to do to make this work?
package.json
{
"dependencies": {
"react": "^15.0.1",
"react-bootstrap": "^0.28.5",
"react-dom": "^15.0.1"
},
"scripts": {
"test": "mocha --compilers jsx:babel-register simple-test.jsx"
},
"devDependencies": {
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babelify": "^7.2.0",
"chai": "^3.5.0",
"jsdom": "^8.4.0",
"mocha": "^2.4.5",
"react-addons-test-utils": "^15.0.1"
}
}
test-dom.jsx
// React needs the basic dom objects defined before it is imported.
// And babel moves the imports before the rest of the code.
// So the dom setup needs to be in its own file and imported.
import jsdom from 'jsdom';
const document = jsdom.jsdom("hello world");
const window = document.defaultView;
// A super simple DOM ready for React to render into
// Store this DOM and the window in global scope ready for React to access
global.document = document;
global.window = window;
global.navigator = {userAgent: 'None'};
export default { document: document, window: window };
simple-test.jsx
import TestDom from './test-dom.jsx';
import { expect } from 'chai';
import React from 'react';
import { Panel } from 'react-bootstrap';
import TestUtils from 'react-addons-test-utils';
const Map = () => (
<Panel>A map </Panel>
);
describe('A simple test', () => {
before('render and locate element', () => {
const renderedComponent = TestUtils.renderIntoDocument(
<Map />
);
expect(renderedComponent).to.exist; // This fails
});
it('test something', () => {
expect(1+1).is('true');
});
});
.babelrc
{
"presets": [
"es2015",
"react"
]
}

Related

Electron Blank Screen Error When Referencing Components

Good afternoon all,
I am trying to import some React components from another application of mine, into my new Electron app. On the new Electron app, I changed aspects of index.html, so that I can reference ‘root’ in my App.js component(which I imported from my react-app to the electron app). I also imported my index.js from my react app into my new electron app, and nested it in the src file.
The Problem:
I am currently getting back a blank screen, and am not sure why. It might be that i referenced some files incorrectly, or a routing issue, but I’m not certain.
(Picture of Screen Attached Below)
File Directory:
The Code:
App.js:
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import {
BrowserRouter as Router,
} from "react-router-dom";
import NavbarA from './src/components/NavbarA';
function App() {
return (
<div>
<Router>
<NavbarA/>
</Router>
</div>
);
}
export default App;
Main.js
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
Index.html
<!DOCTYPE html>
<html>
<div id="root"></div>
<title>Spotify</title>
<!-- You can also require other files to run in this process -->
<script src="./App.js>"></script>
</html>
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Package.json
{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": [
"Electron",
"quick",
"start",
"tutorial",
"demo"
],
"author": "GitHub",
"license": "CC0-1.0",
"devDependencies": {
"electron": "^18.2.0"
},
"dependencies": {
"bootstrap": "^5.1.3",
"firebase": "^9.7.0",
"react": "^18.1.0",
"react-audio-player": "^0.17.0",
"react-bootstrap": "^2.3.1",
"react-is": "^18.1.0",
"react-router-dom": "^6.3.0",
"react-scripts": "^5.0.1"
}
}
Let Me Know What You Think!
Best,
-Zpo
Had a similar issue and including
import * as React from 'react';
in the component -- NavbarA in your case -- solved my issue.

How do I create a Vue 3 custom element, including child component styles?

I tried Vue's defineCustomElement() to create a custom element, but the child component styles are not included in the shadow root for some reason.
I then tried to manually create my shadow root using the native Element.attachShadow() API instead of using defineCustomElement() (based on a Codesandbox), but then no styles were loaded at all:
Code: main.js:
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
let treeHead = document.querySelector("#app");
let holder = document.createElement("div");
let shadow = treeHead.attachShadow({ mode: "open" });
shadow.appendChild(holder);
createApp(App).use(store).use(router).mount(holder);
Code vue.config.js:
module.exports = {
chainWebpack: (config) => {
config.module
.rule("vue")
.use("vue-loader")
.loader("vue-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
config.module
.rule("css")
.oneOf("vue-modules")
.use("vue-style-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
config.module
.rule("css")
.oneOf("vue")
.use("vue-style-loader")
.tap((options) => {
options.shadowMode = true;
return options;
});
},
};
Code package.json:
{
"name": "shadow-root",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"vue": "^3.2.20",
"vue-loader": "^16.8.2",
"vue-router": "^4.0.0-0",
"vue-style-loader": "^4.1.3",
"vuex": "^4.0.0-0"
},
"devDependencies": {
"#vue/cli-plugin-router": "~4.5.0",
"#vue/cli-plugin-vuex": "~4.5.0",
"#vue/cli-service": "~4.5.0",
"#vue/compiler-sfc": "^3.0.0",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
How I can create a custom element with all its styles in the shadow root?
That Vue config is not necessary in Vue 3. It was only needed by the dev server in Vue 2 to render the styles in custom elements.
Using defineCustomElement() is the recommended way to register custom elements. However, there's an open issue when using defineCustomElement(), where nested component styles are not rendered at all (#vuejs/vue-next#4462).
A workaround is to import all components as custom elements so that the styles are attached to the component definition instead of being appended to <head>, then insert those styles into the DOM upon mounting:
Enable vue-loader's customElement mode in vue.config.js:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.customElement = true
return options
})
}
}
Alternatively, rename all component filename extensions from .vue to .ce.vue.
Create a utility function that wraps Vue's defineCustomElement() and does the following in a setup():
Create a temporary application instance that adds a mixin for the mounted and unmounted lifecycle hooks.
In the mounted hook, insert the component's own styles from this.$.type.styles into the DOM in a <style> tag. Do the same with the component definitions from the this.$options.components map.
In the unmounted hook, remove the <style> tag that was inserted from mounted.
Copy the temporary application instance's _context into the current application context from getCurrentInstance().
Return a render function for the component.
// defineCustomElementWithStyles.js
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'
const nearestElement = (el) => {
while (el?.nodeType !== 1 /* ELEMENT */) el = el.parentElement
return el
}
export const defineCustomElement = (component) =>
VueDefineCustomElement({
setup() {
const app = createApp()
1️⃣
app.mixin({
mounted() {
const insertStyles = (styles) => {
if (styles?.length) {
this.__style = document.createElement('style')
this.__style.innerText = styles.join().replace(/\n/g, '')
nearestElement(this.$el).prepend(this.__style)
}
}
2️⃣
insertStyles(this.$?.type.styles)
if (this.$options.components) {
for (const comp of Object.values(this.$options.components)) {
insertStyles(comp.styles)
}
}
},
unmounted() {
this.__style?.remove() 3️⃣
},
})
4️⃣
const inst = getCurrentInstance()
Object.assign(inst.appContext, app._context)
5️⃣
return () => h(component)
},
})
Edit public/index.html to replace the <div id="app"> with a custom element (e.g., named "my-custom-element"):
Before:
// public/index.html
<body>
<div id="app"></div>
</body>
After:
// public/index.html
<body>
<my-custom-element></my-custom-element>
</body>
Instead of createApp(), use the defineCustomElement() from above to create a custom element of your app:
Before:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
After:
// main.js
import { defineCustomElement } from './defineCustomElementWithStyles'
import App from './App.vue'
customElements.define('my-custom-element', defineCustomElement(App))
demo

How to simulate an event on a unit test with Jest, Enzyme for React-Native

I'm trying to figure out how to test an "onPress" event with Jest in a React-Native app so I can make sure the right function is called.
I went through the documentation and Google but couldn't find a solution for it in React-Native.
This is what I found that is supposed to work for React-Native with enzyme:
const mockFunc = jest.fn();
const component = mount(<MyComponent onPress={mockFunc} />);
component.simulate('press');
expect(mockFunc).toHaveBeenCalled();
But this doesn't work. Seems like mount doesn't work and I get this output:
ReferenceError: document is not defined
I tried with shallow instead but the TouchableOpacity is not getting rendered when I look at the output of the function... and you've guessed it, it doesn't work either. Not sure what to do.
Does anyone found a way to test events on React-Native?
Thanks
Enzyme does not support React-Native, because it's rendered differently and doesn't use the DOM. That's why you're getting the error ReferenceError: document is not defined. You can see this issue for more information. The React team is currently working to expose a .find() method in react-test-renderer to simulate actions on components. Then it should work for both React/React-native without needing a DOM environment.
There's a hack you can do (and that's what we did in our company) that is rendering a custom component that extends TouchableOpacity and map onClick to call onPress. Something like this:
const mockPressable = (name) => {
const RealComponent = require.requireActual(name);
class Component extends RealComponent {
render() {
return React.createElement(
RealComponent.displayName || RealComponent.name,
{ ...this.props, onClick: this.props.onPress },
this.props.children
);
}
}
return Component;
};
jest.mock('TouchableOpacity', () => mockPressable('TouchableOpacity'));
And in your test code, you call component.simulate('click').
It's a hack and I'm not sure what are the consequences of doing this but it has worked for our use cases.
You should use shallow instead, then called .dive()
const mockFunc = jest.fn();
const component = shallow(<MyComponent onPress={mockFunc} />);
component.dive().simulate('press');
expect(mockFunc).toHaveBeenCalled();
I'm able to run tests like what you've described in your question in React Native. Here is my configuration:
package.json
"scripts": {
...
"test": "node_modules/jest/bin/jest.js",
}
"devDependencies": {
...
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"enzyme-to-json": "^3.1.2",
"jest": "^21.2.1",
"jest-enzyme": "^4.0.0",
"jest-expo": "~21.0.0",
}
"jest": {
"preset": "jest-expo",
"setupFiles": [
"./test/jestSetup.js"
],
"snapshotSerializers": [
"./node_modules/enzyme-to-json/serializer"
]
}
test/jestSetup.js
import { configure, shallow, render, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure( { adapter: new Adapter() } )
// enzyme
global.shallow = shallow
global.render = render
global.mount = mount
Example component:
import React from 'react'
import { Button } from 'react-native'
const CancelButton = ( props ) =>
<Button
{ ...props }
onPress={ () => { props.navigation.goBack() } }
title="Cancel"
/>
export { CancelButton }
Example test
import React from 'react'
import { CancelButton } from '../CancelButton'
test( 'onPress', () => {
const goBackFunc = jest.fn()
const navigation = {
goBack: goBackFunc,
}
const component = shallow(
<CancelButton
navigation={ navigation }
/>
)
component.simulate( 'press' )
expect( goBackFunc ).toHaveBeenCalled()
} )
.babelrc
{
"presets": ["babel-preset-expo"],
"env": {
"development": {
"plugins": ["transform-react-jsx-source"]
}
}
}

how to add this external vue component in my laravel5.3 project?

I try to add http://gritcode.github.io/gritcode-components/#/wizard in my laravel 5.3 project but when i used its nothing showing in my view here is i'm getting console "Uncaught ReferenceError: gritcode is not defined"
my app.js is.
require('./bootstrap');
Vue.component('example', require('./components/Example.vue'));
new Vue({ components: { 'vs-toast': gritcode-components.toast }})
const app = new Vue({
el: '#app',
});
and my welcome.blade.php
<div id="app">
<vs-toast>
<vs-wizard :current-index.sync="currentStep">
<vs-wizard-step
title="Personal Information"
description="Enter your details"
:progress="progress.step1"
icon="person">
</vs-wizard-step>
<vs-wizard-step
title="Payment"
description="Pay with credit card or Paypal"
:progress="progress.step2"
icon="credit-card">
</vs-wizard-step>
<vs-wizard-step
title="Confirmation"
description="Your order details"
:progress="progress.step3"
:disable-previous="true"
icon="check">
</vs-wizard-step>
</vs-wizard>
</vs-toast>
</div>
my package.json
{
"private": true,
"scripts": {
"prod": "gulp --production",
"dev": "gulp watch"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"bootstrap-sass": "^3.3.7",
"gritcode-components": "^0.4.7",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-9",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.0.1",
"vue-resource": "^1.0.3",
"vuestrap-base-components": "^0.8.10",
"webpack": "^1.14.0"
},
"dependencies": {
"vue-material-datepicker": "^2.0.1"
}
}
my gulpfile.js
const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');
elixir(mix => {
mix.sass('app.scss')
.webpack('app.js');
});
As the example says on the intro page you have to import them from a subdirectory of the plugin.
The example given on their website is for their toast component which has a default export, however, because wizard is made up of two components it uses named exports instead so the syntax for importing them is slightly different.
Importing default export
import foo from "someComponent"
Importing named exports
import {bar, baz} from "SomeOtherComponent"
So, for your situation you should be able to do:
require('./bootstrap');
import {wizard, wizardStep} from "gritcode-components/src/components/wizard";
const app = new Vue({
el: '#app',
components: {
'vs-wizard': wizard,
'vs-wizard-step': wizardStep
}
});
Hope this helps!
I had a similar issue and this worked for me.
import { wizard as vsWizard } from 'gritcode-components/dist/gritcode-components';
import { wizardStep as vsWizardStep } from 'gritcode-components/dist/gritcode-components';
import { toast as vsToast } from 'gritcode-components/dist/gritcode-components';
note that we are loading this from
"gritcode-components/dist/gritcode-components"
not from
"gritcode-components/src/components/wizard" as suggested in one of the answers.
then in your Vue instance you can do something like this to load the components:
require('./bootstrap');
const app = new Vue({
el: '#app',
components: {
vsWizard,
vsWizardStep,
vsToast
},
data: {
currentStep: 0
},
computed: {
progress: function() {
return {
step1: this.getStepPercentage(1),
step2: this.getStepPercentage(2),
step3: this.getStepPercentage(3)
};
}
},
methods: {
getStepPercentage: function(stepNumber) {
if (stepNumber == 1) {
//depending on your requirements you will return
//a value between 0 and 100 that describe
//the completion status of the step 1
}
if (stepNumber == 2) {
//depending on your requirements you will return
//a value between 0 and 100 that describes
//the completion status of the step 2
}
if (stepNumber == 3) {
//depending on your requirements you will return
//a value between 0 and 100 that describes the
//completion status of the step 3
}
}
}
});
Also in your question, you have two Vue instances: one for which you load the components, and another one bound to the element with id #app. The one with the #app element is the one that will be managing your html from the blade file. The problem you will run into, once this code loads is that you are adding the components on the Vue instance that is not bound to your #app div, and therefore the Vue instance designated for managing your #app element will not have access to them. So I suggest using only one instance of Vue like in the example above unless you have a good reason for using more
Lastly, I would advise you against wrapping your 'vs-wizard' tag element with 'vs-toast', unless you are trying to display the wizard in your toast, which I am not sure is possible.
You can do something like this instead:
<div id="app">
<vs-toast></vs-toast>
<vs-wizard :current-index.sync="currentStep">
<vs-wizard-step
title="Personal Information"
description="Enter your details"
:progress="progress.step1"
icon="person">
</vs-wizard-step>
<vs-wizard-step
title="Payment"
description="Pay with credit card or Paypal"
:progress="progress.step2"
icon="credit-card">
</vs-wizard-step>
<vs-wizard-step
title="Confirmation"
description="Your order details"
:progress="progress.step3"
:disable-previous="true"
icon="check">
</vs-wizard-step>
</vs-wizard>
</div>

Testing React: Target Container is not a DOM element

I'm attempting to test a React component with Jest/Enzyme while using Webpack.
I have a very simple test #
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('App', () => {
const app = shallow(<App />);
expect(1).toEqual(1);
});
The relative component it's picking up is :
import React, { Component } from 'react';
import { render } from 'react-dom';
// import './styles/normalize.css';
class App extends Component {
render() {
return (
<div>app</div>
);
}
}
render(<App />, document.getElementById('app'));
However, running jest causes a failure:
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
With errors #
at Object.<anonymous> (src/App.js:14:48)
at Object.<anonymous> (src/App.test.js:4:38)
The test files references line 4, which is the import of <App />, that causes a fail. The stack trace says line 14 of App.js is the reason for the failure -- which is nothing more than the render call from react-dom, something I've never had a challenge with (the app renders properly from my Webpack setup).
For those interested (Webpack code):
module.exports = {
entry: './src/App',
output: {
filename: 'bundle.js',
path: './dist'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
},
{
test: /\.scss$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass'
}
]
}
}
And my package.json:
{
"name": "tic-tac-dux",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors --inline --hot --content-base dist/",
"test": "jest"
},
"jest": {
"moduleNameMapper": {
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"^.+\\.(css|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.17.0",
"babel-jest": "^16.0.0",
"babel-loader": "^6.2.5",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.25.0",
"enzyme": "^2.4.1",
"jest": "^16.0.1",
"jest-cli": "^16.0.1",
"node-sass": "^3.10.1",
"react-addons-test-utils": "^15.3.2",
"react-dom": "^15.3.2",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"react": "^15.3.2",
"react-dom": "^15.3.2"
}
}
Oh, and if anyone is going to say that the div element isn't being loaded before the script, here's my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>App</title>
</head>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>
What could be the reason for this peculiar rendering problem? Something to do with a new Jest update to 15.0?
For anyone else that was combing through the internet like I've been - looking for a solution to this when testing with Jest - I will back up the answer by #biphobe by saying Jest will cause this error to occur when you export something inside the same file that is calling ReactDOM.render.
In my case, I was exporting an object within my index.js where I was also calling ReactDOM.render. I removed this export and voila!
App.jsx is supposed to export the App class and do nothing more, render should be called elsewhere.
If you remove the render call from the App.jsx error should disappear, it pops up because the test environment doesn't supply the DOM with an app id.
As I see, this error arises in many cases and requires different approaches to solve it. My scenario is not the same as the example above, I use redux & router, although I was struggling with the same error. What helped me to solve this problem is to change index.js from:
ReactDOM.render(
<Provider store={store}>
<AppRouter />
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
to:
ReactDOM.render(
(<Provider store={store}>
<AppRouter/>
</Provider>),
document.getElementById('root') || document.createElement('div') // for testing purposes
);
registerServiceWorker();
I found a solution for this error to my use case: Using the same Redux store React is using outside of React.
In trying to export my React's Redux store from index.tsx to be used somewhere else outside of the React application, I was getting the same error while running Jest tests (which make use of Enzyme) in the App.tsx file.
The error
The initial code that didn't work when testing React looked like this.
// index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose, createStore } from "redux";
import App from "./components/App";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
The solution that worked for me
Separate the Redux store logic into a new file named store.ts, then create a default export (to be used by index.tsx, i.e., the React application) and a non-default export with export const store (to be used from non-React classes), as follows.
// store.ts
import { applyMiddleware, compose, createStore } from "redux";
import logger from "redux-logger";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
export default store;
// updated index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
Using the Redux store in non-React classes
// MyClass.ts
import { store } from "./store"; // store.ts
export default class MyClass {
handleClick() {
store.dispatch({ ...new SomeAction() });
}
}
The default export
A small note before you go. Here is how to use the default and the non-default exports.
default export store; is used with import store from "./store";
export const store = ... is used with import { store } from "./store";
Hope this helps!
https://nono.ma/says/solved-invariant-violation-target-container-is-not-a-dom-element
Make sure in your test file you have well imported the render component.
It should be imported from #testing-library/react not from react-dom:
import { render } from '#testing-library/react';
Well we cant stop the developers from exporting component from any file and test it in isolation even if it have a react-dom import or usage in it .I mean what's wrong in it . We are not trying to disturb the whole file and test out some pieces of it as long as that is a valid piece of code .
Jest does not have an issue with react-dom , however conceptually they are diff . Jest is supposedly a browserless virtual test environment . React-DOM is a library which does the stitching of virtual DOM to real DOM for react components .
So obvious enough we can/should not test it in a normal way . But that is not the discussion for now. we are fine as long as our exported components are testable .
So Lets mock it
I did the mock in the testSetup file configured with "setupFilesAfterEnv" in jest config .
jest.mock("react-dom", () => {
return ({
"render": jest.fn()
})
})
That is pretty much worked for me. My react and react-dom code now happily go together in one file , works in browser and in the testing environment as well .
I have not encountered any issues because of this . If there is any I will be looking into the comment section
This solution worked for me. Just render if the element is there:
const root = document.getElementById('root');
if (root) {
render(
<App />,
root,
);
}
I found out this error can also be thrown when working with Portals in your tests. If you want to skip the error you can either mock Portals or add the Portal container element in your render method:
render (
<div>
<TestedComponent />
<div id="portal" />
</div>
)

Categories

Resources