Why is jest test not recognizing react native components? - reactjs

I have a react native app that I am trying to run tests on, I have set up a basic greeting component as shown below called Greetings.js:
import React from 'react';
import {View, Text} from 'react-native';
const Greetings = ({hello}) => {
return (
<View>
<Text>{hello}</Text>
</View>
);
};
export default Greetings;
This is the test I am running called Greetings.test.js:
import React from 'react';
import {render, screen} from '#testing-library/react-native';
import Greetings from './Greetings';
describe('Greetings component', () => {
it('renders hello world as a test', () => {
render(<Greetings hello="Hello World!" />);
const helloWorldElement = screen.getByText('Hello World!');
expect(helloWorldElement).toBeInTheDocument();
});
});
For some reason it doesnt recognise the react native components, this is the error when running the test:
FAIL app/__tests__/components/Account/Greetings.test.js
● Console
console.error
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You li
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 `Greetings`.
at Greetings (C:\Users\meeve\OneDrive\Desktop\Cozify\smartliving-app\app\__tests__\components\Account\Greetings.js:4:21)
5 | return (
6 | <View>
> 7 | <Text>{hello}</Text>
| ^
8 | </View>
9 | );
10 | };
at printWarning (node_modules/react/cjs/react.development.js:220:30)
at error (node_modules/react/cjs/react.development.js:196:5)
at Object.createElementWithValidation [as createElement] (node_modules/react/cjs/react.development.js:2215:7)
at Greetings (app/__tests__/components/Account/Greetings.js:7:7)
at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6016:18)
at mountIndeterminateComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8744:13)
at beginWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9966:16)
at performUnitOfWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13800:12)
It shows the same error for the View Component.
Should it not automatically recognize these components after initial setup?
I have installed the following:
yarn add install -dev react-test-renderer#17.0.1 #testing-library/react-native #testing-library/jest-native
The current Jest configuration in the package.json file:
"jest": {
"preset": "react-native",
"coverageThreshold": {
"app/**/selectors.{js,ts,tsx}": {
"_comment": "Let's strive to increase coverage, instead of lowering it!",
"lines": 57
}
},
"coverageDirectory": ".coverage/",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"native"
],
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js|jsx)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache",
"setupFiles": [
"./jest.setup.js"
]
}

Seems nothing wrong with the component rendering but the test.
You can use getByText query which can be obtained from render.
Please refer to React Native Testing Library for more information.
import React from 'react';
import {render} from '#testing-library/react-native';
import Greetings from './Greetings';
describe('Greetings component', () => {
it('renders hello world as a test', () => {
const {getByText} = render(<Greetings hello="Hello World!" />);
expect(getByText('Hello World!')).toBeDefined();
});
});

The application was set up a while back and it seems they had mocked out the react-native imports in the jest.setup.js file so that was causing the issue

Related

Jest / React Testing Library, So Many Errors

