setup localStorage for testing React app with jest - reactjs

I have created an empty application with create-react-app. it provides a test script at pckage.json and a sample App.test.js. at the first step, I want to set up the test environment according to the documentation of create-react-app. in my app I will use localStorage.
let's say an action like below to be tested
export const cancel = () => {
localStorage.removeItem("MyAppData");
return { type: types.USER_CANCEL};
};
besides the enzyme part, it shows how to initialize localStorage. so I ended up with a setupTests.js file like
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
// react-testing-library renders your components to document.body,
// this will ensure they're removed after each test.
import "react-testing-library/cleanup-after-each";
// this adds jest-dom's custom assertions
import "jest-dom/extend-expect";
configure({ adapter: new Adapter() });
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
here if I do not import jest from jest or jest-dom or jest-enzyme, ESLinter shows an error in jest.fn() that jest is not defined. when I import and run yarn test I get
$ react-scripts test --env=jsdom
FAIL src\App.test.js
● Test suite failed to run
TypeError: _jest2.default.fn is not a function
at Object.<anonymous> (src/setupTests.js:15:27)
at <anonymous>
I really dont get from QAs here and in other forums how should I setup localStorage for testing.

You should not need to import jest into your test files.
You should instead tell eslint what Environment it should expect in the file so it knows what globals are present.
Add this to the top of any files where you use jest globals
/* eslint-env jest */

I really do not know what exactly happened, some packages related to jest, jet-dom, jest-enzyme was mkaing a conflict. but I managed to make it work after deleting package-lock.json, yarn.lock, node_modules, removing jest from the dependencies in package.json, then doing npm install and yarn install!

Related

React + Jest Testing Error - ReferenceError: expect is not defined

