ESLint: 'cy' is not defined (Cypress) - reactjs

I've just started using Cypress with my React Typescript project. I've gotten some simple tests to run:
describe('settings page', () => {
beforeEach(() => {
cy.visit('http://localhost:3000')
});
it('starts in a waiting state, with no settings.', () => {
cy.contains('Waiting for settings...')
});
it('shows settings once settings are received', () => {
const state = cy.window().its('store').invoke('getState')
console.log(state) // different question: how do I get this to be the state and not a $Chainer?
});
});
It runs in Cypress just fine. But I get Typescript errors in Webstorm, saying that cy is not defined (a TS and ESlint error) and an error on describe saying all files must be modules when the --isolatedModules flag is provided.
I can make it a JS file instead of a TS file, then I still get cy is not defined.
I've tried import cy from 'cypress' but then I get ParseError: 'import' and 'export' may appear only with 'sourceType: module' which is a whole other can of worms (I'm taking baby steps in writing my tests and haven't had to import anything yet...)
/// <reference types="cypress" /> does not work.
Update (sort of)
I've followed instructions here and have made a little progress. To my already very full React webpack.config.dev.js I added the recommended code:
{ // TODO inserted for cypress https://stackoverflow.com/a/56693706/6826164
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
to the end of the list of rules (just before the file loader).
When I do this as well as setting up the plugins/index file as indicated in the article, the cypress "home screen" runs but when I click to open my tests, it takes very many seconds and then shows lots of errors, starting with
integration\settings.spec.ts
This occurred while Cypress was compiling and bundling your test code. This is usually caused by:
A missing file or dependency
A syntax error in the file or one of its dependencies
Fix the error in your code and re-run your tests.
./cypress/integration/settings.spec.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for C:\Users\...\...\front_end\cypress\integration\settings.spec.ts.
# multi ./cypress/integration/settings.spec.ts main[0]
Followed by, actually, a lot of Typescript output such as this:
C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx
[tsl] ERROR in C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx(37,41)
TS2339: Property 'toBeTruthy' does not exist on type 'Assertion'.
C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx
[tsl] ERROR in C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx(41,45)
TS2339: Property 'toBeDefined' does not exist on type 'Assertion'.
Notice that these are now errors for code outside the test files (although perhaps that makes sense). Many of them are for files in which I'm using Jest rather than Cypress, and many errors, as you can see, seem to be related to it inferring an Assertion type on expect that is not Jest, such that it thinks the toEqual matcher is wrong.
All the while, in Webstorm ESLint is still complaining about all my cy and TypeScript is underlining all those Jest assertions mentioned in the output.
This is all with a ts test file. If I rename the file to js, it says the file has no tests.
Any help? I love Cypress but I'm having a hell of a time getting it to work fully!

I got that error after upgrading to cypress version 4+. I installed the eslint-plugin-cypress
https://github.com/cypress-io/eslint-plugin-cypress
and activated it in the extends configuration either in package.json or in separate config file:
"eslintConfig": {
"extends": [
"plugin:cypress/recommended"
]
},

Add .eslintrc.json to cypress directory
In .eslintrc.json
{
"extends": [
"plugin:cypress/recommended"
]
}
I do not install eslint-plugin-cypress, and it fix the problem

Specify cy in eslintrc globals
Answered here
cy is a global variable. Much like location. So really it is window.cy. You can add it to the globals in Eslint. Don't import cy from cypress.
{
"globals": {
"cy": true
}
}
Added that to my .eslintrc and fixed the issue

The Cypress ESLint plugin will get rid of these warnings:
yarn add -D eslint-plugin-cypress (https://github.com/cypress-io/eslint-plugin-cypress)
add .eslintrc to the root of your project with the following:
{
"plugins": ["cypress"],
"extends": ["plugin:cypress/recommended"],
"rules": {
"jest/expect-expect": "off"
}
}

Try.. import cy from "cypress" this solved the problem for me.

at the top of your file put
/// <reference types="cypress" />
or download the official types
source: official cypress intellisense docs

I struggled a lot then this helped...
by adding same line in two files, eslintrc.json and eslintrc.js
(if u have other dependencies in extends, append them as well after it)
extends: ['plugin:cypress/recommended'],

Just add these lines to your tsconfig.json file for e2e tests:
"compilerOptions": {
"types": ["cypress"]
}
This adds support for cypress types.

/* global cy */
import above in your test file
example:
suppose you have login test ("cypress test file ex: cypress/integration/login.js")

I replaced the old style of type referencing,
/// <reference types="cypress" />
with this silly import
import type {} from 'cypress';
And the IDE now both recognizes Cypress's globals while also avoiding the "isolatedModules" issue it has with tsconfig.json

Seems I found a remedy that works (at least) for me. Adding this import to the top of the test:
import _Cypress from "cypress";
relaxes and comforts the ESLint plugin. Actually any name for the import can be used instead of "_Cypress": any that conforms your sense of beauty, does not conflict with anything and starts with underscore (to not provoke ESLint again). Of course, it looks like a kind of voodoo. I don't know why it works and probably there are better ways to present ESLint Cypress's globals, but I don't know them.

add this to jest.config.js
testPathIgnorePatterns: [
'/cypress',
],

Wrap your config object with defineConfig in the cypress.confi.ts file
like so
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
return config;
},
},
component: {
devServer: {
framework: "create-react-app",
bundler: "webpack",
},
},
});