I'm new to React Testing Library and Jest. I could successfully run a simple set of tests on it, like the below,
but when I tried to test on my "App.js", where a lot of imports/requires, it started to get a many set of errors on the each import, and I'm tbh overwhelmed.
Here's a working example:
./src/dev/test/AppTmp.js
import React from "react";
export const Topbar = () => {
return (
<>
<p>hoge.</p>
</>
)
}
./src/__tests__/hello.js
import '#testing-library/jest-dom/extend-expect'
import React from 'react'
import { render, screen } from '#testing-library/react'
import * as renderer from "react-test-renderer";
import { Topbar } from '../dev/test/AppTmp'
test('tmp test.', () => {
const component = renderer.create(
<Topbar />,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
})
The above successfully runs.
A problem is when I add an import line like this:
./src/dev/test/AppTmp.js
import React from "react";
import ReactMarkdown from 'react-markdown'; // <--- added this
export const Topbar = () => {
return (
<>
<p>hoge.</p>
</>
)
}
./src/__tests__/hello.js
import '#testing-library/jest-dom/extend-expect'
import React from 'react'
import { render, screen } from '#testing-library/react'
import * as renderer from "react-test-renderer";
import { Topbar } from '../dev/test/AppTmp'
test('tmp test.', () => {
const component = renderer.create(
<Topbar />,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
})
The above, with just an extra import line, causes the following error:
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
...
...
Details:
/home/user/pg/react/myapp/node_modules/react-markdown/index.js:6
export {uriTransformer} from './lib/uri-transformer.js'
^^^^^^
SyntaxError: Unexpected token 'export'
24 | import "prismjs/themes/prism-tomorrow.css";
25 | import { LoremIpsum } from "react-lorem-ipsum";
> 26 | import ReactMarkdown from 'react-markdown';
| ^
27 |
28 | export const Topbar = () => {
29 | return (
at Runtime.createScriptFromCode (../node_modules/jest-runtime/build/index.js:1796:14)
at Object.<anonymous> (dev/test/AppTmp.js:26:1)
Test Suites: 1 failed, 2 passed, 3 total
(note: actually I had more lines as showing above, but what I'm doing is essentially the same, so kindly ignore them)
So this is an SyntaxError: Unexpected token 'export' error. Well, At first I thought I'm going to solve the error on SO or Google. But the error hell continues...
Now I added a different line as the following.
./src/dev/test/AppTmp.js
import React from "react";
// import ReactMarkdown from 'react-markdown';
import Slider from "react-slick"; // <--- added this
export const Topbar = () => {
return (
<>
<p>hoge.</p>
</>
)
}
The above caused an error:
● Test suite failed to run
matchMedia not present, legacy browsers require a polyfill
25 | import { LoremIpsum } from "react-lorem-ipsum";
26 | // import ReactMarkdown from 'react-markdown';
> 27 | import Slider from "react-slick";
| ^
28 | import "slick-carousel/slick/slick.css";
29 | import "slick-carousel/slick/slick-theme.css";
30 | import 'bootstrap';
at new MediaQueryDispatch (../node_modules/enquire.js/src/MediaQueryDispatch.js:15:15)
at Object.<anonymous> (../node_modules/enquire.js/src/index.js:2:18)
at Object.<anonymous> (../node_modules/react-slick/lib/slider.js:50:53)
at Object.<anonymous> (../node_modules/react-slick/lib/index.js:8:38)
at Object.<anonymous> (dev/test/AppTmp.js:27:1)
at Object.<anonymous> (__tests__/hello.js:8:1)
Test Suites: 1 failed, 2 passed, 3 total
This time I got an matchMedia not present, legacy browsers require a polyfill error.
Error hell continues. Next I tried:
./src/dev/test/AppTmp.js
import React from "react";
// import ReactMarkdown from 'react-markdown';
// import Slider from "react-slick";
import { nanoid } from 'nanoid'; // <--- added this
export const Topbar = () => {
return (
<>
<p>hoge.</p>
</>
)
}
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
...
...
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/home/user/pg/react/myapp/node_modules/nanoid/index.browser.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { urlAlphabet } from './url-alphabet/index.js'
^^^^^^
SyntaxError: Cannot use import statement outside a module
49 | // import uniqueId from 'lodash/utility/uniqueId'
50 | import _ from 'lodash'
> 51 | import { nanoid } from 'nanoid';
| ^
52 | import { WithContext as ReactTags } from 'react-tag-input';
53 |
54 | const mymodules = require("./../../mymodules.js")
at Runtime.createScriptFromCode (../node_modules/jest-runtime/build/index.js:1796:14)
at Object.<anonymous> (dev/test/AppTmp.js:51:1)
Test Suites: 1 failed, 2 passed, 3 total
This time, got an error SyntaxError: Cannot use import statement outside a module. What the hell is going on.....
./.babelrc
{
"presets": [
[
"#babel/preset-env",
{
"loose": true,
"modules": false,
"targets": {
"browsers": "last 2 chrome versions"
}
}
],
"#babel/preset-react"
],
"plugins": [
"react-hot-loader/babel",
["#babel/plugin-proposal-class-properties", { "loose": true }]
],
"env": {
"test": {
"presets": [
[
"#babel/preset-env",
{
"loose": true,
"modules": false
}
],
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-transform-runtime",
"#babel/plugin-transform-modules-commonjs"
]
}
}
}
./package.json
"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|less|scss)$": "<rootDir>/__mocks__/styleMock.js"
},
"transform": {
"\\.[jt]sx?$": "babel-jest"
},
"moduleFileExtensions": [
"js",
"jsx",
"tsx"
],
"moduleDirectories": [
"node_modules"
],
"rootDir": "src",
"transformIgnorePatterns": [
"/node_modules/(?![#autofiy/autofiyable|#autofiy/property]).+\\.js$",
"/node_modules/(?![#autofiy/autofiyable|#autofiy/property]).+\\.ts$",
"/node_modules/(?![#autofiy/autofiyable|#autofiy/property]).+\\.tsx$",
"/node_modules/(?!my-package)(.*)",
"/node_modules/(?!#ngrx|(?!deck.gl)|ng-dynamic)"
],
"testEnvironment": "jsdom"
},
So, what's the best thing I can do now?
actually I've been taking 8 hours so far on Jest to get the above-mentioned simple example working, I didn't expect just a testing development environment building is this damn hard way.
I mean I think I'm doing something fundamentally wrong. that's why I'm getting this many errors no? What's not right with this setup, can I ask a help? Thanks.

Jest, Enzyme and Styled Component not working with Warning: React.createElement

I have created a styled components in a sperate file with the same name and .css.jsx for example Abc.jsx have Abc.css.jsx and it's imported to the Abc.jsx to use. But when I try to test Abc.jsx I get the below error from the Enzyme mount,
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, or you might have mixed up default and named imports.
Seems like React can't locate the styles written in my Abc.css.jsx. Does anyone know the reason for this and how to fix this?
Abc.jsx
import * as Styled from './Abc.css';
function Abc() {
return (<Styled.Title>ABC</ Styled.Title>);
}
export default Abc
Abc.css.jsx
import styled from 'styled-components';
export const Title = styled.div`
`;
Abc.test.js
import Abc from '../../../components/Abc';
import { mount } from 'enzyme';
describe("My Abc tests", () => {
let wrapper;
beforeAll(() => {
wrapper = mount(<Abc />);
})
test("check api call", async () => {
})
});
jest.config
module.exports = {
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
setupFilesAfterEnv: ["<rootDir>/setupTests.js"],
moduleNameMapper: {
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
},
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
}
};
I was finally able to get the same error as you! in this codesandbox
So the issue is in the naming of styled-component files. You name them [something].css.jsx.
And in you jest.config file tries to map them as classes or something like that, I assume it is because of the import as it ends with '.css'
...
moduleNameMapper: {
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
},
...
There are a couple of things you can do here.
Change naming convention for styled-components. From[something].css.jsx to [something].styled.jsx.
Remove moduleNameMapper
Remove css from moduleNameMapper
My personal favorite is option 1.

Error running a Jest snapshot test using a custom snapshot serializer - jest-styled-components

I have a react app built with Create-React-app. I am trying to add a unit test to one of the components with an inline snapshot test. Along with the usual suspects, I have styled-components, jest-styled-components and Prettier installed as dev dependencies. I have added 'jest-styled-components' as a snapshotSerializer to my jest config in package.json.
I am getting the following error running the unit test -
PrettyFormatPluginError: plugins[p].test is not a functionTypeError: plugins[p].test is not a function
15 | );
16 |
> 17 | expect(container).toMatchInlineSnapshot();
| ^
18 | });
19 |
20 | test("it renders empty cart message", () => {
at findPlugin (node_modules/pretty-format/build/index.js:343:22)
at prettyFormat (node_modules/pretty-format/build/index.js:523:22)
at Object.toMatchInlineSnapshot (node_modules/expect/build/index.js:342:33)
at Object.<anonymous> (src/components/cart-dropdown/__tests__/cart-dropdown.js:17:21)
I can't figure out what is going wrong. Please help.
// package.json
...
"devDependencies": {
"#testing-library/dom": "^6.11.0",
"#testing-library/jest-dom": "^5.0.0",
"#testing-library/react": "^9.4.0",
"jest-styled-components": "^7.0.0",
"prettier": "^1.19.1"
},
"jest": {
"snapshotSerializers": [
"jest-styled-components"
]
}
// unit test
import React from "react";
import { render } from "#testing-library/react";
import CartDropdown from "../cart-dropdown";
test("it renders", () => {
const mockHistory = jest.fn();
const mockDispatch = jest.fn();
const { container, debug } = render(
<CartDropdown
cartItems={[]}
history={mockHistory}
dispatch={mockDispatch}
/>
);
expect(container).toMatchInlineSnapshot();
});
Removing the snapshotSerializers entry from jest config and adding the jest-styled-components import into the test file resolved this issue.
// unit test
import React from "react";
import { render } from "#testing-library/react";
import CartDropdown from "../cart-dropdown";
//add the below and remove entry for snapshotSerializers in jest config
import 'jest-styled-components'
test("it renders", () => {
const mockHistory = jest.fn();
const mockDispatch = jest.fn();
const { container, debug } = render(
<CartDropdown
cartItems={[]}
history={mockHistory}
dispatch={mockDispatch}
/>
);
expect(container).toMatchInlineSnapshot();
});
Removing the snapshotSerializers entry from jest config (Package.json) error will be gone

Invariant type error when using Jest mount

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 {

Typescript test with Jest with Enzyme does not recognise components

I have a test for Typescript using Jest with Enzyme. Tests work perfect but when i add a component, it gives me a Unterminated regular expression error
import {} from 'jasmine';
import {shallow} from 'enzyme';
import {Show, Hide} from '../components/show_hide';
describe('<Show /> Tests', () => {
it('Show should render once', () => {
const component = shallow(<Show />);
expect(component).toHaveLength(1);
})
})
When I run yarn test the result on the console is
FAIL __tests__/show_hide.ts
● Test suite failed to run
/path/to/repo/__tests__/show_hide.ts: Unterminated regular expression (4:35)
2 | describe('<Show /> Tests', () => {
3 | it('Show should render once', () => {
> 4 | const component = shallow(/>);, expect(component).toHaveLength(1));
| ^
5 | });
6 | });
7 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hvd19oaWRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vX190ZXN0c19fL3Nob3dfaGlkZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBRy9CLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtJQUMxQixFQUFFLENBQUMsbUJBQW1CLEVBQUU7UUFDdkIsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFPLElBQUksRUFDcEMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQSxDQUFDO0lBQ25DLENBQUMsQ0FBQyxDQUFBO0FBQ0gsQ0FBQyxDQUFDLENBQUEifQ==
The jest configuration inside package.json is
"jest": {
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"json"
],
},
Any thoughts on that?
ts files are for pure typescript code, and tsx for react (like jsx).
Rename the file to tsx
It seems that forgetting to import React caused the issue.

Resources