From b4f029e9f0885789f63df3ec24c58466f38c77e2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 12 Aug 2017 10:11:14 +0200 Subject: [PATCH] Test both Chrome 56 and other Chrome versions IME behavior --- spec/text-editor-component-spec.js | 598 ++++++++++++++++++++--------- src/text-editor-component.js | 8 +- 2 files changed, 419 insertions(+), 187 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 2c13b48af..c52cb53a8 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -3049,198 +3049,421 @@ describe('TextEditorComponent', () => { }) describe('keyboard input', () => { - it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { - const {editor, component, element} = buildComponent({text: ''}) - editor.insertText('x') - editor.setCursorBufferPosition([0, 1]) + describe('on Chrome 56', () => { + it('handles inserted accented characters via the press-and-hold menu on macOS correctly', async () => { + const {editor, component, element} = buildComponent({text: '', chromeVersion: 56}) + editor.insertText('x') + editor.setCursorBufferPosition([0, 1]) - // Simulate holding the A key to open the press-and-hold menu, - // then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Escape'}) - component.didKeyup({code: 'Escape'}) - expect(editor.getText()).toBe('xa') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xaa') - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate holding the A key to open the press-and-hold menu, + // then closing it via ESC. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'Escape'}) + component.didKeyup({code: 'Escape'}) + expect(editor.getText()).toBe('xa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xaa') + editor.undo() + expect(editor.getText()).toBe('x') - // Simulate holding the A key to open the press-and-hold menu, - // then selecting an alternative by typing a number. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Digit2'}) - component.didKeyup({code: 'Digit2'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - expect(editor.getText()).toBe('xá') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xáa') - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate holding the A key to open the press-and-hold menu, + // then selecting an alternative by typing a number. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'Digit2'}) + component.didKeyup({code: 'Digit2'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') - // Simulate holding the A key to open the press-and-hold menu, - // then selecting an alternative by clicking on it. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - expect(editor.getText()).toBe('xá') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xáa') - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate holding the A key to open the press-and-hold menu, + // then selecting an alternative by clicking on it. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') - // Simulate holding the A key to open the press-and-hold menu, - // cycling through the alternatives with the arrows, then selecting one of them with Enter. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Enter'}) - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Enter'}) - expect(editor.getText()).toBe('xá') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xáa') - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then selecting one of them with Enter. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.getHiddenInput().value = 'à' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xá') + component.didKeydown({code: 'Enter'}) + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'á', target: component.getHiddenInput()}) + component.didKeyup({code: 'Enter'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xá') - // Simulate holding the A key to open the press-and-hold menu, - // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) - expect(editor.getText()).toBe('xa') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xaa') - editor.undo() - expect(editor.getText()).toBe('x') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') - // Simulate pressing the O key and holding the A key to open the press-and-hold menu right before releasing the O key, - // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyO'}) - component.didKeypress({code: 'KeyO'}) - component.didTextInput({data: 'o', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyO'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xoà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xoá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) - expect(editor.getText()).toBe('xoa') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then closing it via ESC. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.getHiddenInput().value = 'à' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xá') + component.didKeydown({code: 'Escape'}) + component.didCompositionUpdate({data: 'a'}) + component.getHiddenInput().value = 'a' + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didKeyup({code: 'Escape'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xaa') + editor.undo() + expect(editor.getText()).toBe('x') - // Simulate holding the A key to open the press-and-hold menu, - // cycling through the alternatives with the arrows, then closing it by changing focus. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) - expect(editor.getText()).toBe('xá') - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) - expect(editor.getText()).toBe('xá') - // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) - expect(editor.getText()).toBe('xáa') - editor.undo() - expect(editor.getText()).toBe('x') + // Simulate pressing the O key and holding the A key to open the press-and-hold menu right before releasing the O key, + // cycling through the alternatives with the arrows, then closing it via ESC. + component.didKeydown({code: 'KeyO'}) + component.didKeypress({code: 'KeyO'}) + component.didTextInput({data: 'o', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyO'}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.getHiddenInput().value = 'à' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xoà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xoá') + component.didKeydown({code: 'Escape'}) + component.didCompositionUpdate({data: 'a'}) + component.getHiddenInput().value = 'a' + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didKeyup({code: 'Escape'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xoa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then closing it by changing focus. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.getHiddenInput().value = 'à' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didKeyup({code: 'ArrowRight'}) + await getNextTickPromise() + expect(editor.getText()).toBe('xá') + component.didCompositionUpdate({data: 'á'}) + component.getHiddenInput().value = 'á' + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) + await getNextTickPromise() + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') + }) + }) + + describe('on other versions of Chrome', () => { + it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { + const {editor, component, element} = buildComponent({text: '', chromeVersion: 57}) + editor.insertText('x') + editor.setCursorBufferPosition([0, 1]) + + // Simulate holding the A key to open the press-and-hold menu, + // then closing it via ESC. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'Escape'}) + component.didKeyup({code: 'Escape'}) + expect(editor.getText()).toBe('xa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xaa') + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // then selecting an alternative by typing a number. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'Digit2'}) + component.didKeyup({code: 'Digit2'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // then selecting an alternative by clicking on it. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then selecting one of them with Enter. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xá') + component.didKeydown({code: 'Enter'}) + component.didCompositionUpdate({data: 'á'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didKeyup({code: 'Enter'}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then closing it via ESC. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xá') + component.didKeydown({code: 'Escape'}) + component.didCompositionUpdate({data: 'a'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didKeyup({code: 'Escape'}) + expect(editor.getText()).toBe('xa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xaa') + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate pressing the O key and holding the A key to open the press-and-hold menu right before releasing the O key, + // cycling through the alternatives with the arrows, then closing it via ESC. + component.didKeydown({code: 'KeyO'}) + component.didKeypress({code: 'KeyO'}) + component.didTextInput({data: 'o', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyO'}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xoà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xoá') + component.didKeydown({code: 'Escape'}) + component.didCompositionUpdate({data: 'a'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didKeyup({code: 'Escape'}) + expect(editor.getText()).toBe('xoa') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + editor.undo() + expect(editor.getText()).toBe('x') + + // Simulate holding the A key to open the press-and-hold menu, + // cycling through the alternatives with the arrows, then closing it by changing focus. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({code: 'KeyA'}) + component.didKeydown({code: 'KeyA'}) + component.didKeyup({code: 'KeyA'}) + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionStart({data: ''}) + component.didCompositionUpdate({data: 'à'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xà') + component.didKeydown({code: 'ArrowRight'}) + component.didCompositionUpdate({data: 'á'}) + component.didKeyup({code: 'ArrowRight'}) + expect(editor.getText()).toBe('xá') + component.didCompositionUpdate({data: 'á'}) + component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) + expect(editor.getText()).toBe('xá') + // Ensure another "a" can be typed correctly. + component.didKeydown({code: 'KeyA'}) + component.didKeypress({code: 'KeyA'}) + component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeyup({code: 'KeyA'}) + expect(editor.getText()).toBe('xáa') + editor.undo() + expect(editor.getText()).toBe('x') + }) }) }) @@ -3546,6 +3769,7 @@ function buildComponent (params = {}) { rowsPerTile: params.rowsPerTile, updatedSynchronously: params.updatedSynchronously || false, platform: params.platform, + chromeVersion: params.chromeVersion, mouseWheelScrollSensitivity: params.mouseWheelScrollSensitivity }) const {element} = component @@ -3679,3 +3903,7 @@ function getElementHeight (element) { bottomRuler.remove() return height } + +function getNextTickPromise () { + return new Promise((resolve) => process.nextTick(resolve)) +} diff --git a/src/text-editor-component.js b/src/text-editor-component.js index a1867a931..d315df360 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -1644,7 +1644,7 @@ class TextEditorComponent { // 4. compositionend fired // 5. textInput fired; event.data == the completion string didCompositionStart () { - if (parseInt(process.versions.chrome) === 56) { + if (this.getChromeVersion() === 56) { this.getHiddenInput().value = '' } @@ -1655,7 +1655,7 @@ class TextEditorComponent { } didCompositionUpdate (event) { - if (parseInt(process.versions.chrome) === 56) { + if (this.getChromeVersion() === 56) { process.nextTick(() => { if (this.compositionCheckpoint) { const previewText = this.getHiddenInput().value @@ -2828,6 +2828,10 @@ class TextEditorComponent { getPlatform () { return this.props.platform || process.platform } + + getChromeVersion () { + return this.props.chromeVersion || parseInt(process.versions.chrome) + } } class DummyScrollbarComponent {