diff --git a/packages/flutter/lib/src/services/shell.dart b/packages/flutter/lib/src/services/shell.dart index 88b21403379..3f3f4112dff 100644 --- a/packages/flutter/lib/src/services/shell.dart +++ b/packages/flutter/lib/src/services/shell.dart @@ -18,15 +18,33 @@ ApplicationConnection _initConnection() { return new ApplicationConnection(null, serviceProvider); } +// A replacement for requestService. Implementations should return true +// if they handled the request, or false if the request should fall through +// to the default requestService. +typedef bool OverrideRequestService(String url, Object proxy); + +// Set this to intercept calls to requestService and supply an alternative +// implementation of a service (for example, a mock for testing). +OverrideRequestService overrideRequestService; + class _ShellImpl { _ShellImpl._(); final ApplicationConnection _connection = _initConnection(); - void requestService(String url, Object proxy) { + void _requestService(String url, Object proxy) { if (embedder.shell == null) _connection.requestService(proxy); else embedder.connectToService(url, proxy); } + + void requestService(String url, Object proxy) { + if (overrideRequestService != null) { + if (overrideRequestService(url, proxy)) + return; + } + + _requestService(url, proxy); + } } final _ShellImpl shell = new _ShellImpl._(); diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 82794c92678..3280da4c235 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -205,7 +205,7 @@ class EditableText extends StatefulComponent { if (!value.composing.isValid) { // TODO(eseidel): This is the wrong height if empty! - return new Text(value.text, style: style); + return new Row([new Text(value.text, style: style)]); } TextStyle composingStyle = style.merge(const TextStyle(decoration: underline)); diff --git a/packages/unit/test/services/mock_services.dart b/packages/unit/test/services/mock_services.dart new file mode 100644 index 00000000000..264d597f55f --- /dev/null +++ b/packages/unit/test/services/mock_services.dart @@ -0,0 +1,31 @@ +import 'package:sky/src/services/shell.dart' as shell; + +// Tests can use ServiceMocker to register replacement implementations +// of Mojo services. +class _ServiceMocker { + _ServiceMocker() { + shell.overrideRequestService = _requestService; + } + + // Map of interface names to mock implementations. + Map _interfaceMock = new Map(); + + bool _requestService(String url, Object proxy) { + Object mock = _interfaceMock[proxy.impl.name]; + if (mock != null) { + // Replace the proxy's implementation of the service interface with the + // mock. + proxy.ptr = mock; + return true; + } else { + return false; + } + } + + // Provide a mock implementation for a Mojo interface. + void registerMockService(String interfaceName, Object mock) { + _interfaceMock[interfaceName] = mock; + } +} + +final _ServiceMocker serviceMocker = new _ServiceMocker(); diff --git a/packages/unit/test/widget/input_test.dart b/packages/unit/test/widget/input_test.dart new file mode 100644 index 00000000000..7628ccd1aa5 --- /dev/null +++ b/packages/unit/test/widget/input_test.dart @@ -0,0 +1,59 @@ +import 'package:mojo_services/keyboard/keyboard.mojom.dart'; +import 'package:sky/services.dart'; +import 'package:sky/widgets.dart'; +import 'package:test/test.dart'; + +import 'widget_tester.dart'; +import '../services/mock_services.dart'; + +class MockKeyboard implements KeyboardService { + KeyboardClient client; + + void show(Object client, int type) { + this.client = client.impl; + } + + void showByRequest() {} + + void hide() {} +} + +void main() { + test('Editable text has consistent width', () { + WidgetTester tester = new WidgetTester(); + + MockKeyboard mockKeyboard = new MockKeyboard(); + serviceMocker.registerMockService(KeyboardServiceName, mockKeyboard); + + GlobalKey inputKey = new GlobalKey(); + String inputValue; + + Widget builder() { + return new Center( + child: new Input( + key: inputKey, + placeholder: 'Placeholder', + onChanged: (value) { inputValue = value; } + ) + ); + } + + tester.pumpFrame(builder); + + Input input = tester.findWidget((Widget widget) => widget.key == inputKey); + Size emptyInputSize = input.renderObject.size; + + // Simulate entry of text through the keyboard. + expect(mockKeyboard.client, isNotNull); + const String testValue = 'Test'; + mockKeyboard.client.setComposingText(testValue, testValue.length); + + // Check that the onChanged event handler fired. + expect(inputValue, equals(testValue)); + + tester.pumpFrame(builder); + + // Check that the Input with text has the same size as the empty Input. + expect(input.renderObject.size, equals(emptyInputSize)); + }); +}