I am working on a React-Nextjs project and trying to integrate the BDD tool cucumber for specification and feature level testing. Though am having some trouble integrating cucumber with React when using enzyme to shallow render the component:
Here's the errors am getting:
TypeError: Cannot read property 'contextTypes' of undefined at const wrapper = shallow(<Referrer/>);
Code for cucumber step test file:
import React from 'react';
import { defineSupportCode } from "cucumber";
import { shallow } from "enzyme";
import {Referrer} from "./../../components/Referrer";
defineSupportCode(({ Given, When, Then }) => {
Given("I want to do something", function (callback) {
// Write code here that turns the phrase above into concrete actions
callback();
});
When("Xyz link is clicked", function (callback) {
const wrapper = shallow(<Referrer/>);
... // Write code here that turns the phrase above into concrete actions
});
Then("Appropriate action happens", function (callback) {
// Write code here that turns the phrase above into concrete actions
callback();
});
});
The component is a simple UI component, pretty straight forward, here's its structure:
import React from "react"; // eslint-disable-line no-unused-vars
export default class Referrer extends React.Component {
render () {
return (
<div className="some-class" id="some-id">
// html tags
<style jsx>{`
.some-class {
//styling
}
.some-class2 {
//styling
}
`}
</style>
</div>
);
}
}
I am using "cucumber": "^2.3.1", "enzyme": "^2.6.0", I am not sure how to resolve this, no help so far online, I have been trying to debug for last couple hours but no luck.
Exact error snippet:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in.
TypeError: Cannot read property 'contextTypes' of undefined at const wrapper = shallow(<Referrer/>);
I realized what was wrong, my Referrer component is being exported as a default, though I wasn't importing it correctly. I had to import it as import Referrer from "./../../components/Referrer"; instead of import {Referrer} from "./../../components/Referrer";
Related
I am having a lot of trouble trying to implement tests for a component using the useSelector hook from react redux. I've seen some questions already about this subject but I didn't manage to fix my problem using the suggested solutions to those questions.
My component is pretty big so I won't post it all but the part giving me trouble looks like this :
Total.tsx
import React from 'react';
import clsx from 'clsx';
import i18next from 'i18next';
import { useSelector } from 'react-redux';
import { Trans } from 'react-i18next';
import Box from '#material-ui/core/Box';
import CustomTooltip from '../CustomTooltip/CustomTooltip';
import SkeletonTotal from 'components/Skeletons/Total';
import { ApplicationHelper } from 'helpers';
import './Total.scss';
//Some interfaces here for types since this is in TypeScript
function Total(props: TotalProps) {
const { currency } = useSelector(
(state: { currencyReducer: any }) => state.currencyReducer
);
...
}
I first tried to test it like another component that doesn't use redux like so :
Total.test.js (first attempt)
import React from 'react';
import Total from './Total';
import { render } from '#testing-library/react';
test('test', () => {
const { container } = render(
<Total priceLoading={false} bookingPrice={bookingPrice} values={myFormValues} />
);
});
But I was getting an error saying I need a react-redux context value and to wrap my component in a Provider which led me to try this :
Total.test.js (attempt 2)
import React from 'react';
import { Provider } from 'react-redux'
import Total from './Total';
import { render } from '#testing-library/react';
test('test', () => {
const { container } = render(
<Provider>
<Total priceLoading={false} bookingPrice={bookingPrice} values={myFormValues} />
</Provider>
);
});
I am now getting a "Cannot read property 'getState' of undefined" error for the Provider component. I did try to mock a store to pass to my Provider as well as using jest to mock a return value like so
const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue({currency: 'cad'})
Unfortunately I was unsuccessful to make this work and could not find a working solution in the other questions that might relate to this. Any ideas how I could make this work? Thanks
The useSelector hook relies on the redux Context in order to access the state, so it must be inside of a Provider component in order to work. Your second attempt is on the right track, but you haven't set the store prop on the Provider, so the store is undefined and you get error "Cannot read property 'getState' of undefined".
Since you'll likely have many components that you'll want to test with redux context, the redux docs suggest creating your own version of the react testing library's render function which wraps the element in a provider before rendering it. This new render function adds two new optional options to the standard RTL options: initialState and store.
You can basically copy and paste that entire test-utils.js example from the docs, but I modified the return to include the created store so that we can dispatch to it directly (rather than just interacting with the component in ways that will dispatch an action).
return {
...rtlRender(ui, { wrapper: Wrapper, ...renderOptions }),
store
};
With typescript annotations.
Inside your component test file, you will use your test-utils to render the Total component. It's fine to return the container element but you don't actually need to because you can query matching elements on the global RTL screen object or on the bound queries for your base element. We are basically looking to see that the outputted HTML code matches the expectations. You could test the selector itself in isolation, but it seems like you are trying to test the component.
Your test might look something like this:
import React from "react";
import Total from "./Total";
import { render, screen } from "./test-utils";
// if you want events: import userEvent from "#testing-library/user-event";
test( 'gets currency from redux', () => {
// render with an initial currency
const { store, container, getByLabelText } = render(
// not sure where these props come from, presumable constants in the file
<Total priceLoading={false} bookingPrice={bookingPrice} values={myFormValues} />,
{ initialState: { currency: USD } }
);
// some sort of RTL matcher or document.querySelector
const currencyElement = getByLabelText(/currency/i); // uses regex for case-insensitivity
// some sort of check for value
expect(currencyElement?.innerText).toBe("USD");
// dispatch an action to change the currency
// might want to wrap in `act`?
store.dispatch(setCurrency("EUR"));
// check that the value changed
expect(currencyElement?.innerText).toBe("EUR");
});
Working example that I created based on a basic counter component.
Earlier today, I tried running create-react-app, but I got an error about templates and how my version of React may be out of date. So I removed React globally and then reinstalled. I ran create-react-app again and it started working again.
I was trying to create an app afterwards but I keep getting the following message:
×
Error:
Element type is invalid: expected a string (for built-in
components) or a class/function (for composite components) but got:
object. You likely forgot to export your component from the file it's
defined in, or you might have mixed up default and named imports.
Check the render method of App.
I never got this message before while using React. Here is my code so far:
App.js
import React, { Component } from 'react';
import UserOutput from './Components/UserOutput';
import UserInput from './Components/UserInput'
class App extends Component {
render() {
return (
<div>
<UserInput />
<UserOutput username="Test" />
</div>
)
}
};
export default App;
UserOutput.js
import React from 'react';
function UserOutput(props) {
return <h1>this is my username: {props.username} </h1>;
}
export default UserOutput;
UserInput.js
import React from 'react';
function UserInput() {
return <input>Name</input>
};
export default UserInput;
I tried searching for a fix for my error, but could not find a solution. I believe I am importing everything correctly and it complies without error in my IDE, but I get the error in my browser.
Good day
I am a novice React developer building a site for a client using ES6 standards. I have found a component for which the usage as description uses an older syntax, and I am having some trouble implementing my code. I am receiving an error message that I am not sue how to resolve.
The component in questions can be seen here:
https://www.npmjs.com/package/react-fontawesome
it instructs you to use the component as follows:
var React = require('react');
var FontAwesome = require('react-fontawesome');
React.render(<FontAwesome name='rocket' />, document.body);
To my understanding, this is an older way of writing React code. I have thus updated my code to for the ES6 standard.
I scratched in my package.json file to find out where to import the component from, so I am not sure if this is perhaps where I have gone wrong.
Below is a copy of my code using what I believe to be the correct implementation:
import React, { Component } from "react";
import FontAwesome from '#fortawesome/fontawesome-svg-core';
export class Footer extends Component {
constructor(props) {
super(props);
}
render = _ => {
return (
<div>
<FontAwesome name='rocket' />
</div>
);
}
}
When I import the component and run the code I get the following error:
React.createElement: type is invalid -- expected a string (for
built-in components) or a class/function (for composite components)
but got: undefined. You likely forgot to export your component from
the file it's defined in, or you might have mixed up default and named
imports.
Check the render method of Footer.
in Footer (created by App)
in div (created by App)
If anyone would be kind enough to let me know where I might be going wring, I would be incredibly grateful.
There's a simple example on their docs page that should help out:
import ReactDOM from 'react-dom'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faCoffee } from '#fortawesome/free-solid-svg-icons'
const element = <FontAwesomeIcon icon={faCoffee} />
ReactDOM.render(element, document.body)
So I have a React Class lets call it A. I'm running a jest test on it, but I keep getting an
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
In the React Class I'm doing :
export class A extends Component ..
In the jest test file I'm doing :
import { A } from './A.js'
when I run :
const wrapper = mount(<A />)
I get the error above. I'm running on a jsdom environment for jest. I'm kind of at a loss why this wouldn't work. I've read that some people export as default, but I don't see why doing a proper name import shouldn't work. Does anyone have any ideas what could be the issue?
real code :
jest file :
import Adapter from 'enzyme-adapter-react-16';
import Enzyme, { shallow, mount } from 'enzyme';
import React from 'react';
import { A } from '../A';
Enzyme.configure({ adapter: new Adapter() });
/**
* Test Suite
*/
describe('A test', () => {
it('calls componentDidMount', () => {
const wrapper = mount(<A />);
})
})
react class :
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export class A extends Component {
...
}
jest config :
module.exports = {
clearMocks: true,
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',
// The test environment that will be used for testing
testEnvironment: 'jsdom',
testURL: 'http://localhost/',
// Directory to search for tests
roots: ['src/'],
// The glob patterns Jest uses to detect test files
testMatch: [
'**/__tests__/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[tj]s?(x)'
],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
testPathIgnorePatterns: [
'/node_modules/'
],
snapshotSerializers: [
'enzyme-to-json/serializer'
]
};
That is the error that you get when you attempt to render an Object as a Component.
Here is an example:
A.js
import * as React from 'react';
const AnObject = {}; // <= NOT a component
export class A extends React.Component {
render() {
return (<AnObject/>); // <= Attempt to render an object as a component
}
}
A.test.js
import * as React from 'react';
import { mount } from 'enzyme';
import { A } from './A';
test('A', () => {
const wrapper = mount(<A/>); // <= Fails with "Invariant Violation: Element type...
});
...which gives the following error:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of A.
5 |
6 | test('A', () => {
> 7 | const wrapper = mount(<A/>);
| ^
8 | });
9 |
You'll want to check A at the point of the test and make sure it is actually your component.
Then work backwards and make sure everything rendered as a component by A is actually a component (and so on) until you find the non-component that is being used as a component.
LayoutGroup is not a default export
You cannot call LayoutGroup via import { A } from '../A'; it is not exported with default so you cannot rename it as a named import.
To do something like this change
import { A } from './A.js'
to
import A from './A.js'
and
export class LayoutGroup extends Component {
to
export default class LayoutGroup extends Component {
I want to create a slider in my project and I am using react-rangeslider library. I wrote a very simple piece
const Slider = require('react-rangeslider');
var Para = React.createClass({
handleChange: function(value) {
this.setState({
value: value,
});
},
render: function () {
return (
<Slider
value={this.state.value}
orientation="vertical"
onChange={this.handleChange} />
);
}
});
which is resulting in the error
app.js:6873 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of `Para`.
Version "react-rangeslider": "^2.2.0"
Other libraries I tried were mdbReact, ReactBootstrapSlider.
I did see the posts with similar error but all those are importing in a different way.
This is a known issue, the library doesn't export default properly, so to import the library you'll need to do:
const Slider = required('react-rangeslider').default;
Source:
https://github.com/whoisandy/react-rangeslider/issues/96
this error happens when you import incorrectly your component.
in case you are using default export:
// yourfile.js
const Component;
export default Component;
// anotherFile.js
import yourComponent form './yourfile';
in case you are using named export:
// yourfile.js
export const Component;
// anotherFile.js
import { Component } form './yourfile';