React testing through jest gives an unexpected error - reactjs

I'm using JEST to test my react app.
I get the error and some text as in the image below.
Also, the code for my test case(named: TodoApp.test.jsx) is as :
it("should add todo ...", () => {
// const text = "Suzal is trying react";
// I commented out the other lines because the test
// only gave error when this line was included.
const todoApp = TestUtils.renderIntoDocument(<TodoApp />);
// todoApp.state = {
// todos: []
// }
// todoApp.handleAddTodo(text);
// expect(todoApp.state.todos[0].text).toBe(text);
});
If extra code/description is needed then please do ask. The complete file is on Github : TodoApp.test.jsx
Links that I already have gone through
https://github.com/facebook/react/issues/11098
https://github.com/facebook/jest/issues/4597

I cloned your repo and started commenting things out and found that there seems to be something going on with TodoApi.getTodos() on line 15 of TodoApp.jsx in the constructor when setting your initial state. If you remove the call to TodoApi.getTodos and replace with with an empty array the test errors disappear. You may need to create a mock function for TodoApi.getTodos to get your tests to pass.
https://facebook.github.io/jest/docs/en/mock-functions.html

Related

React class component setting state, getting parsing error for the "=" sign

I am using create-react-app (unejected) with this code:
class App extends Component {
state = {
path: 'some_string',
organization: null,
errors: null
}
componentDidMount() {
this.onFetchFromGitHub(this.state.path);
};
...
The code (the application) works as expected.
However I am getting an error in vscode:
Parsing error: unexpected token = eslint [134,9]
That is the "=" in:
state = {`
/|\
|
which is highlight in vscode.
My understanding is that I can use this format instead of a constructor with bindings.
As I said the app is working despite the error.
.eslintrc.yml
Which version of React are you using?
React introduced "hooks" in 16.8, and they largely replace the old "Component" class format.
See the introduction here: https://reactjs.org/docs/hooks-intro.html
Using hooks, your example above can be simplified to a function component:
const App = (props) => {
// This replaces the this.state/this.setState from a component
const [state, setState] = React.useState({
path: 'some_string',
organization: null,
errors: null
});
// This replaces the on mount
React.useEffect(() => {
onFetchFromGitHub(state.path);
}, []);
return ...
}
As for why your example does not work, I would suggest it is likely due to configuration of your IDE syntax highlighting. Check whether you have the right syntax plugins installed/active (es2015, react, etc.) and if your linter (if you have one) has the correct plugins and presets. Your code works fine in my IDE, with no errors.
I fixed this by installing eslint. This gave a problem due to conflict with create-react-app so I had to pin package.json version of eslint to 6.6.0 and then delete package-lock.json and remove node_modules/ and then I got about 30 warnings (instead of one).
Finally I changed the source code to fix the unnecessary parens and ignore propType errors and finally I am error free.

Cypress test fails to run when importing from source code of CRA+TS app

One of my Cypress tests fails to run when it tries to import from a file in the source code of a create-react-app src directory.
The test looks like:
// cypress/integration/this-fails.js
import { MY_CONSTANT } from '../../src/constants';
describe('Cypress', () => {
...
})
The imported source file looks like:
// src/constants.ts
export const MY_CONSTANT = 'foo';
The Cypress test failure is caused by a Jest test file in the source directory:
ERROR in /my-app/src/App.test.tsx(5,1)
Cannot find name 'test'. Do you need to install type definitions for a test runner? Try`npm i #types/jest`or`npm i #types/mocha`.
The Jest type definitions are installed. Additionally, to no avail, I have tried to exclude the problematic Jest test in the Cypress tsconfig.
// cypress/tsconfig.json
{
...
"exclude": [
"../src/App.test.tsx"
],
...
}
Here is a minimal repo that reproduces my problem.
Lastly, to clarify why I am importing things into Cypress tests from the source directory — the imported variable is intended to be a DOM selector or a function that returns a DOM selector so that selectors are not hardcoded in the tests.
I'm not sure why the message is TypeScript emitted no output for /my-app/src/constants.ts, this seems to indicate that the file is readable and typescript attempts to parse it, and does not recognize the syntax.
However my guess is that the code of the test is running in a browser process and can't access files outside of it's folder.
If constant.ts is in cypress/fixtures it works, so one easy way is to add a script to copy the file. A script called "precypress" will be automatically run when the "cypress" script is invoked.
This is kind of 90% there - you don't get hot-module reload when constants.ts changes.
package.json
"scripts": {
...
"precypress": "copyfiles ./src/constants.ts ./cypress/fixtures",
"cypress": "cypress open"
},
It also works with functions and handles typing,
test
import { MY_CONSTANT, getMyConstant } from '../fixtures/src/constants';
describe('Cypress', () => {
it('is working', () => {
cy.visit('/')
alert(MY_CONSTANT);
alert(getMyConstant());
expect(true).to.equal(true)
})
})
constant.ts
export const MY_CONSTANT: Number = 10;
export const getMyConstant: Function = () => 20;

Jest Testing Electron/React Component using window.require

I'm currently creating an Electron application that uses React to create the interface. In order to get access the fs, I have been using:
const fs = window.require('fs');
Which works fine when in an Electron window.
The issue is that when I write jest tests for any components that use the window.require('fs'), I get the following error when running the test.
TypeError: window.require is not a function
I have looked through the documentation for Jest and it seems the solution is to generate a mock of window using a manual mock (see "Mocking methods which are not implemented in JSDOM" at https://jestjs.io/docs/en/manual-mocks). However, when I tried to mock window.require by adding at the top of my test file
window.require = jest.fn();
I still get the same TypeError.
I'm very new to create Jest mocks so any help with this would be much appreciated.
My current test file (Component.test.js) looks like
window.require = jest.fn();
import React from 'react';
import renderer from 'react-test-renderer';
import Component from '../index';
describe('Testing', () => {
it('Component renders correctly', () => {
const component = renderer.create(<Component />);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
Add this line at the beginning of your test (or in a setupFilesAfterEnv setup file):
window.require = require;
Details
electron supplies window.require but it isn't defined when running unit tests with Jest.
By default Jest provides a browser-like environment using jsdom that includes a window object.
The above line mocks window.require by setting it equal to the current value of require.
I once faced this issue and below was what solved it for me:
I had to leverage on the module react-app-rewired. this module Tweaks the webpack config(s), even for those using create-react-app(CRA) without using 'eject' and without creating a fork of the react-scripts.
all you need is to add a config-overrides.js file in the root of your project, and populate it with the snippet below:
module.exports = function override (config) {
config.target = 'electron-renderer'
return config;
}
then you proceed to your package.json and replace your start script with
"start": "react-app-rewired start" . and you are done. you can thereafter rebuild and run your test script without getting the window.require is not a function error.
I hope I have been able to help.
cheers!

How to use react-native-i18n in detox[react-native]

I want to test the alert message in detox,and the message use i18n.
const i18n = require("react-native-i18n");
describe("Example", () => {
beforeEach(async () => {
await device.reloadReactNative();
});
it("should show hello screen after tap", async () => {
await element(by.id("btnLogin")).tap();
I18n.t(LocaleKeys.errorMsg_invalidUsername);
await expect(element(by.text(I18n.t(LocaleKeys.errorMsg_invalidUsername)))).toBeVisible();
// await expect(element(by.text("Please input the email and password."))).toBeVisible();
});
});
Run test and get the following error.
Test suite failed to run
/Users/leogeng/Desktop/studentREP/student-app/node_modules/react-native-i18n/index.js:14
export const getLanguages = () => RNI18n.getLanguages();
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (../node_modules/jest-runtime/build/script_transformer.js:305:17)
at Object.<anonymous> (firstTest.spec.js:1:114)
at Generator.next (<anonymous>)
Then I add the following code for jest:
{
"preset": "react-native",
"transformIgnorePatterns": [
"/node_modules/(?!(react-native(.*)?/|native-base(.*)?/|react-navigation/))"
]
}
and get error again:
Validation Error:
Module <rootDir>/node_modules/react-native/jest/setup.js in the setupFiles option was not found.
Actually i confirm 'setup,js' exist in node_modules/react-native/jest.
I do not know why the error happens, anybody can help me?
Thanks
Most likely it's because you're using an old version of node, try to update and see if it solves the issue. Also, it's completely unrelated to Jest and you should probably revert your attempts to modify Jest settings if you don't have any issues with Jest unit tests; in anyway, it will not fix the detox issues.
In case you have some requirement or reason which forces you to keep node at a specific old version, you can bypass it by performing the test differently: have a demo screen only for the e2e tests (or even create a whole demo project just for e2e), in the demo screen you can have a button which performs what you need with i18n (changing locale or whatever), and in the detox test you tap this "demo" button before testing what you actually want.
I've had the same problem. I resolve it by importing i18n-js instead of react-native-i18n.
Because react-native-i18n is not a plain javascript framework, Detox can't import it.
But react-native-i18n is using i18n-js, so you can access your translations without any problem
const I18n = require('i18n-js')
// and then you can use it for your tests
...
await element(by.text( I18n.t('hello') )).tap()

React Mocha rendering, DOMException Wrong Document

Using React 13.2 and looking to test lifecyles with a setup like the one shown on this gist. If I don't stop subsequent renders (via the shouldComponentUpdate method) then anything causes a render (after the initial) explodes with a DOMException Wrong Document:
DOMException: Wrong document
at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level1\core.js:583:13)
at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level2\events.js:326:32)
at insertChildAt (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOperations.js:34:14)
at Object.DOMChildrenOperations.processUpdates (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOpertions.js:106:11)
JSDOM bails because the parent node is not a document and it don't share the same owner document as the child being inserted. Yeah. How could the owning document be anything other than that the global unless React is doing something funky under the hood.
Just surprised that I don't see more people having a similar problem? There is nothing odd-ball with my Mocha setup nor the JSX components being rendered. Plus the initial render goes fine.
Update for node 4
With node 4 we can use the latest jsdom and solve this issue in a better way, e.g. using testdom.
This is how I test a React 0.13 component with mocha on node 4:
import testDom from "testdom";
import { expect } from "chai";
testDom("<html><body></body></html>");
const React = require("react/addons");
const MyTestableComponent = require("../src/MyTestableComponent");
const ExecutionEnvironment = require("react/lib/ExecutionEnvironment");
ExecutionEnvironment.canUseDOM = true;
describe("MyTestableComponent", () => {
it("works!", () => {
const component = <MyTestableComponent />;
expect(true).to.equal(true);
})
})
Note that we should require rather than import React and the component.
Previous answer
I could fix this issue by following the OP's own comment to the question.
Since React stores the document in an internal variable when it is required, we need to remove React from the require.cache object, before requiring it again:
var jsdom = require("jsdom").jsdom;
var React, TestUtils;
describe("Example", function() {
beforeEach(function() {
// remove react from the require cache
for (var key in require.cache) {
if (key.match(/\/node_modules\/react\//)) {
delete require.cache[key];
}
}
// init the DOM
global.document = jsdom("<html><head><script></script></head><body></body></html>");
global.window = document.parentWindow;
// require react again
React = require("react/addons");
TestUtils = React.addons.TestUtils;
});
// my tests...
});

Resources