blob: 960361dec9e306eff511c567741d4336f6e16cfe [file] [log] [blame]
// 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.
// TODO(gspencergoog): Remove this tag once this test's state leaks/test
// dependencies have been fixed.
// https://github.com/flutter/flutter/issues/85160
// Fails with "flutter test --test-randomize-ordering-seed=1000"
@Tags(<String>['no-shuffle'])
import 'package:file/file.dart';
import '../src/common.dart';
import 'test_data/project.dart';
import 'test_driver.dart';
import 'test_utils.dart';
void main() {
late Directory tempDir;
setUp(() async {
tempDir = createResolvedTempDirectorySync('break_on_framework_exceptions.');
});
tearDown(() async {
tryToDelete(tempDir);
});
testWithoutContext('breaks when AnimationController listener throws', () async {
final TestProject project = TestProject(
r'''
AnimationController(vsync: TestVSync(), duration: Duration.zero)
..addListener(() {
throw 'AnimationController listener';
})
..forward();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'AnimationController listener';"));
});
testWithoutContext('breaks when AnimationController status listener throws', () async {
final TestProject project = TestProject(
r'''
AnimationController(vsync: TestVSync(), duration: Duration.zero)
..addStatusListener((AnimationStatus _) {
throw 'AnimationController status listener';
})
..forward();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'AnimationController status listener';"));
});
testWithoutContext('breaks when ChangeNotifier listener throws', () async {
final TestProject project = TestProject(
r'''
ValueNotifier<int>(0)
..addListener(() {
throw 'ValueNotifier listener';
})
..value = 1;
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'ValueNotifier listener';"));
});
testWithoutContext('breaks when handling a gesture throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(
MaterialApp(
home: Center(
child: ElevatedButton(
child: const Text('foo'),
onPressed: () {
throw 'while handling a gesture';
},
),
),
)
);
await tester.tap(find.byType(ElevatedButton));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'while handling a gesture';"));
});
testWithoutContext('breaks when platform message callback throws', () async {
final TestProject project = TestProject(
r'''
BasicMessageChannel<String>('foo', const StringCodec()).setMessageHandler((_) {
throw 'platform message callback';
});
tester.binding.defaultBinaryMessenger.handlePlatformMessage('foo', const StringCodec().encodeMessage('Hello'), (_) {});
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'platform message callback';"));
});
testWithoutContext('breaks when SliverChildBuilderDelegate.builder throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(MaterialApp(
home: ListView.builder(
itemBuilder: (BuildContext context, int index) {
throw 'cannot build child';
},
),
));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'cannot build child';"));
});
testWithoutContext('breaks when EditableText.onChanged throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(MaterialApp(
home: Material(
child: TextField(
onChanged: (String t) {
throw 'onChanged';
},
),
),
));
await tester.enterText(find.byType(TextField), 'foo');
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'onChanged';"));
});
testWithoutContext('breaks when EditableText.onEditingComplete throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(MaterialApp(
home: Material(
child: TextField(
onEditingComplete: () {
throw 'onEditingComplete';
},
),
),
));
await tester.tap(find.byType(EditableText));
await tester.pump();
await tester.testTextInput.receiveAction(TextInputAction.done);
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'onEditingComplete';"));
});
testWithoutContext('breaks when EditableText.onSelectionChanged throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(MaterialApp(
home: SelectableText('hello',
onSelectionChanged: (TextSelection selection, SelectionChangedCause? cause) {
throw 'onSelectionChanged';
},
),
));
await tester.tap(find.byType(SelectableText));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'onSelectionChanged';"));
});
testWithoutContext('breaks when Action listener throws', () async {
final TestProject project = TestProject(
r'''
CallbackAction<Intent>(onInvoke: (Intent _) { })
..addActionListener((_) {
throw 'action listener';
})
..notifyActionListeners();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'action listener';"));
});
testWithoutContext('breaks when pointer route throws', () async {
final TestProject project = TestProject(
r'''
PointerRouter()
..addRoute(2, (PointerEvent event) {
throw 'pointer route';
})
..route(TestPointer(2).down(Offset.zero));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'pointer route';"));
});
testWithoutContext('breaks when PointerSignalResolver callback throws', () async {
final TestProject project = TestProject(
r'''
const PointerScrollEvent originalEvent = PointerScrollEvent();
PointerSignalResolver()
..register(originalEvent, (PointerSignalEvent event) {
throw 'PointerSignalResolver callback';
})
..resolve(originalEvent);
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'PointerSignalResolver callback';"));
});
testWithoutContext('breaks when PointerSignalResolver callback throws', () async {
final TestProject project = TestProject(
r'''
FocusManager.instance
..addHighlightModeListener((_) {
throw 'highlight mode listener';
})
..highlightStrategy = FocusHighlightStrategy.alwaysTouch
..highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'highlight mode listener';"));
});
testWithoutContext('breaks when GestureBinding.dispatchEvent throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(
MouseRegion(
onHover: (_) {
throw 'onHover';
},
)
);
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: Offset.zero);
await tester.pump();
await gesture.moveTo(tester.getCenter(find.byType(MouseRegion)));
await tester.pump();
gesture.removePointer();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'onHover';"));
});
testWithoutContext('breaks when ImageStreamListener.onImage throws', () async {
final TestProject project = TestProject(
r'''
final Completer<ImageInfo> completer = Completer<ImageInfo>();
OneFrameImageStreamCompleter(completer.future)
..addListener(ImageStreamListener((ImageInfo _, bool __) {
throw 'setImage';
}));
completer.complete(ImageInfo(image: image));
''',
setup: r'''
late ui.Image image;
setUp(() async {
image = await createTestImage();
});
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'setImage';"));
});
testWithoutContext('breaks when ImageStreamListener.onError throws', () async {
final TestProject project = TestProject(
r'''
final Completer<ImageInfo> completer = Completer<ImageInfo>();
OneFrameImageStreamCompleter(completer.future)
..addListener(ImageStreamListener(
(ImageInfo _, bool __) { },
onError: (Object _, StackTrace? __) {
throw 'onError';
},
));
completer.completeError('ERROR');
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'onError';"));
});
testWithoutContext('breaks when LayoutBuilder.builder throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(LayoutBuilder(
builder: (_, __) {
throw 'LayoutBuilder.builder';
},
));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'LayoutBuilder.builder';"));
});
testWithoutContext('breaks when _CallbackHookProvider callback throws', () async {
final TestProject project = TestProject(
r'''
RootBackButtonDispatcher()
..addCallback(() {
throw '_CallbackHookProvider.callback';
})
..invokeCallback(Future.value(false));
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw '_CallbackHookProvider.callback';"));
});
testWithoutContext('breaks when TimingsCallback throws', () async {
final TestProject project = TestProject(
r'''
SchedulerBinding.instance!.addTimingsCallback((List<FrameTiming> timings) {
throw 'TimingsCallback';
});
ui.window.onReportTimings!(<FrameTiming>[]);
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'TimingsCallback';"));
});
testWithoutContext('breaks when TimingsCallback throws', () async {
final TestProject project = TestProject(
r'''
SchedulerBinding.instance!.scheduleTask(
() {
throw 'scheduled task';
},
Priority.touch,
);
await tester.pumpAndSettle();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'scheduled task';"));
});
testWithoutContext('breaks when FrameCallback throws', () async {
final TestProject project = TestProject(
r'''
SchedulerBinding.instance!.addPostFrameCallback((_) {
throw 'FrameCallback';
});
await tester.pump();
'''
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'FrameCallback';"));
});
testWithoutContext('breaks when attaching to render tree throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
''',
classes: r'''
class TestWidget extends StatelessWidget {
@override
StatelessElement createElement() {
throw 'create element';
}
@override
Widget build(BuildContext context) => Container();
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'create element';"));
});
testWithoutContext('breaks when RenderObject.performLayout throws', () async {
final TestProject project = TestProject(
r'''
TestRender().layout(BoxConstraints());
''',
classes: r'''
class TestRender extends RenderBox {
@override
void performLayout() {
throw 'performLayout';
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'performLayout';"));
});
testWithoutContext('breaks when RenderObject.performResize throws', () async {
final TestProject project = TestProject(
r'''
TestRender().layout(BoxConstraints());
''',
classes: r'''
class TestRender extends RenderBox {
@override
bool get sizedByParent => true;
@override
void performResize() {
throw 'performResize';
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'performResize';"));
});
testWithoutContext('breaks when RenderObject.performLayout (without resize) throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
tester.renderObject<TestRender>(find.byType(TestWidget)).layoutThrows = true;
await tester.pump();
''',
classes: r'''
class TestWidget extends LeafRenderObjectWidget {
@override
RenderObject createRenderObject(BuildContext context) => TestRender();
}
class TestRender extends RenderBox {
bool get layoutThrows => _layoutThrows;
bool _layoutThrows = false;
set layoutThrows(bool value) {
if (value == _layoutThrows) {
return;
}
_layoutThrows = value;
markNeedsLayout();
}
@override
void performLayout() {
if (layoutThrows) {
throw 'performLayout without resize';
}
size = constraints.biggest;
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'performLayout without resize';"));
});
testWithoutContext('breaks when StatelessWidget.build throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
''',
classes: r'''
class TestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
throw 'StatelessWidget.build';
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'StatelessWidget.build';"));
});
testWithoutContext('breaks when StatefulWidget.build throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
''',
classes: r'''
class TestWidget extends StatefulWidget {
@override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget> {
@override
Widget build(BuildContext context) {
throw 'StatefulWidget.build';
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'StatefulWidget.build';"));
});
testWithoutContext('breaks when finalizing the tree throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
''',
classes: r'''
class TestWidget extends StatefulWidget {
@override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget> {
@override
void dispose() {
super.dispose();
throw 'dispose';
}
@override
Widget build(BuildContext context) => Container();
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'dispose';"));
});
testWithoutContext('breaks when rebuilding dirty elements throws', () async {
final TestProject project = TestProject(
r'''
await tester.pumpWidget(TestWidget());
tester.element<TestElement>(find.byType(TestWidget)).throwOnRebuild = true;
await tester.pump();
''',
classes: r'''
class TestWidget extends StatelessWidget {
@override
StatelessElement createElement() => TestElement(this);
@override
Widget build(BuildContext context) => Container();
}
class TestElement extends StatelessElement {
TestElement(StatelessWidget widget) : super(widget);
bool get throwOnRebuild => _throwOnRebuild;
bool _throwOnRebuild = false;
set throwOnRebuild(bool value) {
if (value == _throwOnRebuild) {
return;
}
_throwOnRebuild = value;
markNeedsBuild();
}
@override
void rebuild({bool force = false}) {
if (_throwOnRebuild) {
throw 'rebuild';
}
super.rebuild(force: force);
}
}
''',
);
await project.setUpIn(tempDir);
final FlutterTestTestDriver flutter = FlutterTestTestDriver(tempDir);
await flutter.test(withDebugger: true, pauseOnExceptions: true);
await flutter.waitForPause();
final int? breakLine = (await flutter.getSourceLocation())?.line;
expect(breakLine, project.lineContaining(project.test, "throw 'rebuild';"));
});
}
class TestProject extends Project {
TestProject(this.testBody, { this.setup, this.classes });
final String testBody;
final String? setup;
final String? classes;
@override
final String pubspec = '''
name: test
environment:
sdk: '>=2.12.0-0 <3.0.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
''';
@override
final String main = '';
@override
String get test => _test.replaceFirst('// SETUP', setup ?? '').replaceFirst('// TEST_BODY', testBody).replaceFirst('// CLASSES', classes ?? '');
final String _test = r'''
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
// SETUP
testWidgets('test', (WidgetTester tester) async {
// TEST_BODY
});
}
// CLASSES
''';
}