CORS error - Error: Cross origin http://localhost forbidden - in ReactJS/Jest test only - reactjs

I'm running into a problem where the request I am making to an outside API is working fine in execution, but when runing a Jest/Enzyme test it gives me a CORS error. The function in question is using a JsonRpc implementation from an API, and using fetch from node-fetch. Not sure if there are settings for CORS I can apply somewhere?
I tried many variations of async waits in Jest/Enzyme testing framework but am still running into issues.
test("it should do something", done => {
const component = shallow(<CustomComponent />)
component.instance().customAsyncFunction( result => {
expect(result.length).toEqual(5)
done()
})
// return component.instance().customAsyncFunction().then(data => {
// expect(data.length).toEqual(5)
// })
})
I tried the above and a few other methods (like setTimeout and awaiting it) and get the CORS error.
The results I'm getting are:
console.error
node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Cross origin http://localhost forbidden
at dispatchError (...\node_modules\jest-environment-jsdom\node_modules\jsdom\lib\jsdom\living\xhr-utils.js:65:19)
at Request.client.on.res (...\node_modules\jest-environment-jsdom\node_modules\jsdom\lib\jsdom\living\xmlhttprequest.js:679:38)
at Request.emit (events.js:198:13)
at Request.onRequestResponse (...\node_modules\request\request.js:1066:10)
at ClientRequest.emit (events.js:203:15)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:556:21)
at HTTPParser.parserOnHeadersComplete (_http_common.js:109:17)
at TLSSocket.socketOnData (_http_client.js:442:20) undefined
Any ideas?

Jest allows you to set a setup script file. This file will be required before everything else and gives you a chance to modify the environment in which the tests will run. This way you can unset XMLHttpRequest before axios is loaded and the adapter type evaluated since imports are hoisted.
Link:https://facebook.github.io/jest/docs/configuration.html#setuptestframeworkscriptfile-string
In package.json
{
...,
"jest": {
...,
"setupTestFrameworkScriptFile": "./__tests__/setup.js",
...
},
...
}
__tests__/setup.js
global.XMLHttpRequest = undefined;

The error happens because the external API you call during the tests has a CORS restriction different than Jest's default jsdom one has (http://localhost).
To fix this for Jest v24 - v27 you have to set the appropriate testURL (see the docs) in your Jest config (e.g. jest.config.js):
{
// Other config values here ...
"testURL": "http://localhost:8080"
}
In testURL you have to put the actual URL allowed by CORS at your remote API side.
NB: since v28 the option is organized differentlty that requires different update in Jest config.

Assuming you actually want to call the real API during your tests rather than just mock it, you'll need to make sure the server sends an appropriate "access-control-allow-origin" header (obviously the exact mechanism for doing this depends on your server platform)

1) what you're probably looking for is to instead mock the promise or whatever function is being ran using jest.mock(), then assert that that mock was called (with the correct params)
Jest tests are unit tests that shouldn't really talk to your API
2) most likely something with your env vars while in test mode, process.env.NODE_ENV is set to "test" during jest which might be changing something or maybe one of your own custom config env vars

By settting a testURL option which is a valid URL you want in jest config will resovle this problem.
https://jestjs.io/docs/configuration#testurl-string

Related

The current testing environment is not configured to support act(...) - #testing-library/react

