mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-04 09:27:53 +08:00
Summary: For returnKeyType 'go', 'search' and 'send' Android will call onEditorAction twice, once with IME_NULL and another time with the respective IME_ACTION. This change makes sure to only fire one onSubmitEditing by always returning true in onEditorAction, which causes no subsequent events to be fired by android. Fixes #10443 **Test plan** 1. Create view with TextInput having 'go', 'search' or 'send as `returnKeyType` ```javascript <View> <TextInput returnKeyType='search' onSubmitEditing={event => console.log('submit search')}></TextInput> <TextInput returnKeyType='go' onSubmitEditing={event => console.log('submit go')}></TextInput> <TextInput returnKeyType='send' onSubmitEditing={event => console.log('submit send')}></TextInput> </View> ``` 2. Input some text and click submit button in soft keyboard 3. See event fired only once instead of two times Closes https://github.com/facebook/react-native/pull/11006 Differential Revision: D4439110 Pulled By: hramos fbshipit-source-id: 5573b7f15f862b432600ddd3d61a0852ce51b2b3
260 lines
9.6 KiB
Java
260 lines
9.6 KiB
Java
/**
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
package com.facebook.react.tests;
|
|
|
|
import android.graphics.Color;
|
|
import android.text.style.ForegroundColorSpan;
|
|
import android.util.TypedValue;
|
|
import android.view.KeyEvent;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.inputmethod.EditorInfo;
|
|
import android.widget.EditText;
|
|
|
|
import com.facebook.react.bridge.JavaScriptModule;
|
|
import com.facebook.react.testing.ReactAppInstrumentationTestCase;
|
|
import com.facebook.react.testing.ReactInstanceSpecForTest;
|
|
import com.facebook.react.testing.StringRecordingModule;
|
|
import com.facebook.react.uimanager.PixelUtil;
|
|
import com.facebook.react.views.textinput.ReactEditText;
|
|
|
|
/**
|
|
* Test to verify that TextInput renders correctly
|
|
*/
|
|
public class TextInputTestCase extends ReactAppInstrumentationTestCase {
|
|
|
|
private final StringRecordingModule mRecordingModule = new StringRecordingModule();
|
|
|
|
private interface TextInputTestModule extends JavaScriptModule {
|
|
void setValueRef(String ref, String value);
|
|
}
|
|
|
|
/**
|
|
* Test that the actual height of the text input is not dependant on the font size of the text
|
|
* within.
|
|
*/
|
|
public void testTextInputMeasurements() {
|
|
View textInputViewHeightSet = getViewByTestId("textInput1");
|
|
EditText textInputViewNoHeight = getViewByTestId("textInput2");
|
|
|
|
int expectedHeight = Math.round(PixelUtil.toPixelFromDIP(30));
|
|
assertEquals(expectedHeight, textInputViewHeightSet.getHeight());
|
|
|
|
EditText editText = new EditText(textInputViewNoHeight.getContext());
|
|
editText.setTextSize(
|
|
TypedValue.COMPLEX_UNIT_PX,
|
|
(float) Math.ceil(PixelUtil.toPixelFromSP(21.f)));
|
|
editText.setPadding(0, 0, 0, 0);
|
|
int measureSpec = View.MeasureSpec.makeMeasureSpec(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
View.MeasureSpec.UNSPECIFIED);
|
|
editText.measure(measureSpec, measureSpec);
|
|
|
|
assertEquals(editText.getMeasuredHeight(), textInputViewNoHeight.getHeight());
|
|
}
|
|
|
|
/**
|
|
* Test that the cursor moves to the end of the word.
|
|
*/
|
|
public void testTextInputCursorPosition() throws Throwable {
|
|
final EditText textInputWithText = getViewByTestId("textInput3");
|
|
|
|
runTestOnUiThread(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
textInputWithText.setSelection(3);
|
|
}
|
|
});
|
|
getReactContext().getJSModule(TextInputTestModule.class)
|
|
.setValueRef("textInput3", "Some other value");
|
|
waitForBridgeAndUIIdle();
|
|
|
|
assertEquals(4, textInputWithText.getSelectionStart());
|
|
assertEquals(4, textInputWithText.getSelectionEnd());
|
|
}
|
|
|
|
/**
|
|
* Test that the colors are applied to new text
|
|
*/
|
|
public void testTextInputColors() throws Throwable {
|
|
String testIDs[] = new String[] {"textInput4", "textInput5", "textInput6"};
|
|
|
|
for (String testID : testIDs) {
|
|
getReactContext().getJSModule(TextInputTestModule.class).setValueRef(testID, "NewText");
|
|
}
|
|
waitForBridgeAndUIIdle();
|
|
|
|
for (String testID : testIDs) {
|
|
ReactEditText reactEditText = getViewByTestId(testID);
|
|
assertEquals(
|
|
Color.GREEN,
|
|
reactEditText.getText().getSpans(0, 1, ForegroundColorSpan.class)[0]
|
|
.getForegroundColor());
|
|
}
|
|
}
|
|
|
|
public void testOnSubmitEditing() throws Throwable {
|
|
String testId = "onSubmitTextInput";
|
|
ReactEditText reactEditText = getViewByTestId(testId);
|
|
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_GO);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_DONE);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_NEXT);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_PREVIOUS);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_SEARCH);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_SEND);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_UNSPECIFIED);
|
|
fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_NONE);
|
|
}
|
|
|
|
private void fireEditorActionAndCheckRecording(final ReactEditText reactEditText,
|
|
final int actionId) throws Throwable {
|
|
fireEditorActionAndCheckRecording(reactEditText, actionId, true);
|
|
fireEditorActionAndCheckRecording(reactEditText, actionId, false);
|
|
}
|
|
|
|
private void fireEditorActionAndCheckRecording(final ReactEditText reactEditText,
|
|
final int actionId,
|
|
final boolean blurOnSubmit) throws Throwable {
|
|
mRecordingModule.reset();
|
|
|
|
runTestOnUiThread(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
reactEditText.requestFocusFromJS();
|
|
reactEditText.setBlurOnSubmit(blurOnSubmit);
|
|
reactEditText.onEditorAction(actionId);
|
|
}
|
|
});
|
|
waitForBridgeAndUIIdle();
|
|
|
|
assertEquals(1, mRecordingModule.getCalls().size());
|
|
assertEquals(!blurOnSubmit, reactEditText.isFocused());
|
|
}
|
|
|
|
/**
|
|
* Test that the mentions input has colors displayed correctly.
|
|
* Removed for being flaky in open source, December 2016
|
|
public void testMetionsInputColors() throws Throwable {
|
|
EventDispatcher eventDispatcher =
|
|
getReactContext().getNativeModule(UIManagerModule.class).getEventDispatcher();
|
|
ReactEditText reactEditText = getViewByTestId("tokenizedInput");
|
|
String newText = "#Things and more #things";
|
|
int contentWidth = reactEditText.getWidth();
|
|
int contentHeight = reactEditText.getHeight();
|
|
int start = 0;
|
|
int count = newText.length();
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextChangedEvent(
|
|
reactEditText.getId(),
|
|
newText.toString(),
|
|
(int) PixelUtil.toDIPFromPixel(contentWidth),
|
|
(int) PixelUtil.toDIPFromPixel(contentHeight),
|
|
reactEditText.incrementAndGetEventCounter()));
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextInputEvent(
|
|
reactEditText.getId(),
|
|
newText.toString(),
|
|
"",
|
|
start,
|
|
start + count - 1));
|
|
waitForBridgeAndUIIdle();
|
|
|
|
ForegroundColorSpan[] spans = reactEditText
|
|
.getText().getSpans(0, reactEditText.getText().length(), ForegroundColorSpan.class);
|
|
assertEquals(2, spans.length);
|
|
assertEquals(spans[0].getForegroundColor(), spans[1].getForegroundColor());
|
|
assertEquals(0, reactEditText.getText().getSpanStart(spans[1]));
|
|
assertEquals(7, reactEditText.getText().getSpanEnd(spans[1]));
|
|
assertEquals(newText.length() - 7, reactEditText.getText().getSpanStart(spans[0]));
|
|
assertEquals(newText.length(), reactEditText.getText().getSpanEnd(spans[0]));
|
|
|
|
String moreText = "andsuch ";
|
|
String previousText = newText;
|
|
newText += moreText;
|
|
count = moreText.length();
|
|
start = previousText.length();
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextChangedEvent(
|
|
reactEditText.getId(),
|
|
newText.toString(),
|
|
(int) PixelUtil.toDIPFromPixel(contentWidth),
|
|
(int) PixelUtil.toDIPFromPixel(contentHeight),
|
|
reactEditText.incrementAndGetEventCounter()));
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextInputEvent(
|
|
reactEditText.getId(),
|
|
moreText,
|
|
"",
|
|
start,
|
|
start + count - 1));
|
|
waitForBridgeAndUIIdle();
|
|
|
|
spans = reactEditText.getText()
|
|
.getSpans(0, reactEditText.getText().length(), ForegroundColorSpan.class);
|
|
assertEquals(2, spans.length);
|
|
assertEquals(spans[0].getForegroundColor(), spans[1].getForegroundColor());
|
|
assertEquals(0, reactEditText.getText().getSpanStart(spans[1]));
|
|
assertEquals(7, reactEditText.getText().getSpanEnd(spans[1]));
|
|
assertEquals(newText.length() - 15, reactEditText.getText().getSpanStart(spans[0]));
|
|
assertEquals(newText.length() - 1, reactEditText.getText().getSpanEnd(spans[0]));
|
|
|
|
moreText = "morethings";
|
|
previousText = newText;
|
|
newText += moreText;
|
|
count = moreText.length();
|
|
start = previousText.length();
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextChangedEvent(
|
|
reactEditText.getId(),
|
|
newText.toString(),
|
|
(int) PixelUtil.toDIPFromPixel(contentWidth),
|
|
(int) PixelUtil.toDIPFromPixel(contentHeight),
|
|
reactEditText.incrementAndGetEventCounter()));
|
|
|
|
eventDispatcher.dispatchEvent(
|
|
new ReactTextInputEvent(
|
|
reactEditText.getId(),
|
|
moreText,
|
|
"",
|
|
start,
|
|
start + count - 1));
|
|
waitForBridgeAndUIIdle();
|
|
|
|
spans = reactEditText.getText()
|
|
.getSpans(0, reactEditText.getText().length(), ForegroundColorSpan.class);
|
|
assertEquals(spans[0].getForegroundColor(), spans[1].getForegroundColor());
|
|
assertEquals(2, spans.length);
|
|
assertEquals(0, reactEditText.getText().getSpanStart(spans[1]));
|
|
assertEquals(7, reactEditText.getText().getSpanEnd(spans[1]));
|
|
assertEquals(newText.length() - 25, reactEditText.getText().getSpanStart(spans[0]));
|
|
assertEquals(newText.length() - 11, reactEditText.getText().getSpanEnd(spans[0]));
|
|
}
|
|
*/
|
|
|
|
@Override
|
|
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
|
|
return super.createReactInstanceSpecForTest()
|
|
.addJSModule(TextInputTestModule.class)
|
|
.addNativeModule(mRecordingModule);
|
|
}
|
|
|
|
@Override
|
|
protected String getReactApplicationKeyUnderTest() {
|
|
return "TextInputTestApp";
|
|
}
|
|
}
|