Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
runApp(MyApp());
Expand Down
2 changes: 1 addition & 1 deletion e2etests/web/regular_integration_tests/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: regular_integration_tests
publish_to: none

environment:
sdk: ">=2.2.2 <3.0.0"
sdk: ">=2.11.0-0 <3.0.0"

dependencies:
flutter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ void main() async {
await tester.tap(find.byKey(const Key('input')));
// Focus in input, otherwise clipboard will fail with
// 'document is not focused' platform exception.
html.document.querySelector('input').focus();
html.document.querySelector('input')?.focus();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ! instead of ?? I imagine the test should fail if it cannot find the input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks!

Copy link
Contributor Author

@nturgut nturgut Nov 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I'm getting the following error:

Target dart2js failed: Exception: test_driver/text_editing_integration.dart:43:29:
Error: Null safety features are disabled for this library.
    textFormField.controller!.text = 'New Value';

Looks like I will wait for these changes until the packet is moved to nnbd.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case you don't need to change this line at all, because querySelector('input').focus() in old Dart is the same as querySelector('input')!.focus() in new Dart.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'm getting this exception in debug mode:

org-dartlang-app:/platform_messages_integration.dart:31:42: Error: Method 'focus' cannot be called on 'Element?' because it is potentially null.
 - 'Element' is from 'dart:html'.                                       
Try calling using ?. instead.                                           
    html.document.querySelector('input').focus();   

The same tests passes in profile mode, so we didn't need this change before.

Let me know if you have any suggestions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonahwilliams For these tests we are seeing conflicting results for different modes:

  • debug mode has a nnbd error:
org-dartlang-app:/platform_messages_integration.dart:31:42: Error: Method 'focus' cannot be called on 'Element?' because it is potentially null.
 - 'Element' is from 'dart:html'.                                       
Try calling using ?. instead.                                           
    html.document.querySelector('input').focus();  
  • profile/release modes do not recognize nnbd:
Target dart2js failed: Exception: test_driver/text_editing_integration.dart:43:29:
Error: Null safety features are disabled for this library.

Any ideas?

@dnfield have you seen it this issue for other e2e tests?

await Clipboard.setData(const ClipboardData(text: 'sample text'));
}, skip: true); // https://github.com/flutter/flutter/issues/54296

