process is undefined in React - reactjs

I am building a simple React app that generates a QR code from data. I am interested in inspecting the memory usage when the QR code is generated. I am using the built process.memoryUsage() function but the app throws and exception
Uncaught TypeError: process__WEBPACK_IMPORTED_MODULE_1__.process is undefined
I have tested some different solution, i tried to rollback the react script version to "4.0.3" i tried to download the npm polyfill webpack but there is no success.
I am currently using these imports
import React, { useState, useEffect } from 'react';
import process from 'process';
import './App.css';
const QRCode = require('qrcode');
The function looks like this
let stringData = JSON.stringify(qrData);
console.log("Number of chars in data" + " " + stringData.length);
QRCode.toDataURL(stringData, function (err, url) {
if(err) return console.log("error occured")
//window.location.href = url;
})
const used = process.memoryUsage();
for (let key in used) {
console.log(`${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
}

process is a Node.js API and is not available in the browser where your React app is running, which is why you see that error. If there is an available global process object, it is being polyfilled by something in your build tools, and will not have the memoryUsage method.
There is no equivalent API for the browser, but some related APIs do exist. Note that this is an evolving space and some are non-standard, so be sure to read both the spec and documentation before considering any usage:
Device Memory API (MDN)
Performance.memory (MDN)

You are using a built in nodejs package in a react app. Node executes on the server and has access to system level resources. React runs in the browser and does not. See this article for some tips measuring performance in React.

Related

How to test custom React-query hook that is based on Firebase methods?

I came across react-query-firebase which are hooks that are built on React-query for firebase.
I also found library called mock service worker https://mswjs.io/ however it is based on REST and GraphQL.
Here is an example code how I would use these hooks:
import React from "react";
import { useFirestoreDocument } from "#react-query-firebase/firestore";
import {
doc
} from "firebase/firestore";
import { firestore } from "../firebase";
function GetUser() {
const id = "pW5CizOJOpXezr5lGGshDmKdVpP3";
const ref = doc(firestore, "users", id);
const user = useFirestoreDocument(["users", id], ref);
return (
<div>
{user.isLoading && <div>Loading...</div>}
{user.data && <div>{user.data.data()?.name}</div>}
</div>
);
}
export default GetUser;
I am new to testing and I have no idea how would I have to execute this test, since I am mocking requests can I use random url anyways or does it have to be firebase related methods?
react-query-firebase library is an abstraction over Firebase that encapsulates resource paths (it's an SDK, I believe). Since the paths (URLs) are abstracted from, you have at least two options for how to mock requests issued by such libraries.
Option 1: Use explicit paths
Although the exact resource paths are hidden away, requests still reference existing absolute paths. You can observe those in the "Network" tab of your browser or by enabling a simple request introspection with msw:
// my.test.js
import { setupServer } from 'msw/node'
const server = setupServer(/* no handlers */)
beforeAll(() => server.listen())
afterAll(() => server.close())
Since we're using setupServer with no handlers, all requests that happen in my.test.js will be printed as warnings to stderr. You can observe those warnings to see what resource paths your SDK requests.
The benefit of using an SDK is that it guarantees you a certain resource path structure. Most likely, you will be able to replicate that structure in your mocks:
// src/mocks.js
import { rest } from 'msw'
export const handlers = [
rest.get('https://some-resource.:checksum.firebase.app/path', (req, res, ctx) => res(ctx.text('hello)))
]
Utilize dynamic path segments like :checksum to match a broader range of paths.
The downside of this approach is that your mock definition becomes dependent on the SDK internal details (resource paths). Any updates to the SDK may break your mocks, since they may update the path structure internally without denoting it as a breaking change (abstracted paths are not public API).
Option 2: Spy on the SDK
Alternatively, you can spy on the SDK you're using. An example of such a spy would be using jest.spyOn on the react-query-firebase directly:
// my.test.js
import * as reactQueryFirebase from 'react-query-firebase'
it('creates a user', () => {
jest.spyOn(reactQueryFirebase, 'SOME_METHOD_NAME')
.mockReturnValue(/* mock */)
})
The downside of this method is that you're stubbing the functions from a third-party library, which means your code under test never calls those functions. This decreases the reliability of such a test, and you should, generally, avoid resorting to this approach.
I do recommend you research Firebase, since major SDK providers often have guidelines on mocking their API. Often such a guidance would include using a dedicated third-party package authored by the SDK provider that allows mocking their internal resources.

ReactJS Jest Puppeteer tests no longer working: ReferenceError: document is not defined

Scenario
npm test used to work without issue. Over the course of a month or so (I neglected tests) something changed and now I receive ReferenceError: document is not defined when trying to run Jest-Puppeteer tests via npm test.
This error shows up even with document removed so it seems like a puppeteer issue but I'm not sure why this is showing up now. I've checked out code from over a month ago and the tests still work but so much has changed that it's difficult to chase down the actually issue.
Attempted Solutions
upgrade node
reinstall npm packages
revert jest-puppeteer.config.js to previous version
add #jest-environment jsdom to tests which fixes the document issue but then causes ReferenceError: page is undefined
Question
How can I troubleshoot this problem short of starting over from scratch? That said, I'm prepared to start over if that's what it's going to take, which sometimes it does.
Code
this is a basic jest file
import "core-js/stable";
import "regenerator-runtime/runtime";
import {Provider} from "react-redux"
import mockState from "./mocks/mockState"
import configureStore from "redux-mock-store"
import ShallowRenderer from 'react-test-renderer/shallow'
import API from '../src/API'
import getNavigationResponse from '../src/nocks/getNavigation'
import expectedNavigationState from "./static/expectedNavigationState"
import pageObjects from "./static/pageObjects"
import utils from './utils'
import constants from '../src/constants'
describe('API tests', () => {
beforeEach(async() => {
await page.goto('http://localhost:3000');
await page.setViewport({ width: 900, height: 600 });
await page.goto('http://localhost:3000/');
await page.evaluate(() => {
document.getElementById('root').classList.add('animated-test');
});
await page.waitForSelector(pageObjects.navFactory);
});
// PASS
test('API data to be in store', async () => {
await page.waitForSelector(pageObjects.primaryNavLink);
// get state from root
const store = await utils.getStore();
expect(store[0].navigation.urlHashMap).toEqual(expectedNavigationState);
});
test.todo('Make sure content==true on vanity urls (home)')
test.todo('Make sure content==false on url items with children (visitor)')
// PASS
test('API cancel should cancel the API request', async () => {
API.dispatch = () => {
};
API.fetch(constants.NAVIGATION_HREF, 'API_FETCH_TYPE_NAVIGATION');
const promiseCanceled = API.cancel('API_FETCH_TYPE_NAVIGATION');
expect(promiseCanceled).hasOwnProperty('promise');
expect(promiseCanceled).hasOwnProperty('cancel');
});
});
** EDIT **
From what I can find out, this "ReferenceError" seems to be a babel error that is caused because babel can't seem to figure out what "document" is. I traced down where the issue is happening and it is within a third party plugin so I left a note on the developer's github page in the mean time. Currently my "solution" is to comment this test out - I'll put more effort into this again when I have time to find a proper solution
** EDIT 2 **
If I add <rootDir>/node_modules/react-json-view/dist/main.js to babel config's transformIgnorePatterns then I get a different error of
ReferenceError: regeneratorRuntime is not defined
Which is odd because I explicitly have import "regenerator-runtime/runtime" at the top. This seems to be a step closer but I'm not sure. I switched back to babel-polyfill (deprecated) just to try it but ended with a different error of TypeError: jest: failed to cache transform results.
Normally you can do something like this answer which is to add:
npm test --env=jsdom
But since I also need Puppeteer's environment there's a clash because node only seems to support ONE environment.
Ultimately I removed the troubled plugin.

React -- getting ".map is not a function" on PRODUCTION build, but not on regular dev build?

I can't seem to debug this... not sure what's wrong.
This is a React front-end communicating using AXIOS to a Java/MySQL backend. Axios is making CRUD requests over localhost to fetch/update data.
When I run NPM START (development - port 3000) for my React application, it runs fine. However, when I run NPM RUN BUILD and then serve the production build (port 5000), I am getting the following error messages in the console:
Uncaught (in promise) TypeError: this.state.reportData.map is not a function
at t.value (TotalsPerCustomer.js:378)
at Oi (react-dom.production.min.js:3785)
at Ni (react-dom.production.min.js:3776)
at Ri (react-dom.production.min.js:3960)
at Va (react-dom.production.min.js:5514)
at Qa (react-dom.production.min.js:5536)
at Ou (react-dom.production.min.js:5958)
at Pu (react-dom.production.min.js:5925)
at ku (react-dom.production.min.js:5860)
at Ja (react-dom.production.min.js:5787)
I faced this ".map is not a function" previously when I wasn't properly using an ARRAY - but I know this isn't causing the issue now since it works fine on development (Port 3000).
I've tried to do some research on why this is occurring but haven't found any clear answers.
I have added "localhost:5000" to the allowed Origins for CORS in Java back end:
package com.example.groupproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#SpringBootApplication
public class GroupProjectApplication {
public static void main(String[] args) {
SpringApplication.run(GroupProjectApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000","http://localhost:3001","http://localhost:5000");
}
};
}
}
I think I need to understand better what is occurring when a production build is created - I know it creates an minified version of the code -- does this mean that if I have functions named the same thing in different React components then it will create an issue?
Do I need to add the axios dependency somewhere in my WebPack folder? Or is there a different dependency or something missing in my WebPack?
See below screenshot of the console:
I don't really know how to begin debugging using these console errors - can someone shed some light on this?
My apologies for being a little clueless on this production build - any help is much appreciated.
Thanks!
This happen to me as well. First I tried to resolve as it is problem with Array and then finally realized that in reality it is not - because front end (port 5000, production build) lost connection with back end (port 8080) when building for production, hence array was empty.
So this is how I resolved it:
created .env file in root of my React project:
REACT_APP_API_URL_PROD=http://xxx.xxx.xxx.xxx:8080
REACT_APP_API_URL_TEST=http://xxx.xxx.xxx.xxx:8080
REACT_APP_API_URL_DEV=http://localhost:8080
and then in requests.js file (code snippet)
import axios from 'axios';
import endpoints from './endpoints';
if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_PROD;
} else if (process.env.NODE_ENV === 'test') {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_TEST;
} else {
axios.defaults.baseURL = process.env.REACT_APP_API_URL_DEV;
}
export const getRequest = async url => axios.get(url);
export const get = (type, params, options = null) => dispatch => {
const fn = endpoints[type];
axios.defaults.headers.common = {'Authorization': `Bearer ${localStorage.getItem('token')}`};
axios.get(fn(params), options)
.then(response => {
dispatch({
type: type,
payload: response.data
});
});
};
Now, why this is late answer for you, might happen to someone in the future to lose few hours trying to resolve this.
After this, static pages were properly served with 'serve -s build' as well as with Apache HTTP server, and I guess it could be served with any other server.
Please read this for further info.
marked as duplicate of this question:
data.map is not a function
In general, when getting ".map is not a function", this means that you aren't giving an array to map. Only array types can be mapped. So if needed, set the initial state as an empty array (then fetch data, set state, etc.). Bear in mind that if you are mapping certain keys into your page, you may need to set the initial empty array with a 'blank' object, with empty or null values for those keys.
Thanks to those who helped answer this question initially.

Testing in Meteor

I am trying to add tests in Meteor. I added my tests in the folder 'imports'. This is the test file:
import { Meteor } from 'meteor/meteor';
import { chai } from 'meteor/practicalmeteor:chai';
if (Meteor.isClient) {
describe('Client Tasks', () => {
describe('methods', () => {
it('can delete owned task', () => {
Meteor.call('getVideoData', function (error, res) {
if (error) console.log('error', error)
console.log('ok', res);
})
});
});
});
}
I tried to call a method and log the result but I get the following error:
There is no route for the path: /
The result from the console log is:
error {"isClientSafe":true,"error":404,"reason":"Method 'getVideoData' not found","message":"Method 'getVideoData' not found [404]","errorType":"Meteor.Error"}
and
ok undefined
I used Meteor for the back end and React for the front end.
Am I missing something in the test file or is it related to something else?
This is the link to the repo github
The immediate problem you are seeing is "Method 'getVideoData' not found". That is because running meteor test will only load the modules you have specifically imported. It does not eagerly load your project as we are used to when serving meteor in local development mode. You've only imported Meteor and chai into this test so the test knows nothing about any methods you've written in other files in your project.
However, that leads to a more fundamental problem in that meteor test does not run a front end and back end anyways, so methods are not testable as a way to retrieve data from the server when testing the front end. Instead, when testing the front end you need to stub/mock the call to Meteor.call('getVideoData') and all you can really do is assert that it's been called and supply your own fake return data, as shown in this example.
Then you would need to write separate backend tests to verify the method (and hopefully the compartmentalized functions it calls) are properly retrieving the correct data.

React Intl: async loading just one specific locale data in a Universal App

I'm making a multi language universal app using React and I'm having a hard time to find out the best way to deal with locale data.
The app is going to be available in 16 languages and the amount of translated messages are quite big, so I can't load all the messages in one big json (as it is used in most react-intl examples) and I can't import those messages in the webpack generated bundle, I just need to load the user language messages on demand.
I was able to do it when the app is just running on the client side, but I also need it to be working on the server side too. I'm using express for server side rendering and webpack for bundling. Could anyone help to find out the best way to deal with this?
I've been working on something like this lately, although I don't have SSR in my project. I found that pairing dynamic import syntax with React's Suspense component seems to achieve the desired result in my case. Your milage may vary since you need SSR as well, but here's a rough overview of what I found to work for me:
// wrap this around your JSX in App.js:
<React.Suspense fallback={<SomeLoadingComponent />}>
<AsyncIntlProvider>
{/* app child components go here */}
</AsyncIntlProvider>
</React.Suspense>
// the rest is in support of this
// can be placed in another file
// simply import AsyncIntlProvider in App.js
const messagesCache = {};
const AsyncIntlProvider = ({ children }) => {
// replace with your app's locale getting logic
// if based on something like useState, should kick off re-render and load new message bundle when locale changes
const locale = getLocale();
const messages = getMessages(locale);
return (
<IntlProvider locale={locale} messages={messages}>
{children}
</IntlProvider>
);
};
function getMessages(locale) {
if (messagesCache[locale]) {
return messagesCache[locale];
}
// Suspense is based on ErrorBoundary
// throwing a promise will cause <SomeLoadingComponent /> to render until the promise resolves
throw loadMessages(locale);
}
async function loadMessages(locale) {
// dynamic import syntax tells webpack to split this module into its own chunk
const messages = await import('./path/to/${locale}.json`);
messagesCache[locale] = messages;
return messages;
}
Webpack should split each locale JSON file into its own chunk. If it doesn't, something is likely transpiling the dynamic import syntax to a different module system (require, etc) before it reaches webpack. For example: if using Typescript, tsconfig needs "module": "esnext" to preserve import() syntax. If using Babel, it may try to do module transpilation too.
The chunk output for a single locale will look something like this:
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
/***/ "./path/to/en-US.json":
/*!*************************************!*\
!*** ./path/to/en-US.json ***!
\*************************************/
/*! exports provided: message.id, default */
/***/ (function(module) {
eval("module.exports = JSON.parse(\"{\\\"message.id\\\":\\\"Localized message text\\\"}\");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvbG9jYWxpemF0aW9uL2VuLVVTLmpzb24uanMiLCJzb3VyY2VzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./path/to/en-US.json\n");
/***/ })
}]);
Hope this helps. Best of luck internationalizing your project! 😁

Resources