I'm trying to upgrade my project to React 18, everything works in dev and production mode in the browser. But after upgrading to the latest version of #testing-library/react some of my unit tests are failing and a lot of them are logging the following warning:
console.error
Warning: The current testing environment is not configured to support act(...)
at printWarning (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:86:30)
at error (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:60:7)
at isConcurrentActEnvironment (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:25057:7)
at warnIfUpdatesNotWrappedWithActDEV (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:27351:12)
at scheduleUpdateOnFiber (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:25292:5)
at setLoading (node_modules/.pnpm/react-dom#18.0.0_react#18.0.0/node_modules/react-dom/cjs/react-dom.development.js:17342:16)
at _callee2$ (node_modules/.pnpm/#cubejs-client+react#0.29.51_react#18.0.0/node_modules/#cubejs-client/react/src/hooks/cube-query.js:56:7)
First thing I did was check my versions, cleared node modules and lock file just in case:
react 18.0.0
react-dom 18.0.0
#testing-library/react version: "13.1.1",
Testing Framework and version: "jest": "27.5.1",
DOM Environment: jsdom 16.7.0
But everything looks right?
I checked the migration docs for React 18: https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html
Which says the latest version of #testing-library/react shouldn't require the globalThis.IS_REACT_ACT_ENVIRONMENT = true setting.
But I tried setting that manually anyway before my tests run. But that didn't fix it either, (I tried several versions)
// #ts-ignore
global.IS_REACT_ACT_ENVIRONMENT = true
// #ts-ignore
globalThis.IS_REACT_ACT_ENVIRONMENT = true
// #ts-ignore
self.IS_REACT_ACT_ENVIRONMENT = true
// #ts-ignore
window.IS_REACT_ACT_ENVIRONMENT = true
// #ts-ignore
this.IS_REACT_ACT_ENVIRONMENT = true
None of those fixes the Warning or the unit tests.
I'm using jest v. 27.x with jsdom which I imagine would be the most common configuration? So I'm quite surprised to be running into this error?
Here is my jest.config
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
transform: {
'^.+\\.(t|j)sx?$': ['ts-jest'],
},
setupFilesAfterEnv: ['./src/setupTests.tsx'],
modulePathIgnorePatterns: ['src/common/config.ts'],
coverageReporters: ['text', 'json'],
}
Any ideas why a relatively simple setup like this, would be running into this warning with RTL v. 13.1.1?
In my case this warning was appearing because I had accidentally imported act from react-dom/test-utils instead of #testing-library/react. Fixing the import made the warning disappear.
In my case this happened because I had a useless act that I implemented as a workaround in v12.
await act(async () => {
const hours = await screen.findByText('-6h')
expect(hours).toBeInTheDocument()
})
I removed the useless act around my assertion in this test, and the warning about the "environment not configured to support act" was resolved.
In my case, this particular test was failing after upgrading to v13, which is how I ended up trying to clean it up.
The warning message was essentially not helpful in debugging this.
I didn't find the reason why the global flag was not working for me, so the following monkey patch resolved the log lines for me
const originalConsoleError = console.error;
console.error = (...args) => {
const firstArg = args[0];
if (
typeof args[0] === 'string' &&
(args[0].startsWith(
"Warning: It looks like you're using the wrong act()"
) ||
firstArg.startsWith(
'Warning: The current testing environment is not configured to support act'
) ||
firstArg.startsWith('Warning: You seem to have overlapping act() calls'))
) {
return;
}
originalConsoleError.apply(console, args);
};
Yes, it's super ugly and likely not the best solution to the problem, but then again React does something pretty similar in their codebase.
It can also happen if the tested code has a timeout that executes a callback after the test has finished. For instance with a throttle on a user input.
It can be avoided by either using the done callback provided by jest or to make the timers to finish instantly with the timer mocks.

PrintJS getting blocked a frame with origin issue

Hi My Main Application url is http:localhost:4000. It internally render iframe app which is http:localhost:4000/contentApp/index.html (with sandbox parameter as sandbox="allow-scripts allow-popups allow-modals allow-forms allowdownloads allow-same-origin") and its in React application.
PrintJS package, using 1.0 version and it makes call to printJS(URL)
//URL, blob:http:localhost:4000/[guid value]
It gets an error at below piece of code within printjs library.
print.js:
try{
iframeElement.focus(); // iframeElement = iframe#printJS { src: blob:http://localhost:4000/a33334343-33434-343434-343434adf', src: '', name: '', sandbox: DOMTockenList(0..)
...
// other browsers
iframeElement.contentWindow.print(); // throw CORS error at here.
} catch(error){ params.onError(error);}
finally {
(o,_function.cleanup)(params);
}
}
above, iframeElement.contentWindow.print() getting an error out with below error CORS:
Uncaught DOMException: Blocked a frame with origin "http://localhost:4000" frame accessing a cross-origin frame.
at performPrint (webpack-internal:///./node_modules/print-js/dist/print.js:898:35)
at HTMLIframeElement.iframeElement.onload (webpack-internal:///./node_modules/print-js/dist/print.js:852:11)
..
When I remove sandbox then it worked. However, I can not remove sandbox as its structure of application.
Is there any way to fix this CORS issue. Like adding some parameter in "iframe sandbox attribute" OR any option at 'printjs' to fix this issue ?
Appreciate for the help.
PrintJS, internally call iframeElement.contentWindow.print(); , I don't have control to do postMessage as its printJS package part. Though, I have control over localhost:4000/contentApp , sandbox attribute.
(Also, it looks like issue created at, "http://localhost:4000" != "BLOB:http://localhost:4000/GUIDvalue" , (which looks weird as, both are pointing to same origin".)

TypeError: Cannot read property 'twoArgumentPooler' of undefined

Recently we have upgraded the react-native-web package to latest version 0.17.0 From that time we are getting the issue TypeError: Cannot read property 'twoArgumentPooler' of undefined while running yarn test
To analyse this issue, gone through the code which is implemented by our developers but we didn't have anything like twoArgumentPooler but it's available in react-native-web package in the path
at Object.<anonymous> (node_modules/react-native-web/dist/cjs/exports/Touchable/BoundingDimensions.js:19:46)
How to resolve this issue
Can you show your jest config file? I had a similar issue and it turned out that I was (manually) setting up the moduleNameMapper incorrectly. I had the following:
moduleNameMapper: {
'react-native': 'react-native-web',
},
which, upon running the tests, effectively invalidated an import on line 10 inside react-native-web/dist/exports/Touchable/BoundingDimensions.js (the file mentioned in your stacktrace) and surely a lot of other imports.
This
import PooledClass from '../../vendor/react-native/PooledClass';
var twoArgumentPooler = PooledClass.twoArgumentPooler;
turned into this (notice the changed and incorrect path)
import PooledClass from '../../vendor/react-native-web/PooledClass';
var twoArgumentPooler = PooledClass.twoArgumentPooler;
This ultimately resulted in the exact same error as you got, and was resolved by correctly defining the remapper entry like this:
moduleNameMapper: {
'^react-native$': 'react-native-web',
},
Hope it helps! If nothing else, perhaps this will help someone in the future!

Reading in config data throws error in jest unit test

I'm using react in conjunction Jest and enzyme. My unit tests were working as desired until I added a config.json that lives in src/config/config.js and it appears like so:
{
"appName": "Mystery",
"clients": {
"api1": "http://localhost:8082",
"api2": "http://localhost:8083",
"api3": "http://localhost:8084"
},
}
I import this file in my client folder that I use for network requests in this manner:
import CONFIG from '../../config/config.json';
const api = new Client(CONFIG.clients.api1);
Now when I run npm test I get this error on all my files that use that specified api:
TypeError: Cannot read property 'api1' of undefined
After some google foo.... I'm stymied. Any assistance would be greatly appreciated. Please let me know if additional details are required.

Angular2 http.get(url) is returning 404 on a valid url - not a CORS issue

I have an Angular2 App running that is attempting to make a call to my Django server.
I have a function called getObjects That makes the external API call and should return a list of objects. As a bit of debugging I am currently making a XMLHttpRequest, which correctly grabs the data from my server.
However, whenever I attempt to make a request using Http.http.get(url) I see a 404 error. I've tried fiddling with a few of the HTTP headers, as well as playing around with some settings on my server, but I cannot figure out what is wrong.
I assume that the Http.http.get() method is doing something funky behind the scenes that I am unaware of. The odd thing is that my browser dev-network tab doesn't even show any attempt to reach my external browser.
Any help in the matter would be much appreciated, I can provide any additional debug information and could really use a point in the right direction.
ng --version
angular-cli: 1.0.0-beta.24
node: 6.9.1
os: win32 x64
#angular/common: 2.4.3
#angular/compiler: 2.4.3
#angular/core: 2.4.3
#angular/forms: 2.4.3
#angular/http: 2.4.3
#angular/platform-browser: 2.4.3
#angular/platform-browser-dynamic: 2.4.3
#angular/router: 3.4.3
#angular/compiler-cli: 2.4.3
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
...
constructor(private http: Http) { }
getObjects(): Promise<Object[]> {
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
var x = httpGet(this.myUrl);
console.log(x); // This works perfectly and I see an entry on my server log
this.http.get(this.myUrl)
.subscribe(res => console.log(res));// This throws a 404 and I see no entry on my server logs nor in my browser network tab
var headers = new Headers({'content-type': 'application/json'});
this.http.get(this.myUrl, {headers: headers})
.subscribe(res => console.log(res));// This throws a 404 and I see no entry on my server logs nor in my browser network tab
return this.http.get(this.myUrl)
.toPromise()
.then(response => response.json().data as Object[])
.catch(this.handleError); //The original code that worked on an internal in-memory-api
}
I was able to find a working fix in another stack overflow question:
Angular 2 HTTP GET returning URL null
The problem was with the InMemoryWebApiModule and the solution was to make the following config modification to my app.module.ts file:
- InMemoryWebApiModule.forRoot(InMemoryDataService),
+ InMemoryWebApiModule.forRoot(InMemoryDataService, {passThruUnknownUrl: true}),
Making this small config change caused the application to work.
In fact there is no 404, because you are not executing your requests. You need to subscribe() to them, to execute them. Few examples:
this.http.get(this.myUrl).subscribe(res => console.log(res));
this.http.get(this.myUrl).subscribe();
let response: Observable<Response> = this.http.get(this.myUrl);
response.subscribe();
response.subscribe(v => console.log(v);
You can read about observables here:
http://reactivex.io/rxjs/manual/index.html
This can be an issue with angular2-in-memory-web-api. I had the same issue, but when I removed the InMemoryWebApiModule from the AppModule, the API calls worked perfectly.

Resources