For me adding .eslintignore in root directory and placing *.cy.js for all my test files was only workaround.
It seems that for the rest of us the working solution really is installing eslint-plugin-cypress and adding:
"eslintConfig": {
"extends": [
"plugin:cypress/recommended"
]
},
but idt didn't helped in my case because this plugin is no longer supported (almost for a year now) so it ended with critical error when combined with cypress-axe.

Related

Handle webpack loader syntax with Jest testing: exclamation raw-loader

My React project works great. Some files need the raw-loader and I don't want to eject the project. So I have some raw-loader imports like this:
import blank_md from '!!raw-loader!./assets/blank.md.txt';
But jest dies with an error
Cannot find module '!!raw-loader!./assets/blank.md.txt' from ...
This is similar to Jest issue 4868
After adding jest-raw-loader I tried adding to Jest's config:
"transform": { "^!!raw-loader!.*": "jest-raw-loader" }
but no dice.
Using mocking would be fine too.
moduleNameMapper: {
"^!!raw-loader!.*": "jest-raw-loader",
}
This should load all the raw-loader import as required by jest.
Was looking for a solution myself and found that you should add the following module name mapping:
"moduleNameMapper": {
"^!!raw-loader!./assets/(.*)$": "<rootDir>/src/[insert path]/assets/$1"
}
Replacing with your correct path for the assets directory.
Edit: A nicer approach is just doing this tho
"moduleNameMapper": {
"^!!raw-loader!(.*)$": "$1"
}
I was able to use the Jest moduleNameMapper option to have Jest "use" the mock files.
The good news is that the Jest tests now run.
The bad news is that Jest still doesn't know how to load the files, so it supplies the filename to the app (instead of the file's contents). That's ok for my tests but is not optimal.
Here are some of the working settings that I'm using. I'm setting them in the package.json file:
"jest": {
"setupFiles": ["<rootDir>/src/tests/setup-register-context.js"],
"moduleNameMapper": {
"^!!raw-loader!.*sdkExamples.*txt": "<rootDir>/src/tests/__mocks__/templateMock.txt",
"^!!raw-loader!\\./toolbox.xml": "<rootDir>/src/tests/__mocks__/xmlMock.xml",
"^!!raw-loader!.*/assets/startBlocks.xml": "<rootDir>/src/tests/__mocks__/xmlMock.xml",
"!!raw-loader!.*md\\.txt": "<rootDir>/src/tests/__mocks__/mdMock.md"
}
}

Can't resolve 'crypto-js' in React Typescript

