Fix how tests count open SemanticsHandles (#121571)
Fix how tests count open SemanticsHandles
This commit is contained in:
parent
f97a51533b
commit
6de42a70f1
@ -67,6 +67,11 @@ mixin SemanticsBinding on BindingBase {
|
||||
_semanticsEnabled.removeListener(listener);
|
||||
}
|
||||
|
||||
/// The number of clients registered to listen for semantics.
|
||||
///
|
||||
/// The number is increased whenever [ensureSemantics] is called and decreased
|
||||
/// when [SemanticsHandle.dispose] is called.
|
||||
int get debugOutstandingSemanticsHandles => _outstandingHandles;
|
||||
int _outstandingHandles = 0;
|
||||
|
||||
/// Creates a new [SemanticsHandle] and requests the collection of semantics
|
||||
|
@ -1247,6 +1247,7 @@ void main() {
|
||||
label: 'Custom label',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.namesRoute],
|
||||
)));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('CupertinoDialogRoute is state restorable', (WidgetTester tester) async {
|
||||
|
@ -1484,6 +1484,7 @@ void main() {
|
||||
label: 'Dismiss',
|
||||
)));
|
||||
debugDefaultTargetPlatformOverride = null;
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('showCupertinoModalPopup allows for semantics dismiss when set', (WidgetTester tester) async {
|
||||
@ -1519,6 +1520,7 @@ void main() {
|
||||
label: 'Dismiss',
|
||||
));
|
||||
debugDefaultTargetPlatformOverride = null;
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('showCupertinoModalPopup passes RouteSettings to PopupRoute', (WidgetTester tester) async {
|
||||
|
@ -657,7 +657,6 @@ void main() {
|
||||
group('Semantics', () {
|
||||
testWidgets('day mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
await tester.pumpWidget(calendarDatePicker());
|
||||
|
||||
@ -837,11 +836,11 @@ void main() {
|
||||
hasTapAction: true,
|
||||
isFocusable: true,
|
||||
));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('calendar year mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
await tester.pumpWidget(calendarDatePicker(
|
||||
initialCalendarMode: DatePickerMode.year,
|
||||
@ -863,8 +862,8 @@ void main() {
|
||||
isButton: true,
|
||||
));
|
||||
}
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -814,7 +814,6 @@ void main() {
|
||||
group('Semantics', () {
|
||||
testWidgets('calendar mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
await prepareDatePicker(tester, (Future<DateTime?> date) async {
|
||||
// Header
|
||||
@ -858,11 +857,11 @@ void main() {
|
||||
isFocusable: true,
|
||||
));
|
||||
});
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('input mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
initialEntryMode = DatePickerEntryMode.input;
|
||||
await prepareDatePicker(tester, (Future<DateTime?> date) async {
|
||||
@ -901,6 +900,7 @@ void main() {
|
||||
isFocusable: true,
|
||||
));
|
||||
});
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1086,21 +1086,21 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('Semantics', () {
|
||||
testWidgets('calendar mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
currentDate = DateTime(2016, DateTime.january, 30);
|
||||
addTearDown(semantics.dispose);
|
||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||
expect(
|
||||
tester.getSemantics(find.text('30')),
|
||||
matchesSemantics(
|
||||
label: '30, Saturday, January 30, 2016, Today',
|
||||
hasTapAction: true,
|
||||
isFocusable: true,
|
||||
),
|
||||
);
|
||||
});
|
||||
group('Semantics', () {
|
||||
testWidgets('calendar mode', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
currentDate = DateTime(2016, DateTime.january, 30);
|
||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||
expect(
|
||||
tester.getSemantics(find.text('30')),
|
||||
matchesSemantics(
|
||||
label: '30, Saturday, January 30, 2016, Today',
|
||||
hasTapAction: true,
|
||||
isFocusable: true,
|
||||
),
|
||||
);
|
||||
});
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2505,6 +2505,7 @@ void main() {
|
||||
label: 'Custom label',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.namesRoute],
|
||||
)));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('DialogRoute is state restorable', (WidgetTester tester) async {
|
||||
|
@ -262,7 +262,6 @@ void main() {
|
||||
|
||||
testWidgets('Semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
// selection menu.
|
||||
@ -287,6 +286,7 @@ void main() {
|
||||
hasMoveCursorBackwardByCharacterAction: true,
|
||||
hasMoveCursorBackwardByWordAction: true,
|
||||
));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async {
|
||||
|
@ -4514,6 +4514,7 @@ void main() {
|
||||
),
|
||||
],
|
||||
), ignoreTransform: true, ignoreRect: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('TextField with specified suffixStyle', (WidgetTester tester) async {
|
||||
|
@ -13,7 +13,6 @@ void main() {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/100358.
|
||||
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
@ -44,5 +43,6 @@ void main() {
|
||||
type: SemanticsAction.showOnScreen,
|
||||
nodeId: nodeId,
|
||||
));
|
||||
semantics.dispose();
|
||||
});
|
||||
}
|
||||
|
@ -273,7 +273,8 @@ void main() {
|
||||
});
|
||||
|
||||
test('after markNeedsSemanticsUpdate() all render objects between two semantic boundaries are asked for annotations', () {
|
||||
TestRenderingFlutterBinding.instance.pipelineOwner.ensureSemantics();
|
||||
final SemanticsHandle handle = TestRenderingFlutterBinding.instance.ensureSemantics();
|
||||
addTearDown(handle.dispose);
|
||||
|
||||
TestRender middle;
|
||||
final TestRender root = TestRender(
|
||||
|
@ -4510,7 +4510,6 @@ void main() {
|
||||
|
||||
testWidgets('are exposed', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
addTearDown(semantics.dispose);
|
||||
|
||||
controls.testCanCopy = false;
|
||||
controls.testCanCut = false;
|
||||
@ -4603,6 +4602,7 @@ void main() {
|
||||
],
|
||||
),
|
||||
);
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('can copy/cut/paste with a11y', (WidgetTester tester) async {
|
||||
|
@ -1751,6 +1751,7 @@ void main() {
|
||||
await tester.pumpWidget(Focus(includeSemantics: false, child: Container()));
|
||||
final TestSemantics expectedSemantics = TestSemantics.root();
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Focus updates the onKey handler when the widget updates', (WidgetTester tester) async {
|
||||
@ -2043,6 +2044,7 @@ void main() {
|
||||
await tester.pumpWidget(ExcludeFocus(child: Container()));
|
||||
final TestSemantics expectedSemantics = TestSemantics.root();
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/92693
|
||||
|
@ -2160,6 +2160,7 @@ void main() {
|
||||
await tester.pumpWidget(FocusTraversalGroup(child: Container()));
|
||||
final TestSemantics expectedSemantics = TestSemantics.root();
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets("Descendants of FocusTraversalGroup aren't focusable if descendantsAreFocusable is false.", (WidgetTester tester) async {
|
||||
@ -2418,6 +2419,7 @@ void main() {
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets("Raw keyboard listener doesn't introduce a Semantics node when specified", (WidgetTester tester) async {
|
||||
@ -2432,6 +2434,7 @@ void main() {
|
||||
);
|
||||
final TestSemantics expectedSemantics = TestSemantics.root();
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@ -2489,6 +2492,7 @@ void main() {
|
||||
await tester.pumpWidget(ExcludeFocusTraversal(child: Container()));
|
||||
final TestSemantics expectedSemantics = TestSemantics.root();
|
||||
expect(semantics, hasSemantics(expectedSemantics));
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2297,6 +2297,7 @@ void main() {
|
||||
),
|
||||
],
|
||||
), ignoreTransform: true, ignoreRect: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('SelectableText semantics, enableInteractiveSelection = false', (WidgetTester tester) async {
|
||||
|
@ -71,6 +71,7 @@ void main() {
|
||||
),
|
||||
],
|
||||
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Semantics can drop semantics config', (WidgetTester tester) async {
|
||||
@ -128,6 +129,7 @@ void main() {
|
||||
),
|
||||
],
|
||||
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async {
|
||||
|
@ -421,7 +421,7 @@ class SemanticsTester {
|
||||
/// You should call [dispose] at the end of a test that creates a semantics
|
||||
/// tester.
|
||||
SemanticsTester(this.tester) {
|
||||
_semanticsHandle = tester.binding.pipelineOwner.ensureSemantics();
|
||||
_semanticsHandle = tester.ensureSemantics();
|
||||
|
||||
// This _extra_ clean-up is needed for the case when a test fails and
|
||||
// therefore fails to call dispose() explicitly. The test is still required
|
||||
|
@ -238,6 +238,7 @@ void main() {
|
||||
],
|
||||
);
|
||||
expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreId: true, ignoreRect: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Sliver appbars - floating and pinned - second app bar stacks below', (WidgetTester tester) async {
|
||||
|
@ -677,6 +677,7 @@ void main() {
|
||||
final RenderSliver renderSliver = renderViewport.lastChild!;
|
||||
expect(renderSliver.geometry!.scrollExtent, 0.0);
|
||||
expect(find.byType(SliverOffstage), findsNothing);
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('offstage false', (WidgetTester tester) async {
|
||||
@ -696,6 +697,7 @@ void main() {
|
||||
final RenderSliver renderSliver = renderViewport.lastChild!;
|
||||
expect(renderSliver.geometry!.scrollExtent, 14.0);
|
||||
expect(find.byType(SliverOffstage), paints..paragraph());
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@ -841,6 +843,7 @@ void main() {
|
||||
expect(semantics.nodesWith(label: 'a'), hasLength(1));
|
||||
await tester.tap(find.byType(GestureDetector), warnIfMissed: false);
|
||||
expect(events, equals(<String>[]));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('ignores semantics', (WidgetTester tester) async {
|
||||
@ -863,6 +866,7 @@ void main() {
|
||||
expect(semantics.nodesWith(label: 'a'), hasLength(0));
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
expect(events, equals(<String>['tap']));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('ignores pointer events & semantics', (WidgetTester tester) async {
|
||||
@ -884,6 +888,7 @@ void main() {
|
||||
expect(semantics.nodesWith(label: 'a'), hasLength(0));
|
||||
await tester.tap(find.byType(GestureDetector), warnIfMissed: false);
|
||||
expect(events, equals(<String>[]));
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('ignores nothing', (WidgetTester tester) async {
|
||||
@ -906,6 +911,7 @@ void main() {
|
||||
expect(semantics.nodesWith(label: 'a'), hasLength(1));
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
expect(events, equals(<String>['tap']));
|
||||
semantics.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1151,6 +1151,7 @@ void main() {
|
||||
),
|
||||
],
|
||||
)));
|
||||
semantics.dispose();
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/69787
|
||||
@ -1174,29 +1175,34 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(
|
||||
expect(
|
||||
semantics,
|
||||
hasSemantics(
|
||||
TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'included'),
|
||||
TestSemantics(
|
||||
label: 'HELLO',
|
||||
actions: <SemanticsAction>[
|
||||
SemanticsAction.tap,
|
||||
],
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.isLink,
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'included'),
|
||||
TestSemantics(
|
||||
label: 'HELLO',
|
||||
actions: <SemanticsAction>[
|
||||
SemanticsAction.tap,
|
||||
],
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.isLink,
|
||||
],
|
||||
),
|
||||
TestSemantics(label: 'included2'),
|
||||
],
|
||||
),
|
||||
TestSemantics(label: 'included2'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
));
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
),
|
||||
);
|
||||
semantics.dispose();
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/69787
|
||||
@ -1232,29 +1238,34 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(
|
||||
expect(
|
||||
semantics,
|
||||
hasSemantics(
|
||||
TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'foo'),
|
||||
TestSemantics(label: 'bar'),
|
||||
TestSemantics(
|
||||
label: 'HELLO',
|
||||
actions: <SemanticsAction>[
|
||||
SemanticsAction.tap,
|
||||
],
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.isLink,
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'foo'),
|
||||
TestSemantics(label: 'bar'),
|
||||
TestSemantics(
|
||||
label: 'HELLO',
|
||||
actions: <SemanticsAction>[
|
||||
SemanticsAction.tap,
|
||||
],
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.isLink,
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
));
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
),
|
||||
);
|
||||
semantics.dispose();
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/69787
|
||||
@ -1303,24 +1314,29 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, hasSemantics(TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(
|
||||
expect(
|
||||
semantics,
|
||||
hasSemantics(
|
||||
TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'not clipped'),
|
||||
TestSemantics(
|
||||
label: 'next WS is clipped',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
children: <TestSemantics>[
|
||||
TestSemantics(label: 'not clipped'),
|
||||
TestSemantics(
|
||||
label: 'next WS is clipped',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
));
|
||||
ignoreId: true,
|
||||
ignoreRect: true,
|
||||
ignoreTransform: true,
|
||||
),
|
||||
);
|
||||
semantics.dispose();
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877
|
||||
|
||||
testWidgets('RenderParagraph intrinsic width', (WidgetTester tester) async {
|
||||
|
@ -473,7 +473,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('works when semantics are enabled', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
await tester.pumpWidget(
|
||||
const Text('hello', textDirection: TextDirection.ltr));
|
||||
|
||||
@ -497,7 +497,7 @@ void main() {
|
||||
}, semanticsEnabled: false);
|
||||
|
||||
testWidgets('throws state error multiple matches are found', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
|
@ -155,10 +155,10 @@ void testWidgets(
|
||||
() {
|
||||
tester._testDescription = combinedDescription;
|
||||
SemanticsHandle? semanticsHandle;
|
||||
tester._recordNumberOfSemanticsHandles();
|
||||
if (semanticsEnabled == true) {
|
||||
semanticsHandle = tester.ensureSemantics();
|
||||
}
|
||||
tester._recordNumberOfSemanticsHandles();
|
||||
test_package.addTearDown(binding.postTest);
|
||||
return binding.runTest(
|
||||
() async {
|
||||
@ -1044,18 +1044,16 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
|
||||
void _verifySemanticsHandlesWereDisposed() {
|
||||
assert(_lastRecordedSemanticsHandles != null);
|
||||
if (binding.pipelineOwner.debugOutstandingSemanticsHandles > _lastRecordedSemanticsHandles!) {
|
||||
// TODO(goderbauer): Fix known leak in web engine when running integration tests and remove this "correction", https://github.com/flutter/flutter/issues/121640.
|
||||
final int knownWebEngineLeakForLiveTestsCorrection = kIsWeb && binding is LiveTestWidgetsFlutterBinding ? 2 : 0;
|
||||
|
||||
if (_currentSemanticsHandles - knownWebEngineLeakForLiveTestsCorrection > _lastRecordedSemanticsHandles!) {
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary('A SemanticsHandle was active at the end of the test.'),
|
||||
ErrorDescription(
|
||||
'All SemanticsHandle instances must be disposed by calling dispose() on '
|
||||
'the SemanticsHandle.'
|
||||
),
|
||||
ErrorHint(
|
||||
'If your test uses SemanticsTester, it is '
|
||||
'sufficient to call dispose() on SemanticsTester. Otherwise, the '
|
||||
'existing handle will leak into another test and alter its behavior.'
|
||||
),
|
||||
]);
|
||||
}
|
||||
_lastRecordedSemanticsHandles = null;
|
||||
@ -1063,8 +1061,10 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
|
||||
int? _lastRecordedSemanticsHandles;
|
||||
|
||||
int get _currentSemanticsHandles => binding.debugOutstandingSemanticsHandles + binding.pipelineOwner.debugOutstandingSemanticsHandles;
|
||||
|
||||
void _recordNumberOfSemanticsHandles() {
|
||||
_lastRecordedSemanticsHandles = binding.pipelineOwner.debugOutstandingSemanticsHandles;
|
||||
_lastRecordedSemanticsHandles = _currentSemanticsHandles;
|
||||
}
|
||||
|
||||
/// Returns the TestTextInput singleton.
|
||||
|
@ -737,7 +737,6 @@ void main() {
|
||||
|
||||
testWidgets('failure does not throw unexpected errors', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
addTearDown(() => handle.dispose());
|
||||
|
||||
const Key key = Key('semantics');
|
||||
await tester.pumpWidget(Semantics(
|
||||
@ -789,13 +788,13 @@ void main() {
|
||||
);
|
||||
|
||||
expect(failedExpectation, throwsA(isA<TestFailure>()));
|
||||
handle.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
group('containsSemantics', () {
|
||||
testWidgets('matches SemanticsData', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
addTearDown(() => handle.dispose());
|
||||
|
||||
const Key key = Key('semantics');
|
||||
await tester.pumpWidget(Semantics(
|
||||
@ -889,6 +888,7 @@ void main() {
|
||||
)),
|
||||
reason: 'onTapHint "scans" should not have matched "scan".',
|
||||
);
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('can match all semantics flags and actions enabled', (WidgetTester tester) async {
|
||||
@ -1233,7 +1233,6 @@ void main() {
|
||||
|
||||
testWidgets('failure does not throw unexpected errors', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
addTearDown(() => handle.dispose());
|
||||
|
||||
const Key key = Key('semantics');
|
||||
await tester.pumpWidget(Semantics(
|
||||
@ -1283,6 +1282,7 @@ void main() {
|
||||
);
|
||||
|
||||
expect(failedExpectation, throwsA(isA<TestFailure>()));
|
||||
handle.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[];
|
||||
|
||||
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
|
||||
reportTestException = (FlutterErrorDetails details, String testDescription) {
|
||||
errors.add(details);
|
||||
};
|
||||
|
||||
// The error that the test throws in their run methods below will be forwarded
|
||||
// to our exception handler above and do not cause the test to fail. The
|
||||
// tearDown method then checks that the test threw the expected exception.
|
||||
await testMain();
|
||||
}
|
||||
|
||||
void pipelineOwnerTestRun() {
|
||||
testWidgets('open SemanticsHandle from PipelineOwner fails test', (WidgetTester tester) async {
|
||||
final int outstandingHandles = tester.binding.pipelineOwner.debugOutstandingSemanticsHandles;
|
||||
tester.binding.pipelineOwner.ensureSemantics();
|
||||
expect(tester.binding.pipelineOwner.debugOutstandingSemanticsHandles, outstandingHandles + 1);
|
||||
// SemanticsHandle is not disposed on purpose to verify in tearDown that
|
||||
// the test failed due to an active SemanticsHandle.
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
expect(errors, hasLength(1));
|
||||
expect(errors.single.toString(), contains('SemanticsHandle was active at the end of the test'));
|
||||
});
|
||||
}
|
||||
|
||||
void semanticsBindingTestRun() {
|
||||
testWidgets('open SemanticsHandle from SemanticsBinding fails test', (WidgetTester tester) async {
|
||||
final int outstandingHandles = tester.binding.debugOutstandingSemanticsHandles;
|
||||
tester.binding.ensureSemantics();
|
||||
expect(tester.binding.debugOutstandingSemanticsHandles, outstandingHandles + 1);
|
||||
// SemanticsHandle is not disposed on purpose to verify in tearDown that
|
||||
// the test failed due to an active SemanticsHandle.
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
expect(errors, hasLength(1));
|
||||
expect(errors.single.toString(), contains('SemanticsHandle was active at the end of the test'));
|
||||
});
|
||||
}
|
||||
|
||||
void failingTestTestRun() {
|
||||
testWidgets('open SemanticsHandle from SemanticsBinding fails test', (WidgetTester tester) async {
|
||||
final int outstandingHandles = tester.binding.debugOutstandingSemanticsHandles;
|
||||
tester.binding.ensureSemantics();
|
||||
expect(tester.binding.debugOutstandingSemanticsHandles, outstandingHandles + 1);
|
||||
|
||||
// Failing expectation to verify that an open semantics handle doesn't
|
||||
// cause any cascading failures and only the failing expectation is
|
||||
// reported.
|
||||
expect(1, equals(2));
|
||||
fail('The test should never have gotten this far.');
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
expect(errors, hasLength(1));
|
||||
expect(errors.single.toString(), contains('Expected: <2>'));
|
||||
expect(errors.single.toString(), contains('Actual: <1>'));
|
||||
});
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
import 'flutter_test_config.dart' as config;
|
||||
|
||||
void main() => config.failingTestTestRun();
|
@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
import 'flutter_test_config.dart' as config;
|
||||
|
||||
void main() => config.pipelineOwnerTestRun();
|
@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
import 'flutter_test_config.dart' as config;
|
||||
|
||||
void main() => config.semanticsBindingTestRun();
|
Loading…
x
Reference in New Issue
Block a user