Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support running tests in Jest #225

Open
Reinmar opened this issue Mar 10, 2021 · 7 comments
Open

Support running tests in Jest #225

Reinmar opened this issue Mar 10, 2021 · 7 comments
Labels
squad:devops Issue to be handled by the Devops team. status:discussion support:2 An issue reported by a commercially licensed client. type:feature

Comments

@Reinmar
Copy link
Member

Reinmar commented Mar 10, 2021

Problem

Jest is the default test runner used by many React apps. Unfortunately, Jest does not use a real browser – instead, it runs tests in Node.js with the use of JSDOM. JSDOM is not a complete DOM implementation and while it's apparently sufficient for standard apps, it's not able to polyfill all the DOM APIs that CKEditor 5 requires. Thus, even if someone solves compilation issues, then running CKEditor 5 tests for real in Jest will not work.

Example error:

console.log src/App.js:84
    CKEditor (1): Error. TypeError: Cannot read property 'substr' of undefined
        at startsWithFiller (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/filler.js:92:45)
        at getDataWithoutFiller (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/filler.js:119:7)
        at DomConverter._processDataFromDomText (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:1072:10)
        at DomConverter.domToView (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:413:27)
        at DomConverter.child [as domChildrenToView] (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:472:27)
        at domChildrenToView.next (<anonymous>)
        at DomConverter.domToView (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:451:17)
        at DomConverter.child [as domChildrenToView] (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:472:27)
        at domChildrenToView.next (<anonymous>)
        at DomConverter.domToView (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js:451:17)
        at HtmlDataProcessor.toView (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js:79:29)
        at DataController.parse (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/controller/datacontroller.js:392:47)
        at Object.callback (/Users/pomek/Projects/pomek/react-ckeditor5-eject/node_modules/@ckeditor/ckeditor5-engine/src/controller/datacontroller.js:314:25)

Solution(s)

I don't think there's a solution for running all kind of CKEditor 5 tests in Jest. However, there are a couple things that could be done:

  • CKEditor 5 consists of pure-JS model and view implementations. Many of our tests rely on these two levels only (they skip the DOM) and the same could be true for developers integrating CKEditor 5. So, we could expose and document how to use a virtual editor in the tests.
  • We could investigate the most common JSDOM incompatibilities that break CKEditor 5 and try to figure out how to resolve them. One option would be to contribute to JSDOM, the other options is to add some hacks in our code for these specific issues.
  • We could document how to use Karma instead of Jest at least for CKEditor 5 tests. That's what worked best so far.

What else?


If you'd like to have this issue resolved please react with 👍 to this ticket.

@pomek
Copy link
Member

pomek commented Mar 10, 2021

I was able to run a single test case using VirtualTestEditor which does not use DOM.

I decided to substitute the ClassicEditor class (which I use in my app) with the VirtualTestEditor class in tests. It can be done using the #moduleNameMapper option in the Jest configuration.

My configuration in package.json:

{
    "jest":{
        "roots":[
            "<rootDir>/src"
        ],
        "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",
            "^.+\\.(svg)$":"<rootDir>/node_modules/jest-raw-loader",
            "^.+\\.css$":"<rootDir>/config/jest/cssTransform.js",
            "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)":"<rootDir>/config/jest/fileTransform.js"
        },
        "transformIgnorePatterns":[
            "\\\\/node_modules\\\\/(?!@ckeditor).+\\.(js|jsx|ts|tsx|svg)$",
            "^.+\\.module\\.(css|sass|scss)$"
        ],
        "modulePaths":[],
        "moduleNameMapper":{
            "^react-native$":"react-native-web",
            "^.+\\.module\\.(css|sass|scss)$":"identity-obj-proxy",
            "classiceditor":"<rootDir>/node_modules/@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor"
        },
        "moduleFileExtensions":[
            "web.js",
            "js",
            "web.ts",
            "ts",
            "web.tsx",
            "tsx",
            "json",
            "web.jsx",
            "jsx",
            "node"
        ],
        "watchPlugins":[
            "jest-watch-typeahead/filename",
            "jest-watch-typeahead/testname"
        ]
    }
}

