diff --git a/package.json b/package.json index 548f7a8bb0f..b4240af03f4 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "jest": "^23.6.0", "lerna": "~2.9.1", "lolex": "~2.3.2", + "mutationobserver-shim": "^0.3.3", "prettier": "~1.16.4", "raf": "~3.4.0", "ts-jest": "^23.10.5", diff --git a/packages/ra-input-rich-text/src/index.js b/packages/ra-input-rich-text/src/index.js index 1ae88488912..b2c5337a9d0 100644 --- a/packages/ra-input-rich-text/src/index.js +++ b/packages/ra-input-rich-text/src/index.js @@ -10,6 +10,8 @@ import { withStyles } from '@material-ui/core/styles'; import styles from './styles'; export class RichTextInput extends Component { + lastValueChange = null; + static propTypes = { addLabel: PropTypes.bool.isRequired, classes: PropTypes.object, @@ -56,6 +58,10 @@ export class RichTextInput extends Component { this.quill.on('text-change', debounce(this.onTextChange, 500)); } + shouldComponentUpdate(nextProps) { + return nextProps.input.value !== this.lastValueChange; + } + componentDidUpdate(prevProps) { if (prevProps.input.value !== this.props.input.value) { const selection = this.quill.getSelection(); @@ -76,6 +82,7 @@ export class RichTextInput extends Component { onTextChange = () => { const value = this.editor.innerHTML == '


' ? '' : this.editor.innerHTML; + this.lastValueChange = value; this.props.input.onChange(value); }; @@ -91,7 +98,7 @@ export class RichTextInput extends Component { fullWidth={this.props.fullWidth} className="ra-rich-text-input" > -
+
{error && {error}} {helperText && {helperText}} diff --git a/packages/ra-input-rich-text/src/index.spec.js b/packages/ra-input-rich-text/src/index.spec.js new file mode 100644 index 00000000000..b8e26ae3ba0 --- /dev/null +++ b/packages/ra-input-rich-text/src/index.spec.js @@ -0,0 +1,52 @@ +import React from 'react'; +import debounce from 'lodash/debounce'; +import {render, fireEvent, waitForElement, cleanup, getByTestId} from 'react-testing-library' + +import { RichTextInput } from './index'; + +let container; + +jest.mock('lodash/debounce'); +describe('RichTextInput', () => { + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + document.getSelection = () => { + return { + removeAllRanges: () => {}, + getRangeAt: function() {}, + }; + }; + jest.mock('lodash.debounce', (fn) => fn); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('should call text-change event only once when editing', async () => { + const mockFn = jest.fn(); + debounce.mockImplementation(fn => fn); + const { getByTestId, rerender } = render( + test

', + onChange: mockFn + }} + meta={{error: null}} />); + const quillNode = await waitForElement(() => { + return getByTestId('quill') + }); + quillNode.__quill.setText('test1'); + rerender( + test1

', + onChange: mockFn + }} + meta={{error: null}} />) + + expect(mockFn).toHaveBeenCalledTimes(1); + }); +}) diff --git a/test-setup.js b/test-setup.js index 46e3b690fe7..2526e5ab9d6 100644 --- a/test-setup.js +++ b/test-setup.js @@ -1,4 +1,5 @@ require('raf/polyfill'); +require('mutationobserver-shim'); var enzyme = require('enzyme'); var Adapter = require('enzyme-adapter-react-16'); diff --git a/yarn.lock b/yarn.lock index 62fed4b7ff7..685cf6b9acf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10181,6 +10181,11 @@ multimatch@^2.0.0: arrify "^1.0.0" minimatch "^3.0.0" +mutationobserver-shim@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#65869630bc89d7bf8c9cd9cb82188cd955aacd2b" + integrity sha512-gciOLNN8Vsf7YzcqRjKzlAJ6y7e+B86u7i3KXes0xfxx/nfLmozlW1Vn+Sc9x3tPIePFgc1AeIFhtRgkqTjzDQ== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"