Barilo Aleksandr
Barilo Aleksandr

Reputation: 31

React CKeditor Jest error: SyntaxError: Cannot use import statement outside a module

App was created using CreateReactApp with ejecting. I'm trying to use CKeditor according to this doc CKeditor 5 After few hours it works fine, but much more hours trying to fix error in test finished unsuccessfully! When I run npm test I got this error:

node_modules/@ckeditor/ckeditor5-editor-classic/src/classiceditor.js:10
    import Editor from '@ckeditor/ckeditor5-core/src/editor/editor';
   
    SyntaxError: Cannot use import statement outside a module

      1 | import React, { useState, useEffect } from 'react';
      2 | import CKEditor from '@ckeditor/ckeditor5-react';
    > 3 | import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

my package.json:

{
  "private": true,
  "dependencies": {
    "@babel/core": "7.4.3",
    "@ckeditor/ckeditor5-alignment": "^16.0.0",
    "@ckeditor/ckeditor5-basic-styles": "^16.0.0",
    "@ckeditor/ckeditor5-dev-utils": "^12.0.5",
    "@ckeditor/ckeditor5-dev-webpack-plugin": "^8.0.5",
    "@ckeditor/ckeditor5-editor-classic": "^16.0.0",
    "@ckeditor/ckeditor5-essentials": "^16.0.0",
    "@ckeditor/ckeditor5-heading": "^16.0.0",
    "@ckeditor/ckeditor5-link": "^16.0.0",
    "@ckeditor/ckeditor5-list": "^16.0.0",
    "@ckeditor/ckeditor5-paragraph": "^16.0.0",
    "@ckeditor/ckeditor5-react": "^2.0.0",
    "@ckeditor/ckeditor5-theme-lark": "^16.0.0",
    "@svgr/webpack": "4.1.0",
    "@typescript-eslint/eslint-plugin": "1.6.0",
    "@typescript-eslint/parser": "1.6.0",
    "axios": "^0.18.1",
    "babel-eslint": "10.0.1",
    "babel-jest": "24.7.1",
    "babel-loader": "8.0.5",
    "babel-plugin-named-asset-import": "^0.3.2",
    "babel-preset-react-app": "^8.0.0",
    "base64url": "^3.0.1",
    "blueimp-load-image": "^2.21.0",
    "case-sensitive-paths-webpack-plugin": "2.2.0",
    "cleave.js": "^1.4.10",
    "css-loader": "2.1.1",
    "dotenv": "6.2.0",
    "dotenv-expand": "4.2.0",
    "enzyme": "^3.9.0",
    "enzyme-adapter-react-16": "^1.12.1",
    "file-loader": "3.0.1",
    "fingerprintjs2": "^2.1.0",
    "flow-typed": "^2.5.2",
    "fs-extra": "7.0.1",
    "google-map-react": "^1.1.4",
    "history": "^4.9.0",
    "html-react-parser": "^0.10.0",
    "html-webpack-plugin": "4.0.0-beta.5",
    "identity-obj-proxy": "3.0.0",
    "is-wsl": "^1.1.0",
    "jest": "24.7.1",
    "jest-environment-jsdom-fourteen": "0.1.0",
    "jest-resolve": "24.7.1",
    "jest-watch-typeahead": "0.3.0",
    "lint-staged": "^8.1.5",
    "mini-css-extract-plugin": "0.5.0",
    "moment": "^2.24.0",
    "node-sass": "^4.12.0",
    "optimize-css-assets-webpack-plugin": "5.0.1",
    "pnp-webpack-plugin": "1.2.1",
    "postcss-flexbugs-fixes": "4.1.0",
    "postcss-loader": "3.0.0",
    "postcss-normalize": "7.0.1",
    "postcss-preset-env": "6.6.0",
    "postcss-safe-parser": "4.0.1",
    "qs": "^6.7.0",
    "raw-loader": "^3.1.0",
    "rc-slider": "^8.6.9",
    "react": "^16.8.6",
    "react-app-polyfill": "^1.0.0",
    "react-avatar-editor": "^11.0.7",
    "react-dates": "^20.2.2",
    "react-dev-utils": "^9.0.0",
    "react-dom": "^16.8.6",
    "react-modal": "^3.8.1",
    "react-onclickoutside": "^6.8.0",
    "react-places-autocomplete": "^7.2.1",
    "react-redux": "^7.0.3",
    "react-responsive": "^6.1.2",
    "react-router-dom": "^5.0.0",
    "react-select": "^2.4.3",
    "react-slick": "^0.24.0",
    "react-test-renderer": "^16.8.6",
    "react-truncate": "^2.4.0",
    "react-with-direction": "^1.3.0",
    "redux": "^4.0.1",
    "redux-thunk": "^2.3.0",
    "resolve": "1.10.0",
    "sass-loader": "7.1.0",
    "semver": "6.0.0",
    "slick-carousel": "^1.8.1",
    "style-loader": "0.23.1",
    "stylelint": "^10.0.1",
    "stylelint-config-standard": "^18.3.0",
    "terser-webpack-plugin": "1.2.3",
    "url-loader": "1.1.2",
    "webpack": "4.29.6",
    "webpack-dev-server": "3.2.1",
    "webpack-manifest-plugin": "2.0.4",
    "workbox-webpack-plugin": "4.2.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run test && flow"
    }
  },
  "proxy": "https://getrenty-qa.devopsready.tools",
  "scripts": {
    "start": "node scripts/start.js",
    "precommit": "npm test && lint-staged",
    "build": "node scripts/build.js",
    "test:lint:js": "eslint src/**/*.{js,jsx}",
    "test:lint:scss": "stylelint --config=.stylelintrc \"**/*.scss\"",
    "test:lint": "npm run test:lint:js && npm run test:lint:scss",
    "test:unit": "node scripts/test.js --env=jsdom",
    "test": "npm run test:lint && npm run test:unit",
    "test:ci": "node scripts/test.js --env=jsdom --ci --reporters=default --reporters=jest-junit --coverage",
    "flow": "flow"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-config-prettier": "^4.2.0",
    "eslint-config-react-app": "^4.0.1",
    "eslint-loader": "^2.2.1",
    "eslint-plugin-flowtype": "^3.11.1",
    "eslint-plugin-import": "^2.18.0",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-plugin-react": "^7.14.2",
    "eslint-plugin-react-hooks": "^1.6.1",
    "flow-bin": "^0.98.0",
    "jest-junit": "^7.0.0",
    "prettier": "^1.17.0",
    "redux-devtools": "^3.5.0",
    "redux-devtools-extension": "^2.13.8",
    "stylelint-scss": "^3.6.1",
    "husky": "^2.1.0"
  },
  "jest": {
    "coverageReporters": [
      "text",
      "cobertura"
    ],
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,ts,tsx}",
      "!src/**/*.d.ts"
    ],
    "setupFiles": [
      "react-app-polyfill/jsdom"
    ],
    "setupFilesAfterEnv": [
      "<rootDir>/src/setupTests.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
      "<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
    ],
    "testEnvironment": "jest-environment-jsdom-fourteen",
    "transform": {
      "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
      "^.+\\.module\\.(css|sass|scss)$"
    ],
    "modulePaths": [
      "src/"
    ],
    "moduleNameMapper": {
      "^react-native$": "react-native-web",
      "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
    },
    "moduleFileExtensions": [
      "web.js",
      "js",
      "web.ts",
      "ts",
      "web.tsx",
      "tsx",
      "json",
      "web.jsx",
      "jsx",
      "node"
    ],
    "watchPlugins": [
      "jest-watch-typeahead/filename",
      "jest-watch-typeahead/testname"
    ]
  },
  "babel": {
    "presets": [
      "react-app"
    ]
  }
}

