I'm trying to put our SPFx React Components under test.
We're using following technologies:
- spfx 1.13.1
- react 16.13.1
- jest 27.4.7
- enzyme 3.11.0
- typescript 4.2.4
- fabric-ui: 1.13.1
I am stuck on following error when running a simple test using enzym.mount.
TypeError: window.requestAnimationFrame is not a function
at Stylesheet.Object.<anonymous>.Stylesheet._getStyleElement (node_modules/@uifabric/merge-styles/src/Stylesheet.ts:295:16)
at Stylesheet.Object.<anonymous>.Stylesheet.insertRule (node_modules/@uifabric/merge-styles/src/Stylesheet.ts:227:65)
at applyRegistration (node_modules/@uifabric/merge-styles/src/styleToClassName.ts:284:20)
at Object.styleToClassName (node_modules/@uifabric/merge-styles/src/styleToClassName.ts:294:5)
at mergeCss (node_modules/@uifabric/merge-styles/src/mergeStyles.ts:30:18)
at Object.mergeStyles (node_modules/@uifabric/merge-styles/src/mergeStyles.ts:13:10)
at Object.<anonymous> (node_modules/@uifabric/utilities/src/scroll.ts:9:33)
Based on various other answers (here, here), I tried to play around with following code
global.requestAnimationFrame = function (callback) {
return setTimeout(callback, 0);
};
placing it at top of my test code, inside the describe and in a separate test-init file.
I also tried to use ras/polyfill
but without any change in the error.
Any help in moving me forward to a working solution?
test file.
/// <reference types="jest" />
import * as React from 'react';
import { configure, mount, ReactWrapper, shallow } from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';
import "jsdom-global/register";
import MyComponent, { IMyComponentProps, IMyComponentState } from './my-component';
// import { polyfill } from 'raf';
// polyfill();
// global.requestAnimationFrame = function (callback) {
// return setTimeout(callback, 0);
// };
configure({ adapter: new Adapter() });
describe('<MyComponent/>', () => {
let renderedElement: ReactWrapper<IMyComponentProps, IMyComponentState>;
beforeEach(() => {
renderedElement = mount(<MyComponent/>);
});
afterEach(() => {
renderedElement.unmount();
});
it('load my component', () => {
expect(renderedElement).toBeTruthy();
});
});
component controls
<TextField name='abc' label="" defaultValue={state.abc} onChange={_handleChange} />
<Dropdown label='xyz' placeholder='Select xyz' options={options} defaultSelectedKey={state.xyz} onChange={(e, i) => _handleChangeDropdown(e, i, 'xyz')} />
package.json file
...
"devDependencies": {
"@microsoft/microsoft-graph-types": "^2.11.0",
"@microsoft/rush-stack-compiler-4.2": "0.1.1",
"@microsoft/sp-build-web": "1.13.1",
"@microsoft/sp-module-interfaces": "1.13.1",
"@types/enzyme": "^3.10.11",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.10",
"@types/react": "17.0.38",
"@types/react-dom": "17.0.11",
"@types/react-router-dom": "^5.3.2",
"@types/webpack-env": "1.16.3",
"@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.1",
"ajv": "~8.8.2",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"eslint": "^8.6.0",
"eslint-config-react-app": "^7.0.0",
"eslint-plugin-react": "^7.28.0",
"gulp": "~4.0.2",
"gulp-eslint-new": "^1.1.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.4.7",
"jest-junit": "^13.0.0",
"jsdom": "^19.0.0",
"jsdom-global": "^3.0.2",
"raf": "^3.4.1",
"react-test-renderer": "^17.0.2",
"spfx-fast-serve-helpers": "~1.13.0",
"ts-jest": "^27.1.3",
"typescript": "4.2.4"
},
"jest": {
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": {
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1",
"^@mywebpart/(.*)": "<rootDir>/src/webparts/mywebpart/$1",
"^@shared/(.*)": "<rootDir>/src/shared/$1"
},
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testMatch": [
"**/src/**/*.tests.+(ts|tsx)"
],
"setupFiles": [
"<rootDir>/src/webparts/mywebpart/tests/tests-setup.ts"
],
"collectCoverage": true,
"coverageReporters": [
"json",
"lcov",
"text",
"cobertura"
],
"coverageDirectory": "<rootDir>/test-results",
"reporters": [
"default",
"jest-junit"
],
"coverageThreshold": {
"global": {
"branches": 60,
"functions": 60,
"lines": 60,
"statements": 60
}
}
},
"jest-junit": {
"output": "./test-results/summary-jest-junit.xml"
}
tsconfig.json file
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.2/includes/tsconfig-web.json",
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"inlineSources": false,
"strictNullChecks": false,
"noUnusedLocals": false,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"webpack-env",
"jest",
"node"
],
"lib": [
"es6",
"dom",
"es2015.collection",
"es2015.promise"
],
"baseUrl": "src",
"paths": {
"@mywebpart/*": [
"webparts/mywebpart/*"
],
"@shared/*": [
"shared/*"
]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
]
}