I trying to use crypto-js in react typescript run with docker compose , but I am getting the following error
Module not found: Can't resolve 'crypto-js' in '/app/crypto'
Here is that i imported crypto-js. For example:
import crypto from 'crypto-js';
export const encrypt = (key: string, evalue: any) => {
const secret_key = crypto.SHA256(key);
return crypto.AES.encrypt(evalue, secret_key).toString();
};
I have tried many times but it is not working.
My best guess is Typescript requires some type definitions for the packages.
Try to run npm install #types/crypto-js --save-dev
Regarding your tsconfig.json file, I believe it is because you are specifing "include": [ "src" ] so it means that all node_modules will be skipped.
Try removing it and using baseUrl option instead.
The types are not required for the project to build (unless you use the strict flag). But as #Kael said, it could be useful installing them. So you can specify
"typeRoots": [
"node_modules/#types"
],
in your config file
Try declaring in your types.d.ts
declare module 'crpyto-js' {
}
If that works, we now at least that your TypeScript settings should be correct.
Then you just have to install the #types/crypto-js package and delete your module declaration again.
If that doesn't work your typescript config doesn't your node_modules/#types folder.
Then set in your tsconfig.json your TypeRoots
"compilerOptions": {
"typeRoots" : ["./typings", "node_modules/#types"]
}
}

Property 'hot' does not exist on type 'NodeModule'.ts(2339)

I have a purchased react template with the following lines, but its not clear to me whats the purpose of this, the template its in JS and I want to change it to Typescript
The following lines were present in the template
if (module.hot) {
module.hot.accept('./dashApp.js', () => {
const NextApp = require('./dashApp').default;
ReactDOM.render(<NextApp />, document.getElementById('root'));
});
}
However when renamed to .TS, I get this error:
Property 'hot' does not exist on type 'NodeModule'.ts(2339)
What does this code really does? in plain english
This code is related to Webpack's hot module replacement feature (HMR). module.hot works like this:
module.hot.accept(
dependencies, // Either a string or an array of strings
callback // Function to fire when the dependencies are updated
);
So the code you included does this: *when the code of ./dashApp.js or one of the module it requires/imports in the requirement/import tree gets updated, re-render the whole React app.
The hot property on node modules it not standard, thus the TS error - make sure you install the required type definitions! npm install --save-dev #types/webpack-env should do the trick.
Related reads:
Hot Module Replacement concept: high-level Webpack doc on HMR
Hot Module Replacement API low-level Webpack doc on HMR, explaining how to use it and how does module.hot.accept does
Property 'hot' does not exist on type 'NodeModule': Github issue resolving the TS error
Just to add to the accepted answer: After installing #types/webpack-env you might have to add "types": ["webpack-env"] to your tsconfig.json in compilerOptions. Only then it finally worked for me.
So your tsconfig.json would look like this:
{
"compilerOptions": {
...
"types": ["webpack-env"]
},
...
}

Jest setup "SyntaxError: Unexpected token export"