The <App> component:

import React, { Component } from 'react';

import { CKEditor } from '@ckeditor/ckeditor5-react';

import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
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';

const editorConfiguration = {
	plugins: [
		Essentials,
		Bold,
		Italic,
		Paragraph
	],
	toolbar: [ 'bold', 'italic' ]
};


class App extends Component {
	render() {
		return (
			<div className="App">
				<h2>Using CKEditor 5 from source in React</h2>

				<div className="ckeditor-component" data-ckeditor-class-name={ ClassicEditor.name }>
					<CKEditor
						editor={ ClassicEditor }
						config={ editorConfiguration }
						data="<p>Hello from CKEditor 5!</p>"
					/>
				</div>
			</div>
		);
	}
}

export default App;

And a test that is saved into two files: App.test.js, and App2.test.js

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

test( 'renders the <CKEditor> component', () => {
	const { container } = render( <App/> );
	const editorWrapper = container.querySelector( '.ckeditor-component' );

	expect( editorWrapper ).toBeInTheDocument();
	expect( editorWrapper.getAttribute( 'data-ckeditor-class-name' ) ).toEqual( 'VirtualTestEditor' );
} );

I am using two of the same files in order to check whether the ckeditor-duplicated-modules error occurs.

My results:

image

We should start thinking about publishing our dev-utils.

Edit: My project followed the Integrating CKEditor 5 built from source section in the React component guide.

@pomek pomek pinned this issue Mar 10, 2021
@alicewriteswrongs
Copy link

