From 7bd9a08aad280aef4e538751f544bd4768bd9cab Mon Sep 17 00:00:00 2001 From: "alexey.kamaev" Date: Wed, 25 Apr 2018 10:02:41 +0300 Subject: [PATCH] fix textInput dispatch in safari --- .../automation/playback/type/type-text.js | 25 ++++++++++++++++--- .../fixtures/regression/gh-1956/test.js | 2 +- .../gh-1956/testcafe-fixtures/index.js | 4 +-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/client/automation/playback/type/type-text.js b/src/client/automation/playback/type/type-text.js index 67712f611fe..2da6a3555fc 100644 --- a/src/client/automation/playback/type/type-text.js +++ b/src/client/automation/playback/type/type-text.js @@ -104,16 +104,33 @@ function _excludeInvisibleSymbolsFromSelection (selection) { return selection; } -// NOTE: typing can be prevented in Chrome/Edge but can not be prevented in IE11 or Firefox +// NOTE: Typing can be prevented in Chrome/Edge but can not be prevented in IE11 or Firefox // Firefox does not support TextInput event -// Safari support TextInput event but adds e.data to node value. So let's ignore it +// Safari supports the TextInput event but has a bug: e.data is added to the node value. +// So in Safari we need to call preventDefault in the last textInput handler but not prevent the Input event + +let forceInputInSafari; + function simulateTextInput (element, text) { - const isTextInputIgnoredByBrowser = [ browserUtils.isFirefox, browserUtils.isSafari ].some(browser => browser); - const isInputEventRequired = isTextInputIgnoredByBrowser || eventSimulator.textInput(element, text); + forceInputInSafari = false; + + if (browserUtils.isSafari) + document.addEventListener('textInput', onSafariTextInput); + + const isInputEventRequired = browserUtils.isFirefox || eventSimulator.textInput(element, text) || forceInputInSafari; + + if (browserUtils.isSafari) + document.removeEventListener('textInput', onSafariTextInput); return isInputEventRequired || browserUtils.isIE11; } +function onSafariTextInput (e) { + forceInputInSafari = !e.defaultPrevented; + + e.preventDefault(); +} + function _typeTextToContentEditable (element, text) { var currentSelection = _getSelectionInElement(element); var startNode = currentSelection.startPos.node; diff --git a/test/functional/fixtures/regression/gh-1956/test.js b/test/functional/fixtures/regression/gh-1956/test.js index 66325503ece..97616caa660 100644 --- a/test/functional/fixtures/regression/gh-1956/test.js +++ b/test/functional/fixtures/regression/gh-1956/test.js @@ -1,6 +1,6 @@ var expect = require('chai').expect; -var browsersWithLimitations = [ 'ie', 'safari', 'firefox', 'firefox-osx', 'ipad', 'iphone' ]; +var browsersWithLimitations = [ 'ie', 'firefox', 'firefox-osx' ]; describe('Should support TextInput event[Regression](GH-1956)', function () { it('Prevent Input event on TextInput when type to input element', function () { diff --git a/test/functional/fixtures/regression/gh-1956/testcafe-fixtures/index.js b/test/functional/fixtures/regression/gh-1956/testcafe-fixtures/index.js index 87acf1a0488..3fad6c6d841 100644 --- a/test/functional/fixtures/regression/gh-1956/testcafe-fixtures/index.js +++ b/test/functional/fixtures/regression/gh-1956/testcafe-fixtures/index.js @@ -9,7 +9,7 @@ const contentEditableWithElementNode = Selector('#contentEditableWithElementNode const contentEditableWithModify = Selector('#contentEditableWithModify'); const contentEditableWithReplace = Selector('#contentEditableWithReplace'); -// NOTE: Chrome/Edge. Typing is prevented and Input event is not raised +// NOTE: Chrome/Edge/Safari. Typing is prevented and Input event is not raised test('Prevent Input event on TextInput when type to input element', async t => { await t .typeText(simpleInput, 'Hello') @@ -23,7 +23,7 @@ test('Prevent Input event on TextInput when type to input element IE11/Firefox', .expect(simpleInput.value).eql('Hello'); }); -// NOTE: Chrome/Edge. Typing is prevented. Input event is not raised +// NOTE: Chrome/Edge/Safari. Typing is prevented. Input event is not raised test('Prevent Input event on TextInput when type to ContentEditable div', async t => { await t .typeText(simpleContentEditable, 'Hello')