I have literally trawled everywhere for an answer to this and possibly tried 99% of things out there so i decided to start a thread of its own so others can run their eyes over what i have currently and see if they can spot the issue.
i am very new to Jest testing and decided to try implement it onto our code base. i used this guide to make sure everything i done was perfect but still this error occurs
A Practical Guide To Testing React Applications With Jest
I am testing this aginst a simple functional component which uses react-hook-form to produce a form on the page and then sends the completed form to our backend via a redux call
I have setup the setupTests.js file as:
import '#testing-library/jest-dom'
import { configure } from "enzyme"
import Adapter from "enzyme-adapter-react-16";
import '#testing-library/jest-dom/extend-expect';
configure({ adapter: new Adapter() });
Updated my package.json test command to
"test": "react-scripts test --env=jsdom --setupFiles ./src/setupTests.js"
Here is the test spec im trying to run with a simple test:
import React from 'react';
import { render as rtlRender, screen } from '#testing-library/react';
import { Provider } from 'react-redux';
import store from '../../../store';
import AddNewProperty from './AddNewProperty';
configure({ adapter: new Adapter() });
const render = component => rtlRender(
<Provider store={store()}>
{component}
</Provider>
)
describe('Add New Property', () => {
test('component redners successfully', () => {
render(<AddNewProperty />)
// expect(screen.getByText('Apartment Number')).toBeInTheDocument();
})
});
here is the error returned on the screen for me:
FAIL src/components/Forms/Agency/AddNewProperty.spec.js
● Test suite failed to run
ReferenceError: expect is not defined
3 | import Adapter from "enzyme-adapter-react-16";
4 | import '#testing-library/jest-dom/extend-expect';
> 5 | configure({ adapter: new Adapter() });
| ^
at Object.<anonymous> (node_modules/#testing-library/jest-dom/dist/extend-expect.js:9:1)
at Object.<anonymous> (node_modules/#testing-library/jest-dom/dist/index.js:3:1)
at Object.<anonymous> (src/setupTests.js:5:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.167s
Ran all test suites related to changed files.
Watch Usage: Press w to show more.
I have all the packages installed in with the latest versions also
You would want to set up the files after the test framework has been installed
Here are a couple of ways you can go about doing it (For this particular question, method 1 is more relevant)
1) react-scripts
Replace/Add --setupFilesAfterEnv instead of using --setupFiles
Example: "test": "react-scripts test --setupFilesAfterEnv <test setup filepath>
2) jest.config.js
setupFilesAfterEnv: [
'./setupTests.js',
],
Along with that make sure your node version is at least 12

ECMAScript module error when running react-scripts test

I am having trouble getting my test runner to run properly within my React/Typescript application. When I try and run it, I get the following error:
Watch Usage
› Press a to run all tests.
FAIL src/components/InvestmentStyleSlider/index.test.tsx
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
D:\projects\cult-wines-repos\CultWines.Onboarding.Ui\node_modules\react-bootstrap\esm\Button.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import _extends from "#babel/runtime/helpers/esm/extends";
^^^^^^
SyntaxError: Cannot use import statement outside a module
1 | import React from 'react';
FAIL src/components/InvestmentStyleSlider/index.test.tsx
I am a tad confused as I have another application that is built in the same way and this has no issues whatsoever.I have tried amending the jest config to the following in my package.json but no matter what I do it still spits out the same error
"version": "0.1.0",
"private": true,
"jest": {
"testEnvironment": "jest-environment-node",
"transform": {}
},
"dependencies": {
Has anyone had a similar error before or can advise as to what is happening here? Again, I am using the react-scripts version of jest which I presumed has ecmascript module support out of the box.
Here is my setupTest.js file in case that gives further clues:
import '#testing-library/jest-dom/extend-expect';
import 'jest-styled-components';
import { configure } from 'enzyme';
import Adapter from '#wojtekmaj/enzyme-adapter-react-17';
import { createSerializer } from 'enzyme-to-json';
configure({ adapter: new Adapter() });
expect.addSnapshotSerializer(createSerializer({ mode: 'deep' }));
And the very simple test file that fails:
/* eslint-disable #typescript-eslint/no-unused-vars */
import React from 'react';
import { render } from 'enzyme';
import InvestmentStyleSlider from './index';
describe('Investment Style Slider', () => {
it('renders correctly', () => {
const rendering = render(<InvestmentStyleSlider />);
expect(rendering).toMatchSnapshot();
});
});
Thanks

Jest + React Testing Library: waitFor is not working

I am writing unit tests for my React JS application using Jest and React testing library. I am trying to test the async functions. But it is not working.
This is my test
import React from 'react';
import "regenerator-runtime/runtime"
import {render, waitFor, fireEvent, screen} from '#testing-library/react';
import {DonorSelect} from "../../src/components";
import MockAdapter from "axios-mock-adapter";
import Axios from 'axios';
import vars from "../configVars";
import {searchUsersResponse} from "../mock/apiResponse";
import { act } from "react-dom/test-utils"
test ("DonorSelect Component", async () => {
let selectedUser = null;
let users = [ ];
let inputValue=""
//mock the users api endpoint
let mock = new MockAdapter(Axios);
mock.onGet(`${vars.baseApEndpoint}/users?keyword=client`)
.reply(200, searchUsersResponse)
await act(async() => await render(
<DonorSelect
id={"user_select"}
onSelect={(user, displayText) => {
selectedUser = { ...user }
}}
onInputChange={(textFieldValue) => {
inputValue = textFieldValue;
}}
onUsersFetched={(userItems) => {
users = [ ...userItems ]
}}
onChange={(name, value) => {
}}
label={"Search User"}
placeholder={"Please, select a user."}
name={"user"}
value={selectedUser!=null? selectedUser.id:""}
inputValue={inputValue}
/>
))
//assert that input is rendered
expect(screen.getByTestId("user_select_input")).toBeTruthy()
fireEvent.change(screen.getByTestId("user_select_input"), {
target: { value: "client" }
})
fireEvent.focus(screen.getByTestId("user_select_input"))
await waitFor(() => {
//assert that if the label is rendered
expect(screen.getByTestId("user_select_label")).toBeTruthy()
// assert that input is rendered
expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()
})
})
As you can see in the test what is not working is the last expect()
expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()
It is always failing. What that component is doing is that, when the input value changes and focus on the input, it will make the api request and render the items. The component is working as expected. I have fully tested it. But it is just not working in the test. What is wrong with my code and how can I fix it?
The default waitFor timeout time is 1000ms.
If you are calling a real endpoint without mocking (mocking is recommended, for example using msw), this might take more than 1 second to execute.
This will result in the timeout being exceeded and the waitFor throws an error.
IF you do not want to mock the endpoint, intercept it and return a test value, which should be under 1 sec, you could also extend the timeout time ti wait for the real api call to be executed and resolved:
await waitFor(() => {
//assert that if the label is rendered
expect(screen.getByTestId("user_select_label")).toBeTruthy()
// assert that input is rendered
expect(screen.getByTestId("user_select_user_item_0")).toBeTruthy()
}
,{timeout: 4000}) // this will now wait 4 secs for the execution, but you should see what works for you.
Based on the information here:
Testing: waitFor is not a function #8855 link
The Solution that works for me is update the library to new version:
This module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:
npm install --save-dev #testing-library/react
or
for installation via yarn
yarn add --dev #testing-library/react
This library has peerDependencies listings for react and react-dom.
React Testing Library versions 13+ require React v18. If your project uses an older version of React, be sure to install version 12:
npm install --save-dev #testing-library/react#12
yarn add --dev #testing-library/react#12
For more information

Jest Your test suite must contain at least one test

I have a simple test file in ./pages/test.js
import React from 'react'
export default function HomePage () {
return (
<main>
<h1>Testing Next.js With Jest and React Testing Library</h1>
</main>
)
}
In ./test/pages/index.test.js I made the following simple test to check if my page is rendering properly and if it has a heading
import React from 'react'
// Using render and screen from test-utils.js instead of
// #testing-library/react
import { render, screen } from '../test-utils'
import HomePage from '../../pages/test'
describe('HomePage', () => {
it('should render the heading', () => {
render(<HomePage />)
const heading = screen.getByText('Testing Next.js With Jest and React Testing Library')
// we can only use toBeInTheDocument because it was imported
// in the jest.setup.js and configured in jest.config.js
expect(heading).toBeInTheDocument()
})
})
After running the test, I get the following error
FAIL pages/test.js
● Test suite failed to run
Your test suite must contain at least one test.
at onResult (node_modules/#jest/core/build/TestScheduler.js:175:18)
at node_modules/#jest/core/build/TestScheduler.js:304:17
at node_modules/emittery/index.js:260:13
at Array.map (<anonymous>)
at Emittery.Typed.emit (node_modules/emittery/index.js:258:23)
PASS test/pages/index.test.js
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 passed, 1 total
Why does jest say I am missing a test?
Why does jest say I am missing a test?
Because Jest thinks pages/test.js is a test file. Jest uses the following regex to detect test files.
(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$
From the docs,
By default it looks for .js, .jsx, .ts and .tsx files inside of __tests__ folders, as well as any files with a suffix of .test or .spec (e.g. Component.test.js or Component.spec.js). It will also find files called test.js or spec.js.
A simple solution would be to rename the file.

Enzyme / Jest Error testing component render in React (TS)

I've been having an odd issue with Jest/Enzyme testing on my react typescript app. For some reason it gives a syntax error even though this is following the official documentation, as well as input from several articles.
The Code:
import React from 'react';
import NavbarTop from "../components/navbar";
import { shallow } from 'enzyme';
describe('NavbarTop', () => {
it('renders correctly', () => {
const wrapper = shallow(<NavbarTop />);
expect(wrapper).toMatchSnapshot();
// On the first run of this test, Jest will generate a snapshot file automatically.
});
});
The folder structure. I have a named class and then an index with a default export.
The error log.
Do you have JSX configured for Jest? Looks like you don't have support for JSX in Jest, which probably means this is a configuration issue. Have a look at configuring babel to support JSX in Jest.
Make sure you read this tutorial

Resources