diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index cfaf814c65c1..68664ae7b6d4 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -13,14 +13,15 @@ final String _kAcceptVideoMimeType = 'video/*'; /// /// This class implements the `package:image_picker` functionality for the web. class ImagePickerPlugin extends ImagePickerPlatform { + final Function _overrideCreateInput; + bool get _shouldOverrideInput => _overrideCreateInput != null; + html.Element _target; - /// A constructor that allows tests to override the window object used by the plugin. - ImagePickerPlugin({@visibleForTesting html.Element target}) - : _target = target { - if (_target == null) { - _target = _initTarget(_kImagePickerInputsDomId); - } + /// A constructor that allows tests to override the function that creates file inputs. + ImagePickerPlugin({@visibleForTesting Function overrideCreateInput}) + : _overrideCreateInput = overrideCreateInput { + _target = _initTarget(_kImagePickerInputsDomId); } /// Registers this class as the default instance of [ImagePickerPlatform]. @@ -122,6 +123,10 @@ class ImagePickerPlugin extends ImagePickerPlatform { html.Element _createInputElement(String accept, String capture) { html.Element element; + if (_shouldOverrideInput) { + return _overrideCreateInput(accept, capture); + } + if (capture != null) { // Capture is not supported by dart:html :/ element = html.Element.html( @@ -137,8 +142,10 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// Injects the file input element, and clicks on it void _injectAndActivate(html.Element element) { - _target.children.clear(); - _target.children.add(element); + if (!_shouldOverrideInput) { + _target.children.clear(); + _target.children.add(element); + } element.click(); } } diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart index 678dba4a5a30..0bc6adfe775c 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -4,12 +4,74 @@ @TestOn('chrome') // Uses web-only Flutter SDK +import 'dart:async'; +import 'dart:convert'; import 'dart:html' as html; +import 'dart:typed_data'; + import 'package:flutter_test/flutter_test.dart'; +import 'package:image_picker_for_web/image_picker_for_web.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; import 'package:mockito/mockito.dart'; -class MockWindow extends Mock implements html.Window {} +final String expectedStringContents = "Hello, world!"; +final Uint8List bytes = utf8.encode(expectedStringContents); +final html.File textFile = html.File([bytes], "hello.txt"); + +class MockFileInput extends Mock implements html.FileUploadInputElement {} + +class MockOnChangeEvent extends Mock implements html.Event { + @override + MockFileInput target; +} + +class MockElementStream extends Mock + implements html.ElementStream { + final StreamController controller = StreamController(); + @override + StreamSubscription listen(void onData(T event), + {Function onError, void onDone(), bool cancelOnError}) { + return controller.stream.listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); + } +} void main() { + MockFileInput mockInput = MockFileInput(); + MockElementStream mockStream = MockElementStream(); + MockElementStream mockErrorStream = MockElementStream(); + MockOnChangeEvent mockEvent = MockOnChangeEvent()..target = mockInput; + + // Under test... + ImagePickerPlugin plugin = + ImagePickerPlugin(overrideCreateInput: (_, __) => mockInput); + + setUp(() { + // Make the mockInput behave like a proper input... + when(mockInput.onChange).thenAnswer((_) => mockStream); + when(mockInput.onError).thenAnswer((_) => mockErrorStream); + }); + + tearDown(() { + reset(mockInput); + }); + + // Pick a file... + test('Can select a file, happy case', () async { + // Init the pick file dialog... + final file = plugin.pickImage( + source: ImageSource.gallery, + ); + + // Mock the browser behavior of selecting a file... + when(mockInput.files).thenReturn([textFile]); + mockStream.controller.add(mockEvent); + + // Now the file should be selected + expect(file, completes); + // And readable + expect((await file).readAsString(), completion(expectedStringContents)); + }); + // Creates the correct DOM for the input... }