I have a working nextjs app and am wanting to add Cypress component tests for my react components.
e2e cypress tests are working without issue, but when trying to implement component tests I'm receiving the error, "Cannot read properties of undefined (reading 'displayName')" when trying to mount a component.
I followed the documentation at https://docs.cypress.io/guides/component-testing/component-framework-configuration#Next-jsn and also accepted the configuration that was generated by the cypress tool when I ran yarn cypress.
My code with component testing issue is at https://gitlab.com/kennyrbr/activ/-/tree/cypress-testing/web
Here is where I'm attempting to mount .
import React from 'react';
import { mount } from '#cypress/react';
import { NavBar } from '../../components/NavBar';
describe('NavBar.cy.ts', () => {
it('playground', () => {
cy.mount(`<NavBar />`);
});
});
My package.json is
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"gen": "graphql-codegen --config codegen.yml",
"cypress": "cypress open"
},
"dependencies": {
"#graphql-codegen/typescript-urql": "^3.6.1",
"#urql/exchange-graphcache": "^4.4.3",
"daisyui": "^2.22.0",
"formik": "^2.2.9",
"graphql": "^16.5.0",
"next": "latest",
"next-urql": "^3.3.3",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-is": "^18.2.0",
"urql": "^2.2.2",
"yup": "^0.32.11"
},
"devDependencies": {
"#cypress/react": "^6.1.1",
"#cypress/webpack-dev-server": "^2.2.0",
"#graphql-codegen/cli": "^2.8.0",
"#graphql-codegen/typescript": "^2.7.1",
"#graphql-codegen/typescript-operations": "^2.5.1",
"#testing-library/cypress": "^8.0.3",
"#types/node": "17.0.35",
"#types/react": "18.0.9",
"#types/react-dom": "18.0.5",
"autoprefixer": "^10.4.7",
"cypress": "^10.6.0",
"html-webpack-plugin": "^5.5.0",
"postcss": "^8.4.14",
"tailwindcss": "^3.1.2",
"typescript": "4.7.2",
"webpack": "^5.74.0",
"webpack-dev-server": "^4.10.0"
}
}
Here's the error which displays after running yarn cypress and choosing component testing for the 'NavBar.cy.ts' test.
N.B., I did add a few dev dependencies because I was receiving a webpack warning early on.
Any help is greatly appreciated.
edit:
I had added an incorrect displayName assignment to some of my components in an attempt to get cypress component testing working - and had forgotten to remove in a previous commit. This wasn't even the issue as displayName couldn't be read from undefined, so I think the issue is that the component/s aren't available to cypress. In any case, it was wrong and I've removed.
The basic problem is the parameter you are passing into cy.mount() isn't being compiled to JSX.
Two things should fix it
take the quotes off the JSX, so it should be cy.mount(<NavBar />);
change the extension of the spec file to NavBar.cy.tsx
It's not really a working nextjs app, you are getting the exact same message from a different component SelectActivType.tsx when you you run the app (outside of the Cypress test).
In terms of the NavBar, the code should be adjusted from this
export const NavBar: React.FC<NavBarProps> = ({}) => {
NavBar.displayName = 'ActivTypes';
const router = useRouter();
return (
...
);
}
to this
export const NavBar: React.FC<NavBarProps> = ({}) => {
const router = useRouter();
return (
...
);
}
// move the offending line outside of the function
NavBar.displayName = 'ActivTypes';
You cannot add a property to a function inside the function definition.
For reference see how to set displayName in a functional component [React].
Related
Im getting the above mentioned error when trying to run the npm run build for next js app. The next.js app is in typescript.
Here is the error screenshot with the folder structure
Error. Unable to understand why _app.tsx is being considered as directory here instead of a file. Any help is much appreciated. Thanks in advance!
Edit: It's just a basic next.js app created with typescript by default containing the folder structure shown in the left side in the Error screenshot above.
Below is the code inside _app.tsx:
import 'tailwindcss/tailwind.css'
import React from 'react'
import { Layout } from '../components'
import '../styles/globals.scss'
import type { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
export default MyApp
Below is my package.json
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"graphql": "^16.3.0",
"graphql-request": "^4.1.0",
"html-react-parser": "^1.4.8",
"moment": "^2.29.1",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-multi-carousel": "^2.8.0",
"sass": "^1.49.9"
},
"devDependencies": {
"#types/node": "17.0.4",
"#types/react": "17.0.38",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.5",
"prettier": "^2.5.1",
"prettier-plugin-tailwindcss": "^0.1.1",
"tailwindcss": "^3.0.7",
"typescript": "4.5.4"
}
}
I receive error when I ran npm run build as Error: EISDIR: illegal operation on a directory, readlink 'D:\study\noobinjs\pages_app.tsx'.
Just started learning next.js and this happens in the initial encounter.
Try to put the file of project in C drive not in the D.
Example => C:\Users\Mahmoud\Desktop\next-damo
Then try to run npm run build.
This problem may be related to whether the symbolic link can be created or not.
I also encountered the same problem, but solved it by changing the filesystem from exFAT to NTFS.
As you know exFAT can't create symlink.
The site loses all functionalities after building it. In develop mode everything works fine, but when I build the website it looks like all scripts are missing. Bootstrap (Carousel DropDowns) are not responding, leflet map and background image not loading and react-multi-carousel do not work. I don't see any errors in the browser console, of course I ran gatsby clean before building. I uploaded the project to netlify. Below I am enclosing the json package:
{
"name": "Website",
"private": true,
"description": "Description",
"version": "0.1.0",
"license": "0BSD",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"dependencies": {
"#fortawesome/fontawesome-svg-core": "^1.2.35",
"#fortawesome/free-brands-svg-icons": "^5.15.3",
"#fortawesome/free-solid-svg-icons": "^5.15.3",
"#fortawesome/react-fontawesome": "^0.1.14",
"bootstrap": "^4.6.0",
"gatsby": "^3.2.1",
"gatsby-background-image": "^1.5.0",
"gatsby-image": "^3.2.0",
"gatsby-link": "^3.2.0",
"gatsby-plugin-image": "^1.2.0",
"gatsby-plugin-postcss": "^4.2.0",
"gatsby-plugin-react-helmet": "^4.2.0",
"gatsby-plugin-react-leaflet": "^3.0.0",
"gatsby-plugin-recaptcha": "^1.0.5",
"gatsby-plugin-robots-txt": "^1.5.5",
"gatsby-plugin-sass": "^4.2.0",
"gatsby-plugin-sharp": "^3.2.0",
"gatsby-plugin-sitemap": "^3.2.0",
"gatsby-remark-images": "^4.2.0",
"gatsby-source-filesystem": "^3.2.0",
"gatsby-transformer-remark": "^3.2.0",
"gatsby-transformer-sharp": "^3.2.0",
"gbimage-bridge": "^0.1.2",
"leaflet": "^1.7.1",
"node-sass": "^5.0.0",
"postcss": "^8.2.9",
"react": "^17.0.2",
"react-animations": "^1.0.0",
"react-bootstrap": "^1.5.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-leaflet": "^3.1.0",
"react-multi-carousel": "^2.6.2",
"react-scripts": "^4.0.3",
"styled-components": "^5.2.3"
},
"devDependencies": {
"http-proxy-middleware": "^1.1.0",
"netlify-lambda": "^2.0.3",
"npm-run-all": "^4.1.5",
"prettier": "^2.2.1"
}
}
There's not much debug in the question however, to me, it seems that you are using some dependencies outside React's scope, which may potentially block React's hydration process, which may explain the problem described. For example, using Leaflet instead of React's Leaflet or (depending on its implementation) Bootstrap instead of React's Boostrap.
You should be able to change all React-unfriendly modules to React's ones without too much effort and that should fix your problems.
Keep in mind that if your project "work in develop and breaks in build" doesn't mean that your project work or stops working, it just means that is working under certain and specific circumstances. Basically, and summarizing (to avoid extending the answer), gatsby develop uses the browser as an interpreter, where there are, among other things, global objects like window or document. However, gatsby build occurs in the Node server, where at the build time, there are not global objects because there are not even created yet, that the main reason why you may face a different behavior between both scenarios but doesn't mean that the project stopped working magically.
You can read further details in the Overview of Gatsby Build Process.
Another option, linked with blocking React's hydration, is that some component may be blocking that process because of its own behavior. Be careful when using global objects like window or document (or when importing modules that uses it), they use should be always be wrapped inside the following condition, as you can see from the docs:
When referencing window in a React component.
import * as React from "react"
// Check if window is defined (so if in the browser or in node.js).
const isBrowser = typeof window !== "undefined"
export default function MyComponent() {
let loggedIn = false
if (isBrowser) {
window.localstorage.getItem("isLoggedIn") === "true"
}
return <div>Am I logged in? {loggedIn}</div>
}
Or when requiring a module:
// Requiring a function causes an error during builds
// as the code tries to reference window
const module = require("module") // Error
// Wrap the require in check for window
if (typeof window !== `undefined`) {
const module = require("module")
}
The same approach can be done using loadable components as the docs suggests but without providing any piece of code it's impossible to guess what should be its implementation.
I solved the problem by wrapping the leaflet maps in Loadable
import React from 'react';
import Loadable from "#loadable/component"
const LoadableMap = Loadable(() => import("./map.js"))
export default LoadableMap;
I am having an error when I build my application in react. I noticed this error only when I tried to build application.
When I stopped dev server and ran it again, it showed the same error. It seems that I made some change that only showed when I started the server again or make build:
Module not found: Error: Can't resolve 'buffer' in '\node_modules\htmlparser2\lib' BREAKING CHANGE: webpack < 5
used to include polyfills for node.js core modules by default.This is
no longer the case. Verify if you need these module and configure a
polyfill for it.
If you want to include a polyfill, you need to install 'buffer'. If
you don't want to include a polyfill, you can use an empty module like
this:
resolve.alias: { "buffer": false }
error Command failed with exit code 1.
My application is made in CRA and Typescript. This is my package.json:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "react-scripts start",
"build": "cross-env NODE_OPTIONS='--max-old-space-size=4096' react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"dependencies": {
"#apollo/react-hooks": "^4.0.0",
"#date-io/moment": "^1.3.13",
"#material-ui/core": "^4.11.0",
"#material-ui/icons": "^4.9.1",
"#material-ui/lab": "^4.0.0-alpha.56",
"#material-ui/pickers": "^3.2.10",
"#optimizely/react-sdk": "^2.4.0",
"apollo-boost": "^0.4.9",
"classnames": "^2.2.6",
"formik": "^2.2.5",
"graphql": "^15.4.0",
"lodash": "^4.17.20",
"moment": "^2.29.1",
"react": "^16.13.1",
"react-app-polyfill": "^2.0.0",
"react-dom": "^16.13.1",
"react-google-recaptcha": "^2.1.0",
"react-masonry-css": "^1.0.14",
"react-router-dom": "^5.2.0",
"react-test-renderer": "^16.13.1",
"react-toastify": "^6.1.0",
"reset-css": "^5.0.1",
"use-debounce": "^5.1.0"
},
"devDependencies": {
"#testing-library/jest-dom": "^5.11.6",
"#testing-library/react": "^11.2.1",
"#testing-library/user-event": "^12.2.2",
"#types/classnames": "^2.2.11",
"#types/enzyme": "^3.10.8",
"#types/enzyme-adapter-react-16": "^1.0.6",
"#types/jest": "^26.0.15",
"#types/lodash": "^4.14.165",
"#types/moment": "^2.13.0",
"#types/node": "^14.14.9",
"#types/react": "^16.9.56",
"#types/react-dom": "^16.9.9",
"#types/react-google-recaptcha": "^2.1.0",
"#types/react-router-dom": "^5.1.6",
"cross-env": "^7.0.2",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"enzyme-to-json": "^3.6.1",
"husky": "^4.3.0",
"jest-dom": "^4.0.0",
"jest-sonar-reporter": "^2.0.0",
"lint-staged": "^10.5.1",
"node-sass": "^5.0.0",
"prettier": "^2.2.0",
"ts-jest": "^26.4.4",
"typescript": "^4.1.2"
}
}
You need to install the buffer package
npm install buffer
You have to Install this
npm install assert browserify-zlib buffer process stream-browserify util .
it will help you out
I found a solution to my problem. It is a bit weird that it didn't show up as test error.
SOLUTION
To solve this I just replaced location of TEST_ID to be in my component, and that my-component.test file to import it from there:
My component
import React, { FunctionComponent } from 'react';
/* Tests */
export const TEST_ID = 'my-component-test-id';
export const MyComponent: FunctionComponent = () => {
return <div data-test-id={TEST_ID}>123</div>;
};
Test
import React from 'react';
import { cleanup } from '#testing-library/react';
import { mount } from 'enzyme';
import { TEST_ID } from './my-component';
import MyComponent from './my-component'
afterEach(cleanup);
it('Render My component and have some value', () => {
const wrapper = mount(<MyComponent />);
const myComponent = wrapper.find(`[data-testid='${TEST_ID}']`);
expect(myComponent).toHaveValue('some value');
});
Analysis
Apparently if you import some value (in my case a constant) from .test file, if you try and build your app, the mentioned error will show up.
In my case I had a component:
MyComponent
import React, { FunctionComponent } from 'react';
/* Tests */
import { TEST_ID } from './test/my-component.test';
export const MyComponent: FunctionComponent = () => {
return <div data-test-id={TEST_ID}>some value</div>;
};
The TEST_ID was imported from my-component.test file. The purpose of that constant was to have that test id set for component so I can find that element based of that test id in my test.
Test
import React from 'react';
import { cleanup } from '#testing-library/react';
import { mount } from 'enzyme';
import MyComponent from './my-component'
afterEach(cleanup);
export const TEST_ID = 'my-component-test-id';
it('Render My component and have some value', () => {
const wrapper = mount(<MyComponent />);
const myComponent = wrapper.find(`[data-testid='${TEST_ID}']`);
expect(myComponent).toHaveValue('some value');
});
you need to install 'buffer' : npm install buffer oR npm install buffer --f
I've got a TypeScript function which returns a React Native View.
import React from "react";
import JSX, {View} from "react-native";
class DummyClass {
static getView() {
return (
<View style={{flex: 1}}/>
);
}
}
export default DummyClass;
And I'm calling this function in this way:
import JSX from "react-native";
import DummyClass from "./util/dummy";
const DummyWrapper = () => {
return (DummyClass.getView());
};
export default DummyWrapper;
And when I run eslint, I get a warning.
5:5 warning Missing return type on function #typescript-eslint/explicit-module-boundary-types
So, I need to be returning something. JSX.Element seems reasonable enough, but that doesn't seem to be working. For one, when I try to return a JSX.Element, VSCode can't resolve it and pretends it's any instead. And moreover, it causes errors in other places that call the function.
So, doing this:
static getView() : JSX.Element {
and const DummyWrapper = () : JSX.Element => {
Results in the following error in DummyCaller:
5:5 error Unsafe return of an any typed value #typescript-eslint/no-unsafe-return
So now I'm not sure exactly what to do. I've tried a few other things, such as returning View, typeof View, React.Component (and typeof), and a few other things. I've also messed around with where JSX is being imported from. If I import from react, it seems to work even worse than if I import it from react-native. Also in my research, I see the most common problem is that one's React and React Native types are out of date, but as far as I can tell, I'm on the most up-to-date versions.
My packages.json:
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"lint": "eslint -c .eslintrc.js --ext .tsx ."
},
"dependencies": {
"#dudigital/react-native-zoomable-view": "^1.0.15",
"#react-native-community/masked-view": "^0.1.10",
"#react-navigation/native": "^5.7.6",
"#react-navigation/stack": "^5.9.3",
"#types/react-native-vector-icons": "^6.4.6",
"change-case": "^4.1.1",
"expo": "~39.0.2",
"expo-status-bar": "~1.0.2",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-39.0.2.tar.gz",
"react-native-gesture-handler": "^1.8.0",
"react-native-paper": "^4.2.0",
"react-native-reanimated": "^1.13.1",
"react-native-safe-area-context": "^3.1.8",
"react-native-screens": "^2.11.0",
"react-native-tab-view": "^2.15.2",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "^0.13.18"
},
"devDependencies": {
"#babel/core": "~7.9.0",
"#types/jest": "^26.0.15",
"#types/react": "^16.9.53",
"#types/react-dom": "^16.9.8",
"#types/react-native": "^0.63.27",
"#types/react-navigation": "^3.4.0",
"#types/react-redux": "^7.1.9",
"#types/react-test-renderer": "^16.9.3",
"#typescript-eslint/eslint-plugin": "^4.5.0",
"#typescript-eslint/parser": "^4.5.0",
"commonjs": "latest",
"eslint": "^7.11.0",
"eslint-plugin-jsdoc": "^30.7.3",
"eslint-plugin-prefer-arrow": "^1.2.2",
"eslint-plugin-react": "^7.21.5",
"react-native-typescript-transformer": "^1.2.13",
"requirejs": "latest",
"ts-jest": "^26.4.1",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
},
"private": true
}
React should be putting JSX into the global namespace, so if you don't import it from anywhere then returning JSX.Element should work.
You can also import {ReactElement} from "react" and return ReactElement.
You can also import {FunctionComponent} from "react" and type the DummyWrapper function itself, not the return type, as DummyWrapper: FunctionComponent<{}>.
There's a lot of options.
But I really do not understand the use case where you would be creating an element from a static method on a class. This seems like a bad design that you should rethink. Can you make getView into a function component? Do you need the class DummyClass at all?
I am trying to integrate a CARTO map according to this example:
Importing Carto:
// Import react-leaflet for the map / basemap components
import { Map, TileLayer as Basemap } from 'react-leaflet';
// Import CARTO.js v4 <3
import carto from 'carto.js';
// Import our custom Layer component (it uses carto.js methods internally)
import Layer from './Layer';
// Voyager basemap <3
const CARTO_BASEMAP = 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png';
This is the constructor of my React Component:
constructor(props) {
super(props);
this.state = {
center: [40.758313915, -3.67774875],
zoom: 11,
},
// Setup the client in the contructor with our user and apiKey
this.cartoClient = new carto.Client({ apiKey: 'wadus', username: 'rochoa' });
package.json:
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"carto.js": "^4.0.1",
"classnames": "^2.2.6",
"jsonwebtoken": "^8.3.0",
"jwt-decode": "^2.2.0",
"leaflet": "^1.3.3",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-leaflet": "^2.0.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-scripts": "1.1.4",
"react-simple-storage": "^1.2.1",
"redux": "^4.0.0",
"redux-connect": "^7.0.0",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
When running, receiving:
TypeError: __WEBPACK_IMPORTED_MODULE_2_carto_js___default.a.Client is not a constructor
Having a hard time to understand what is wrong here...
The problem is because that there are differences between carto.js 4.0.0-beta and 4.0.1.
The example you linked to is using 4.0.0-beta version. I tried created a sandbox with carto.js 4.0.1, and the issue happen as well.
I can't find the documentation about carto.js differences between 4.0.1 and 4.0.0 beta. The official docs even says that you should do new cartoClient() as well. I can only assume that there are something wrong with their 4.0.1 version.
What you can do right now is install the beta package instead of 4.0.1.
npm -i carto.js#4.0.0-beta.42
Then run your project again.
The package is outdated. They moved it to another place. I added as dependency #carto/carto.js instead of carto.js and substituted it in whatever file it's used in.
npm install #carto/carto.js
import carto from '#carto/carto.js'