ag-grid Jest testing - this.btFirst.insertAdjacentElement is not a function - reactjs

I try to test ag-grid component using Jest:
describe('DataGridInternal Component Tests', () => {
it('includes class names on DataGrid', () => {
const component = mount(<DataGridInternal {...SAMPLE_PROPS} />);
expect(component.find('[data-test="ccfk-datagrid"]')).toHaveClassName('csf-material-grid');
});
});
I get the exception :
TypeError: this.btFirst.insertAdjacentElement is not a function
coming from
node_modules/ag-grid-community/dist/lib/rowModels/pagination/paginationComp.js:49
Once I remark this line the test is passing OK
any idea what is not correct?
I`m using :
"ag-grid-community": "21.2.2",
"ag-grid-react": "21.2.2",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.14.0",
"enzyme-to-json": "3.3.5"

Solution:
If you're using jest for your test runner, you'll need to upgrade by installing jest-environment-jsdom-fourteen, and adding the following to your jest.config
testEnvironment: 'jest-environment-jsdom-fourteen'
and
If you're using create-react-app,
npm i -D jest-environment-jsdom-fourteen
then in your scripts:
"test": "react-scripts test --env=jsdom-fourteen",
Sources: 1 2

I am facing the same issue as well.
I believe the issue lies in the version of the jsdom package that is being used with Jest testing runner.
insertAdjacentElement was implemented in version 13.1.0 of jsdom as stated in the changelog.
I am running a create-react-app v2, which currently does not use this version of jsdom.

Can you show how you're exactly requiring/importing ag-grid and defining your gridOptions structure?
I assume you're testing an existing table or a table you defined yourself in HTML?

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.

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"
}
}

ESLint: 'cy' is not defined (Cypress)

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.

React Jest --coverage ignore

My folder/ project structure for reusable components (i.e. field types) looks like this:
/fields
/fields/text
/fields/radio
/fields/checkbox
/fields/...
/fields/index.jsx (which only reexports each of above for simpler importing purposes)
now when i run jet --coverage i get index.jsx which is just a import/export proxy included into coverage report, is there a way to configure jest runner to ignore "such" files ?
Thanks
You could add the filename to coveragePathIgnorePatterns list of your jest settings
coveragePathIgnorePatterns: ['/fields/index.jsx'],
There are two ways I found:
First (already mentioned by #andreas-köberle) is ignoring files using config or CLI instruction.
Another one is writing some dummy tests:
import {Stuff} from '../index';
describe('check', () => {
it('reexports', () => {
expect(Stuff).toBeTruthy();
});
})
I found this one preferable. In case you write some logic in your reexports-file it reminds you to cover it with tests.

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)']

Resources