[file_selector_web] Migrated to null-safety (#3550)
Co-authored-by: David Iglesias Teixeira <ditman@gmail.com>
diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md
index 619aa76..4caad4b 100644
--- a/packages/file_selector/file_selector_web/CHANGELOG.md
+++ b/packages/file_selector/file_selector_web/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.8.0
+
+- Migrated to null-safety
+
# 0.7.0+1
- Add dummy `ios` dir, so flutter sdk can be lower than 1.20
diff --git a/packages/file_selector/file_selector_web/example/README.md b/packages/file_selector/file_selector_web/example/README.md
new file mode 100644
index 0000000..6187e55
--- /dev/null
+++ b/packages/file_selector/file_selector_web/example/README.md
@@ -0,0 +1,21 @@
+# Testing
+
+This package utilizes the `integration_test` package to run its tests in a web browser.
+
+See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info.
+
+## Running the tests
+
+Make sure you have updated to the latest Flutter master.
+
+1. Check what version of Chrome is running on the machine you're running tests on.
+
+2. Download and install driver for that version from here:
+ * <https://chromedriver.chromium.org/downloads>
+
+3. Start the driver using `chromedriver --port=4444`
+
+4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_test.dart --target=integration_test/TEST_NAME.dart`, or (in Linux):
+
+ * Single: `./run_test.sh integration_test/TEST_NAME.dart`
+ * All: `./run_test.sh`
diff --git a/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart
similarity index 91%
rename from packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart
rename to packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart
index a942c0d..274aed9 100644
--- a/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart
+++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// @dart = 2.9
-
import 'dart:html';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -11,19 +9,19 @@
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
void main() {
- group('FileSelectorWeb', () {
+ group('dom_helper', () {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
- DomHelper domHelper;
- FileUploadInputElement input;
+ late DomHelper domHelper;
+ late FileUploadInputElement input;
- FileList FileListItems(List<File> files) {
+ FileList? createFileList(List<File> files) {
final dataTransfer = DataTransfer();
- files.forEach(dataTransfer.items.add);
- return dataTransfer.files;
+ files.forEach(dataTransfer.items!.add);
+ return dataTransfer.files as FileList?;
}
void setFilesAndTriggerChange(List<File> files) {
- input.files = FileListItems(files);
+ input.files = createFileList(files);
input.dispatchEvent(Event('change'));
}
diff --git a/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart
similarity index 60%
rename from packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart
rename to packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart
index abd31dd..5442fed 100644
--- a/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart
+++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart
@@ -2,11 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// @dart = 2.9
-
+import 'dart:html';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
-import 'package:mockito/mockito.dart';
import 'package:integration_test/integration_test.dart';
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
import 'package:file_selector_web/file_selector_web.dart';
@@ -15,18 +13,18 @@
void main() {
group('FileSelectorWeb', () {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
- MockDomHelper mockDomHelper;
- FileSelectorWeb plugin;
-
- setUp(() {
- mockDomHelper = MockDomHelper();
- plugin = FileSelectorWeb(domHelper: mockDomHelper);
- });
group('openFile', () {
- final mockFile = createXFile('1001', 'identity.png');
-
testWidgets('works', (WidgetTester _) async {
+ final mockFile = createXFile('1001', 'identity.png');
+
+ final mockDomHelper = MockDomHelper()
+ ..setFiles([mockFile])
+ ..expectAccept('.jpg,.jpeg,image/png,image/*')
+ ..expectMultiple(false);
+
+ final plugin = FileSelectorWeb(domHelper: mockDomHelper);
+
final typeGroup = XTypeGroup(
label: 'images',
extensions: ['jpg', 'jpeg'],
@@ -34,11 +32,6 @@
webWildCards: ['image/*'],
);
- when(mockDomHelper.getFiles(
- accept: '.jpg,.jpeg,image/png,image/*',
- multiple: false,
- )).thenAnswer((_) async => [mockFile]);
-
final file = await plugin.openFile(acceptedTypeGroups: [typeGroup]);
expect(file.name, mockFile.name);
@@ -49,20 +42,22 @@
});
group('openFiles', () {
- final mockFile1 = createXFile('123456', 'file1.txt');
- final mockFile2 = createXFile('', 'file2.txt');
-
testWidgets('works', (WidgetTester _) async {
+ final mockFile1 = createXFile('123456', 'file1.txt');
+ final mockFile2 = createXFile('', 'file2.txt');
+
+ final mockDomHelper = MockDomHelper()
+ ..setFiles([mockFile1, mockFile2])
+ ..expectAccept('.txt')
+ ..expectMultiple(true);
+
+ final plugin = FileSelectorWeb(domHelper: mockDomHelper);
+
final typeGroup = XTypeGroup(
label: 'files',
extensions: ['.txt'],
);
- when(mockDomHelper.getFiles(
- accept: '.txt',
- multiple: true,
- )).thenAnswer((_) async => [mockFile1, mockFile2]);
-
final files = await plugin.openFiles(acceptedTypeGroups: [typeGroup]);
expect(files.length, 2);
@@ -81,7 +76,36 @@
});
}
-class MockDomHelper extends Mock implements DomHelper {}
+class MockDomHelper implements DomHelper {
+ List<XFile> _files = <XFile>[];
+ String _expectedAccept = '';
+ bool _expectedMultiple = false;
+
+ @override
+ Future<List<XFile>> getFiles({
+ String accept = '',
+ bool multiple = false,
+ FileUploadInputElement? input,
+ }) {
+ expect(accept, _expectedAccept,
+ reason: 'Expected "accept" value does not match.');
+ expect(multiple, _expectedMultiple,
+ reason: 'Expected "multiple" value does not match.');
+ return Future.value(_files);
+ }
+
+ void setFiles(List<XFile> files) {
+ _files = files;
+ }
+
+ void expectAccept(String accept) {
+ _expectedAccept = accept;
+ }
+
+ void expectMultiple(bool multiple) {
+ _expectedMultiple = multiple;
+ }
+}
XFile createXFile(String content, String name) {
final data = Uint8List.fromList(content.codeUnits);
diff --git a/packages/file_selector/file_selector_web/example/lib/main.dart b/packages/file_selector/file_selector_web/example/lib/main.dart
new file mode 100644
index 0000000..e1a38dc
--- /dev/null
+++ b/packages/file_selector/file_selector_web/example/lib/main.dart
@@ -0,0 +1,25 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+void main() {
+ runApp(MyApp());
+}
+
+/// App for testing
+class MyApp extends StatefulWidget {
+ @override
+ _MyAppState createState() => _MyAppState();
+}
+
+class _MyAppState extends State<MyApp> {
+ @override
+ Widget build(BuildContext context) {
+ return Directionality(
+ textDirection: TextDirection.ltr,
+ child: Text('Testing... Look at the console output for results!'),
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_web/example/pubspec.yaml b/packages/file_selector/file_selector_web/example/pubspec.yaml
new file mode 100644
index 0000000..cae4b13
--- /dev/null
+++ b/packages/file_selector/file_selector_web/example/pubspec.yaml
@@ -0,0 +1,21 @@
+name: file_selector_web_integration_tests
+publish_to: none
+
+dependencies:
+ flutter:
+ sdk: flutter
+
+dev_dependencies:
+ build_runner: ^1.10.0
+ file_selector_web:
+ path: ../
+ flutter_driver:
+ sdk: flutter
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+environment:
+ sdk: ">=2.12.0-259.9.beta <3.0.0"
+ flutter: ">=1.27.0-0" # For integration_test from sdk
diff --git a/packages/file_selector/file_selector_web/run_integration_test b/packages/file_selector/file_selector_web/example/run_test.sh
similarity index 100%
rename from packages/file_selector/file_selector_web/run_integration_test
rename to packages/file_selector/file_selector_web/example/run_test.sh
diff --git a/packages/file_selector/file_selector_web/test_driver/integration_test.dart b/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart
similarity index 100%
rename from packages/file_selector/file_selector_web/test_driver/integration_test.dart
rename to packages/file_selector/file_selector_web/example/test_driver/integration_test.dart
diff --git a/packages/file_selector/file_selector_web/example/web/index.html b/packages/file_selector/file_selector_web/example/web/index.html
new file mode 100644
index 0000000..dc8d0cf
--- /dev/null
+++ b/packages/file_selector/file_selector_web/example/web/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<!-- Copyright 2014 The Flutter Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file. -->
+<html>
+ <head>
+ <title>Browser Tests</title>
+ </head>
+ <body>
+ <script src="main.dart.js"></script>
+ </body>
+</html>
diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart
index 48f57ee..1c411ca 100644
--- a/packages/file_selector/file_selector_web/lib/file_selector_web.dart
+++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart
@@ -13,7 +13,7 @@
///
/// This class implements the `package:file_selector` functionality for the web.
class FileSelectorWeb extends FileSelectorPlatform {
- final _domHelper;
+ final DomHelper _domHelper;
/// Registers this class as the default instance of [FileSelectorPlatform].
static void registerWith(Registrar registrar) {
@@ -23,14 +23,14 @@
/// Default constructor, initializes _domHelper that we can use
/// to interact with the DOM.
/// overrides parameter allows for testing to override functions
- FileSelectorWeb({@visibleForTesting DomHelper domHelper})
+ FileSelectorWeb({@visibleForTesting DomHelper? domHelper})
: _domHelper = domHelper ?? DomHelper();
@override
Future<XFile> openFile({
- List<XTypeGroup> acceptedTypeGroups,
- String initialDirectory,
- String confirmButtonText,
+ List<XTypeGroup>? acceptedTypeGroups,
+ String? initialDirectory,
+ String? confirmButtonText,
}) async {
final files = await _openFiles(acceptedTypeGroups: acceptedTypeGroups);
return files.first;
@@ -38,31 +38,31 @@
@override
Future<List<XFile>> openFiles({
- List<XTypeGroup> acceptedTypeGroups,
- String initialDirectory,
- String confirmButtonText,
+ List<XTypeGroup>? acceptedTypeGroups,
+ String? initialDirectory,
+ String? confirmButtonText,
}) async {
return _openFiles(acceptedTypeGroups: acceptedTypeGroups, multiple: true);
}
@override
- Future<String> getSavePath({
- List<XTypeGroup> acceptedTypeGroups,
- String initialDirectory,
- String suggestedName,
- String confirmButtonText,
+ Future<String?> getSavePath({
+ List<XTypeGroup>? acceptedTypeGroups,
+ String? initialDirectory,
+ String? suggestedName,
+ String? confirmButtonText,
}) async =>
null;
@override
- Future<String> getDirectoryPath({
- String initialDirectory,
- String confirmButtonText,
+ Future<String?> getDirectoryPath({
+ String? initialDirectory,
+ String? confirmButtonText,
}) async =>
null;
Future<List<XFile>> _openFiles({
- List<XTypeGroup> acceptedTypeGroups,
+ List<XTypeGroup>? acceptedTypeGroups,
bool multiple = false,
}) async {
final accept = acceptedTypesToString(acceptedTypeGroups);
diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart
index a965ceb..5c578b6 100644
--- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart
+++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart
@@ -14,7 +14,7 @@
/// Default constructor, initializes the container DOM element.
DomHelper() {
- final body = querySelector('body');
+ final body = querySelector('body')!;
body.children.add(_container);
}
@@ -22,42 +22,45 @@
Future<List<XFile>> getFiles({
String accept = '',
bool multiple = false,
- @visibleForTesting FileUploadInputElement input,
+ @visibleForTesting FileUploadInputElement? input,
}) {
- final Completer<List<XFile>> _completer = Completer();
- input = input ?? FileUploadInputElement();
+ final Completer<List<XFile>> completer = Completer();
+ final FileUploadInputElement inputElement =
+ input ?? FileUploadInputElement();
_container.children.add(
- input
+ inputElement
..accept = accept
..multiple = multiple,
);
- input.onChange.first.then((_) {
- final List<XFile> files = input.files.map(_convertFileToXFile).toList();
- input.remove();
- _completer.complete(files);
+ inputElement.onChange.first.then((_) {
+ final List<XFile> files =
+ inputElement.files!.map(_convertFileToXFile).toList();
+ inputElement.remove();
+ completer.complete(files);
});
- input.onError.first.then((event) {
- final ErrorEvent error = event;
+ inputElement.onError.first.then((event) {
+ final ErrorEvent error = event as ErrorEvent;
final platformException = PlatformException(
code: error.type,
message: error.message,
);
- input.remove();
- _completer.completeError(platformException);
+ inputElement.remove();
+ completer.completeError(platformException);
});
- input.click();
+ inputElement.click();
- return _completer.future;
+ return completer.future;
}
XFile _convertFileToXFile(File file) => XFile(
Url.createObjectUrl(file),
name: file.name,
length: file.size,
- lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified),
+ lastModified: DateTime.fromMillisecondsSinceEpoch(
+ file.lastModified ?? DateTime.now().millisecondsSinceEpoch),
);
}
diff --git a/packages/file_selector/file_selector_web/lib/src/utils.dart b/packages/file_selector/file_selector_web/lib/src/utils.dart
index 4ddd7dd..6be58c2 100644
--- a/packages/file_selector/file_selector_web/lib/src/utils.dart
+++ b/packages/file_selector/file_selector_web/lib/src/utils.dart
@@ -5,19 +5,19 @@
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
/// Convert list of XTypeGroups to a comma-separated string
-String acceptedTypesToString(List<XTypeGroup> acceptedTypes) {
+String acceptedTypesToString(List<XTypeGroup>? acceptedTypes) {
if (acceptedTypes == null) return '';
final List<String> allTypes = [];
for (final group in acceptedTypes) {
_assertTypeGroupIsValid(group);
if (group.extensions != null) {
- allTypes.addAll(group.extensions.map(_normalizeExtension));
+ allTypes.addAll(group.extensions!.map(_normalizeExtension));
}
if (group.mimeTypes != null) {
- allTypes.addAll(group.mimeTypes);
+ allTypes.addAll(group.mimeTypes!);
}
if (group.webWildCards != null) {
- allTypes.addAll(group.webWildCards);
+ allTypes.addAll(group.webWildCards!);
}
}
return allTypes.join(',');
@@ -26,9 +26,9 @@
/// Make sure that at least one of its fields is populated.
void _assertTypeGroupIsValid(XTypeGroup group) {
assert(
- !((group.extensions == null || group.extensions.isEmpty) &&
- (group.mimeTypes == null || group.mimeTypes.isEmpty) &&
- (group.webWildCards == null || group.webWildCards.isEmpty)),
+ !((group.extensions == null || group.extensions!.isEmpty) &&
+ (group.mimeTypes == null || group.mimeTypes!.isEmpty) &&
+ (group.webWildCards == null || group.webWildCards!.isEmpty)),
'At least one of extensions / mimeTypes / webWildCards is required for web.');
}
diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml
index a170d5f..55424a7 100644
--- a/packages/file_selector/file_selector_web/pubspec.yaml
+++ b/packages/file_selector/file_selector_web/pubspec.yaml
@@ -1,7 +1,7 @@
name: file_selector_web
description: Web platform implementation of file_selector
homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web
-version: 0.7.0+1
+version: 0.8.0
flutter:
plugin:
@@ -11,22 +11,18 @@
fileName: file_selector_web.dart
dependencies:
- file_selector_platform_interface: ^1.0.2
- platform_detect: ^1.4.0
+ file_selector_platform_interface: ^2.0.0
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter
- meta: ^1.1.7
+ meta: ^1.3.0
dev_dependencies:
flutter_test:
sdk: flutter
- mockito: ^4.1.1
- pedantic: ^1.8.0
- integration_test:
- path: ../../integration_test
+ pedantic: ^1.10.0
environment:
- sdk: ">=2.2.0 <3.0.0"
- flutter: ">=1.10.0"
+ sdk: ">=2.12.0-259.9.beta <3.0.0"
+ flutter: ">=1.20.0"
diff --git a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart
new file mode 100644
index 0000000..e9faa3a
--- /dev/null
+++ b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart
@@ -0,0 +1,10 @@
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ test('Tell the user where to find the real tests', () {
+ print('---');
+ print('This package also uses integration_test to run additional tests.');
+ print('See `example/README.md` for more info.');
+ print('---');
+ });
+}
diff --git a/packages/file_selector/file_selector_web/test/utils_test.dart b/packages/file_selector/file_selector_web/test/utils_test.dart
index 9fa187e..e3e47c0 100644
--- a/packages/file_selector/file_selector_web/test/utils_test.dart
+++ b/packages/file_selector/file_selector_web/test/utils_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// @dart = 2.9
-
import 'package:flutter_test/flutter_test.dart';
import 'package:file_selector_web/src/utils.dart';
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';