I'm implementing tests into an existing project that currently has no tests. My tests are failing to compile node_modules/ imports.
/Users/me/myproject/node_modules/lodash-es/lodash.js:10
export { default as add } from './add.js';
^^^^^^
SyntaxError: Unexpected token export
at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:320:12)
at Object.<anonymous> (app/reducers/kind_reducer.js:2:43)
at Object.<anonymous> (app/reducers/index.js:12:47)
The workaround I've found is to 'whitelist' node_modules in package.json jest config like this:
"jest": {
"transformIgnorePatterns": [
"!node_modules/"
]
}
This seems like a hack because it takes over 1 minute to run a simple test that imports node_modules/lodash-es/lodash.js.
If none of the other solutions worked for you, you can try this in your jest
"moduleNameMapper": {
"^lodash-es$": "lodash"
}
It will replace lodash-es with the commonjs version during testing runtime.
I had to add this into my .jestconfig:
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!lodash-es)"
]
Posting a more complete answer here:
Jest by default does not transform node_modules because node_modules is huge. Most node modules are packaged to expose ES5 code because this is runnable without any further transformation (and largely backwards compatible).
In your case, lodash-es specifically exposes ES modules, which will need to be built by Jest via babel.
You can try narrowing your whitelist down so Jest doesn't try to pass every JavaScript file within node_modules through babel.
I think the correct configuration in your case is:
"jest": {
"transformIgnorePatterns": [
"/!node_modules\\/lodash-es/"
]
}
For create-react-app users who are looking for a fix, here's what worked for me:
// package.json
...
"jest": {
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!lodash-es)"
]
},
...
Overriding options in jest.config.js file didn't work for me. Keep in mind that not every option can be overridden, here's a list of supported options: https://create-react-app.dev/docs/running-tests#configuration
Probably someone finds this useful:
In my case, I have an Angular application that uses lodash-es package. During the testing, I am having the same error as the author.
OPatel's answer worked fine for me with a little tweak (add it to your jest.config.ts):
"moduleNameMapper": {
"lodash-es": "lodash"
}
After the changes I also needed to add the "esModuleInterop": true into my tsconfig.spec.json within the compilerOptions property to get rid of the TypeError: cloneDeep_1.default is not a function.
UPDATE:
After the solution above all the lodash methods return LodashWrapper instead of actual values e.g.
const clone = cloneDeep(object); // LodashWrapper
To get rid of this issue I used this solution:
https://github.com/nrwl/nx/issues/812#issuecomment-787141835
moduleNameMapper: {
"^lodash-es/(.*)$": "<rootDir>/node_modules/lodash/$1",
}
Renaming .babelrc to babel.config.js and adding transformIgnorePatterns worked for me.
module.exports = {
"presets": ["#babel/preset-env"]
}
P.S. My Jest version is:
"jest": "24.9.0"
babel-jest does not transpile import/export in node_modules when Babel 7 is used
I use pnpm, so I had to account for the symlink in the pattern, i.e.
transformIgnorePatterns: ['/node_modules/.pnpm/(?!lodash-es)']

React-router issues using static-render-webpack-plugin

I just started working with React last week, and I'm having trouble following a tutorial for the static-render-webpack-plugin.
I've put the code online at GitHub if you want to take a closer look.
After following the tutorial and making a couple of changes (I added babel-core, I changed the js loader to babel-loader and the entry point url needed a small correction), when I try to run webpack -p to generate the static files I get the following error:
ERROR in ./src/entry.js
Module build failed: SyntaxError: .../src/entry.js: Unexpected token (10:2)
8 |
9 | const routes = (
> 10 | <Route path="/" handler={RootPage}>
| ^
I think it might have something to do with the changes made with the latest version of react-router. I'm using the latest version, but the syntax for the tutorial looks like it might have been written prior to v.1.0. For example, I think the part of the tutorial that says to add this to the src/entry.js file:
if (typeof document != 'undefined') {
Router.run(routes, path, (Root) => {
React.render(<Root/>, document);
});
}
probably needs to be rewritten to something like this (but I'm not sure if this is quite right):
if (typeof document != 'undefined') {
ReactDOM.render(routes, document);
}
There's obviously more going on though since I get the same error message when I try that rewritten snippet then run webpack-dev-server -- which is the only time it should hit that code. (Yes, I added import ReactDOM from 'react-dom'; to the top of the page and "react-dom": "^0.14.7", to the package.json.)
I am sure this part (also on src/entry.js) needs to be rewritten to match the latest react-router too but I'm not sure how:
export default function(path, props, callback) {
Router.run(routes, path, (Root) => {
const html = React.renderToString(<Root/>);
callback('<!doctype html>' + html);
});
}
Thanks in advance for any help or hints you can give.
Your code is breaking because Webpack doesn't know how to transpile the JSX to ES5. You've specified babel-loader as your loader for JS files in your webpack config, but unfortunately Babel 6 does not do anything out of the box, you need to include "plugins" that contain the rules for compiling different syntaxes down to ES5. In this case, you'll want the es2015 preset to support all ES6 syntax, and the react preset to support JSX. You're also missing the extract-text-webpack-plugin you are trying to import into your webpack config. Snag these through NPM:
npm i -D babel-preset-2015 babel-preset-react extract-text-webpack-plugin
Then, add the presets to your webpack.config.js file in the loaders section for js/jsx files:
{
test: /\.(js|jsx)?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
I forked your repo and made these changes and was able to get a bit further through the compilation process. It seems like there are module dependencies specific to your project you'll still need to resolve.

Resources