@pomek is there any chance you could share a minimal complete example of the test setup you have, perhaps in a separate repo? As far as I can tell my code is doing more or less the same things you're doing here but I'm still getting the 'duplicate modules' error (#219) so I'm curious what the difference is between my setup and yours.

@pomek
Copy link
Member

pomek commented Mar 12, 2021

@aliceriot, I published my example application here – https://github.com/pomek/react-ckeditor5-eject.

In the README you will find everything that would help to execute the test.

@guscsales
Copy link

I installed this @ckeditor/ckeditor5-core package, but there is no tests folder there to map to virtual editor, maybe it was removed in some new version?

@tony
Copy link

tony commented Jan 9, 2024

If anyone has a recent example of the latest Jest + latest CKEditor + and TypeScript, it'd be appreciated.

@philippenunes
Copy link

philippenunes commented Feb 28, 2024

My ck-editor version is 35.x I'm trying update to last version to get last improviments, but my app do not run tests anymore using jest. I have been recived the following css erros:

console.error Error: Could not parse CSS stylesheet at exports.createStylesheet (***\node_modules\jsdom\lib\jsdom\living\helpers\stylesheets.js:34:21) at HTMLStyleElementImpl._updateAStyleBlock (***\node_modules\jsdom\lib\jsdom\living\nodes\HTMLStyleElement-impl.js:68:5) at HTMLStyleElementImpl._childTextContentChangeSteps (***\node_modules\jsdom\lib\jsdom\living\nodes\HTMLStyleElement-impl.js:36:12) at HTMLStyleElementImpl._insert (***\node_modules\jsdom\lib\jsdom\living\nodes\Node-impl.js:822:14) at HTMLStyleElementImpl._preInsert (***\node_modules\jsdom\lib\jsdom\living\nodes\Node-impl.js:756:10) at HTMLStyleElementImpl.insertBefore (***\node_modules\jsdom\lib\jsdom\living\nodes\Node-impl.js:593:17) at HTMLStyleElement.insertBefore (***\node_modules\jsdom\lib\jsdom\living\generated\Node.js:384:60) at insertBefore (***\ckeditor-custom\build\ckeditor.js:6:432142) at o (***\ckeditor-custom\build\ckeditor.js:6:432835) at f (***\ckeditor-custom\build\ckeditor.js:6:431391) { detail: '.ck-hidden{display:none!important}.ck-reset_all :not(.ck-reset_all-excluded *),.ck.ck-reset,.ck.ck-reset_all{box-sizing:border-box;height:auto;position:static;width:auto}:root{--ck-z-default:1;--ck-z-panel:calc(var(--ck-z-default) + 999);--ck-z-dialog:9999}.ck-transitions-disabled,.ck-transitions-disabled *{transition:none!important}:root{--ck-powered-by-line-height:10px;--ck-powered-by-padding-vertical:2px;--ck-powered-by-padding-horizontal:4px;--ck-powered-by-text-color:#4f4f4f;--ck-powered-by-border-radius:var(--ck-border-radius);--ck-powered-by-background:#fff;--ck-powered-by-border-color:var(--ck-color-focus-border)}.ck.ck-balloon-panel.ck-powered-by-balloon{--ck-border-radius:var(--ck-powered-by-border-radius);background:var(--ck-powered-by-background);box-shadow:none;min-height:unset;z-index:calc(var(--ck-z-panel) - 1)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by{line-height:var(--ck-powered-by-line-height)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by a{align-items:center;cursor:pointer;display:flex;filter:grayscale(80%);line-height:var(--ck-powered-by-line-height);opacity:.66;padding:var(--ck-powered-by-padding-vertical) var(--ck-powered-by-padding-horizontal)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-powered-by__label{color:var(--ck-powered-by-text-color);cursor:pointer;font-size:7.5px;font-weight:700;letter-spacing:-.2px;line-height:normal;margin-right:4px;padding-left:2px;text-transform:uppercase}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-icon{cursor:pointer;display:block}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by:hover a{filter:grayscale(0);opacity:1}.ck.ck-balloon-panel.ck-powered-by-balloon[class*=position_inside]{border-color:transparent}.ck.ck-balloon-panel.ck-powered-by-balloon[class*=position_border]{border:var(--ck-focus-ring);border-color:var(--ck-powered-by-border-color)}:root{--ck-color-base-foreground:#fafafa;--ck-color-base-background:#fff;--ck-color-base-border:#ccced1;--ck-color-base-action:#53a336;--ck-color-base-focus:#6cb5f9;--ck-color-base-text:#333;--ck-color-base-active:#2977ff;--ck-color-base-active-focus:#0d65ff;--ck-color-base-error:#db3700;--ck-color-focus-border-coordinates:218,81.8%,56.9%;--ck-color-focus-border:hsl(var(--ck-color-focus-border-coordinates));--ck-color-focus-outer-shadow:#cae1fc;--ck-color-focus-disabled-shadow:rgba(119,186,248,.3);--ck-color-focus-error-shadow:rgba(255,64,31,.3);--ck-color-text:var(--ck-color-base-text);--ck-color-shadow-drop:rgba(0,0,0,.15);--ck-color-shadow-drop-active:rgba(0,0,0,.2);--ck-color-shadow-inner:rgba(0,0,0,.1);--ck-color-button-default-background:transparent;--ck-color-button-default-hover-background:#f0f0f0;--ck-color-button-default-active-background:#f0f0f0;--ck-color-button-default-disabled-background:transparent;--ck-color-button-on-background:#f0f7ff;--ck-color-button-on-hover-background:#dbecff;--ck-color-button-on-active-background:#dbecff;--ck-color-button-on-disabled-background:#f0f2f4;--ck-color-button-on-color:#2977ff;--ck-color-button-action-background:var(--ck-color-base-action);--ck-color-button-action-hover-background:#4d9d30;--ck-color-button-action-active-background:#4d9d30;--ck-color-button-action-disabled-background:#7ec365;--ck-color-button-action-text:var(--ck-color-base-background);--ck-color-button-save:#008a00;--ck-color-button-cancel:#db3700;--ck-color-switch-button-off-background:#939393;--ck-color-switch-button-off-ho

This is not my oficial app, is is a boilerplate created to try jest works, but a have the same issue in;

this happens from version 40.0.0

@DeltekDavid
Copy link

Yes please, we are trying to integrate CKEditor5 into a project that uses Jest heavily. We could use some guidance. Is it even supported? @pomek 's example from 2021 is a 404 now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
squad:devops Issue to be handled by the Devops team. status:discussion support:2 An issue reported by a commercially licensed client. type:feature
Projects
None yet
Development

No branches or pull requests

9 participants