component code:

import React, { useState, useEffect } from 'react';
import CKEditor from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment';
import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Link from '@ckeditor/ckeditor5-link/src/link';
import List from '@ckeditor/ckeditor5-list/src/list';
import styles from './rtf.module.scss';

const editorConfig = {
  plugins: [
    Essentials,
    Alignment,
    Bold,
    Italic,
    Paragraph,
    Heading,
    Link,
    List,
  ],
  toolbar: [
    'heading',
    'bold',
    'italic',
    'link',
    'bulletedList',
    'numberedList',
    'alignment',
  ],
};

type Props = {
  initialData?: string,
  onSave: Function,
  title?: string,
  savingStatus?: string,
};

const Editor = ({ initialData, onSave, title, savingStatus }: Props) => {
  const [editorData, setData] = useState(initialData || '');

  useEffect(() => {
    setData(initialData);
  }, [initialData]);

  const handleChange = (event, editor) => {
    const data = editor.getData();

    setData(data);
  };

  const resetEdit = () => {
    setData(initialData);
  };

  const handleSave = () => {
    onSave(editorData);
  };

  return (
    <div>
      <div className={styles.title_row}>
        <h5 className={styles.title}>{title}</h5>
        <button
          type="button"
          className={`button_small ${styles.to_right}`}
          onClick={resetEdit}
        >
          Reset
        </button>
        <button
          type="button"
          className="button_green_dark_short"
          onClick={handleSave}
        >
          Save
        </button>
      </div>
      <div className={styles.saving_status}>{savingStatus}</div>
      <div className={styles.rtf_wrapper}>
        <CKEditor
          config={editorConfig}
          editor={ClassicEditor}
          onChange={handleChange}
          data={editorData}
        />
      </div>
    </div>
  );
};

Editor.defaultProps = {
  initialData: '',
  title: '',
  savingStatus: '',
};

export default Editor;

I have tried modify jest.transformIgnorePatterns in package.json but it failed again. Any advices?????

Upvotes: 3

Views: 3742

Answers (1)

This is happening because you are using the unbundled version of the ckeditor, jest does not understand es6, so you got to change transformIgnorePatterns so jest can be able to compile the files for you.

This is for a standard jest configuration (e.g jest.config.js) and .babelrc

*If you are using .babelrc try changing it to babel.config.js

In your jest configuration file include this:

{
      moduleNameMapper: {
        '^~/(.*)': '<rootDir>/src/$1',
        '\\.(css|scss)$': '<rootDir>/src/__mocks__/styleMock.js',
      },
      transformIgnorePatterns: ['/node_modules/(?!@ckeditor)/.+\\.js$']
}

If you are using craco in a react app use it like this:

jest: {
    configure(config) {
      config.moduleNameMapper = {
        '^~/(.*)': '<rootDir>/src/$1',
        '\\.(css|scss)$': '<rootDir>/src/__mocks__/styleMock.js',
      };

      ...

      config.transformIgnorePatterns = ['/node_modules/(?!@ckeditor)/.+\\.js$'];
      return config;
    },
  },

The ckeditor builded version is buggy right now, I hope they fix it soon enough...

Upvotes: 3

Related Questions