testWidgets('Should create and dispose view embedder',
(WidgetTester tester) async {
int viewInstanceCount = 0;

final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
platformViewsRegistry.getNextPlatformViewId();
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory('MyView', (int viewId) {
++viewInstanceCount;
Expand All @@ -46,14 +46,11 @@ void main() async {
app.main();
await tester.pumpAndSettle();
final Map<String, dynamic> createArgs = <String, dynamic>{
'id': '567',
'id': 567,
'viewType': 'MyView',
};
await SystemChannels.platform_views.invokeMethod<void>('create', createArgs);
final Map<String, dynamic> disposeArgs = <String, dynamic>{
'id': '567',
};
await SystemChannels.platform_views.invokeMethod<void>('dispose', disposeArgs);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ferhatb @yjbanov @hterkelsen

I'm trying to run these tests on different modes. This error really confused me. Unless I change the arguments for dispose only with an integer, I'm getting the following stack trace:

Failure in method: Should create and dispose view embedder
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞═════════════════
The following TypeErrorImpl was thrown running a test:
Expected a value of type 'int', but got one of type
'LinkedMap<dynamic, dynamic>'

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 216:49      throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 64:3        castError
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 442:10  cast
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 204:12                as
lib/ui/ui.dart 139:13                                                             _disposePlatformView
lib/ui/ui.dart 108:7                                                              handlePlatformViewCall
lib/_engine/engine/platform_dispatcher.dart 380:11                                [_sendPlatformMessage]
lib/_engine/engine/platform_dispatcher.dart 216:5                                 sendPlatformMessage
lib/ui/src/ui/window.dart 116:24                                                  sendPlatformMessage
packages/flutter/src/services/system_channels.dart.js 2184:17                     [_sendPlatformMessage]
packages/flutter/src/services/system_channels.dart.js 2228:40                     send
packages/flutter_test/src/_matchers_web.dart.js 3264:40                           send
packages/flutter/src/services/system_channels.dart.js 938:50                      _invokeMethod
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54                runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:12               _async
packages/flutter/src/services/system_channels.dart.js 936:20                      [_invokeMethod]
packages/flutter/src/services/system_channels.dart.js 950:33                      invokeMethod
platform_messages_integration.dart.js 79:63                                       <fn>
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 45:50                <fn>
packages/stack_trace/src/stack_zone_specification.dart.js 163:98                  <fn>
packages/stack_trace/src/stack_zone_specification.dart.js 231:16                  [_run]
packages/stack_trace/src/stack_zone_specification.dart.js 163:80                  <fn>
dart-sdk/lib/async/zone.dart 1198:47                                              _rootRunUnary
dart-sdk/lib/async/zone.dart 1100:19                                              runUnary
dart-sdk/lib/async/future_impl.dart 143:18                                        handleValue
dart-sdk/lib/async/future_impl.dart 696:44                                        handleValueCallback
dart-sdk/lib/async/future_impl.dart 725:32                                        _propagateToListeners
dart-sdk/lib/async/future_impl.dart 529:5                                         [_completeWithValue]
dart-sdk/lib/async/future_impl.dart 567:7                                         <fn>
packages/stack_trace/src/stack_zone_specification.dart.js 231:16                  [_run]
packages/stack_trace/src/stack_zone_specification.dart.js 154:71                  <fn>
dart-sdk/lib/async/zone.dart 1190:13                                              _rootRun
dart-sdk/lib/async/zone.dart 1093:19                                              run
dart-sdk/lib/async/zone.dart 997:7                                                runGuarded
dart-sdk/lib/async/zone.dart 1037:23                                              callback
dart-sdk/lib/async/schedule_microtask.dart 41:11                                  _microtaskLoop
dart-sdk/lib/async/schedule_microtask.dart 50:5                                   _startMicrotaskLoop
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15               <fn>

The test description was:
  Should create and dispose view embedder

However when I read the framework code the arguments are also send as a <String, dynamic> map: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/services/platform_views.dart#L945

Do you have any opinion on this type error? (I think there can be some other breakages in the code, if the <String, dynamic> is the correct argument set but started causing an error due to a recent change`)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I don't why it didn't fail before. According to the logic in _disposePlatformView we are expecting an int, not a map: final int id = methodCall.arguments;

Is it possible that this test was failing before but the failure didn't register?

await SystemChannels.platform_views.invokeMethod<void>('dispose', 567);
expect(viewInstanceCount, 1);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import 'package:flutter/material.dart';
import 'package:integration_test/integration_test.dart';

void main() {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;

testWidgets('Focused text field creates a native input element',
(WidgetTester tester) async {
Expand All @@ -38,7 +40,7 @@ void main() {

// Change the value of the TextFormField.
final TextFormField textFormField = tester.widget(finder);
textFormField.controller.text = 'New Value';
textFormField.controller?.text = 'New Value';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use ! instead? Is it a valid situation that textFormField.controller is null?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if textFormField.controller is null? Does it just skip the assignment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Getting an error in this case is better.

@mdebbar Yes, it does not give an error, no assignment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, if this is not null safe code, you shouldn't need to change this line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated above the reason of the change is the tests are not able to run in debug mode otherwise.

// DOM element's value also changes.
expect(input.value, 'New Value');

Expand Down Expand Up @@ -68,7 +70,7 @@ void main() {

// Change the value of the TextFormField.
final TextFormField textFormField = tester.widget(finder);
textFormField.controller.text = 'New Value';
textFormField.controller?.text = 'New Value';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated above the reason of the change is the tests are not able to run in debug mode otherwise.

// DOM element's value also changes.
expect(input.value, 'New Value');
});
Expand Down Expand Up @@ -145,9 +147,9 @@ void main() {
expect(input2.value, 'Text2');
});

testWidgets('Jump between TextFormFields with tab key after CapsLock is'
'activated',
(WidgetTester tester) async {
testWidgets(
'Jump between TextFormFields with tab key after CapsLock is'
'activated', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();

Expand All @@ -163,7 +165,7 @@ void main() {
final List<Node> nodeList = document.getElementsByTagName('input');
expect(nodeList.length, equals(1));
final InputElement input =
document.getElementsByTagName('input')[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;

// Press and release CapsLock.
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
Expand Down Expand Up @@ -207,7 +209,7 @@ void main() {
// A native input element for the next TextField should be attached to the
// DOM.
final InputElement input2 =
document.getElementsByTagName('input')[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
expect(input2.value, 'Text2');
});

Expand Down Expand Up @@ -243,8 +245,8 @@ void main() {
expect(input.hasAttribute('readonly'), isTrue);

// Make sure the entire text is selected.
TextRange range =
TextRange(start: input.selectionStart, end: input.selectionEnd);
TextRange range = TextRange(
start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?? is essentially an if/else, which means two paths are possible, one when input.selectionStart is null and another when it isn't. However, a test is only executed once, which means only one situation should be possible, and the other situation is likely a failure of some sort.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it does not change the result for one this particular method is covering. This is an integration tests, the other conditions related to text selection ranges are covered in the unit tests.

The purpose of the test is to see if the text in the selection range is 'Lorem'. Whether input.end being null or 0 will give the same outcome, since the selection range won't be 'Lorem' in either case, this method should fail.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is input being null semantically equivalent to input.end being 0? Or would it indicate a bug in the framework? If it's the latter, then failing due to "Lorem" string not being selected would be misleading because the actual bug is that the framework sent null, which was not expected. If they both mean the same thing, then I guess it's OK to fallback to zeros. It still feels strange to me that we don't know what the framework will send.

expect(range.textInside(text), text);

// Double tap to select the first word.
Expand All @@ -257,7 +259,8 @@ void main() {
await gesture.up();
await gesture.down(firstWordOffset);
await gesture.up();
range = TextRange(start: input.selectionStart, end: input.selectionEnd);
range = TextRange(
start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

expect(range.textInside(text), 'Lorem');

// Double tap to select the last word.
Expand All @@ -270,7 +273,8 @@ void main() {
await gesture.up();
await gesture.down(lastWordOffset);
await gesture.up();
range = TextRange(start: input.selectionStart, end: input.selectionEnd);
range = TextRange(
start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

expect(range.textInside(text), 'amet');
});
}
Expand Down
Loading