Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[file_selector_web] Migrated to null-safety #3550

Merged
merged 22 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/file_selector/file_selector_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
21 changes: 21 additions & 0 deletions packages/file_selector/file_selector_web/example/README.md
Original file line number Diff line number Diff line change
@@ -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`
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,27 @@
// 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';
import 'package:file_selector_web/src/dom_helper.dart';
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;
FileUploadInputElement? input;
ditman marked this conversation as resolved.
Show resolved Hide resolved

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.dispatchEvent(Event('change'));
input!.files = createFileList(files);
input!.dispatchEvent(Event('change'));
}

setUp(() {
Expand Down Expand Up @@ -87,17 +85,17 @@ void main() {
bool wasClicked = false;

//ignore: unawaited_futures
input.onClick.first.then((_) => wasClicked = true);
input!.onClick.first.then((_) => wasClicked = true);

final futureFile = domHelper.getFiles(
accept: accept,
multiple: multiple,
input: input,
);

expect(input.matchesWithAncestors('body'), true);
expect(input.accept, accept);
expect(input.multiple, multiple);
expect(input!.matchesWithAncestors('body'), true);
expect(input!.accept, accept);
expect(input!.multiple, multiple);
expect(
wasClicked,
true,
Expand All @@ -109,7 +107,7 @@ void main() {
await futureFile;

// It should be already removed from the DOM after the file is resolved.
expect(input.parent, isNull);
expect(input!.parent, isNull);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -15,30 +13,25 @@ import 'package:file_selector_web/src/dom_helper.dart';
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'],
mimeTypes: ['image/png'],
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);
Expand All @@ -49,20 +42,22 @@ void main() {
});

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);
Expand All @@ -81,7 +76,36 @@ void main() {
});
}

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);
Expand Down
25 changes: 25 additions & 0 deletions packages/file_selector/file_selector_web/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -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!'),
);
}
}
21 changes: 21 additions & 0 deletions packages/file_selector/file_selector_web/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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-0 <3.0.0"
ditman marked this conversation as resolved.
Show resolved Hide resolved
flutter: ">=1.26.0-0" # For integration_test from sdk
ditman marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions packages/file_selector/file_selector_web/example/web/index.html
Original file line number Diff line number Diff line change
@@ -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>
34 changes: 17 additions & 17 deletions packages/file_selector/file_selector_web/lib/file_selector_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'package:file_selector_web/src/utils.dart';
///
/// 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) {
Expand All @@ -23,46 +23,46 @@ class FileSelectorWeb extends FileSelectorPlatform {
/// 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;
}

@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);
Expand Down
Loading