blob: 39f5d1571ad307a1b542d1b88716f5b609315bff [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.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('tab', () {
testWidgets('failure case, empty', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.tab, child: const Text('a tab')),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'A tab needs selected states');
});
testWidgets('failure case, no tap', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.tab, selected: false, child: const Text('a tab')),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'A tab must have a tap action');
});
testWidgets('success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.tab,
selected: false,
onTap: () {},
child: const Text('a tab'),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('list', () {
testWidgets('failure case, list item without list parent', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.listItem, child: const Text('some child')),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith('Semantics node 1 has role ${SemanticsRole.listItem}, but its parent'),
);
});
testWidgets('Success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.list,
explicitChildNodes: true,
child: Semantics(role: SemanticsRole.listItem, child: const Text('some child')),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('tabBar', () {
testWidgets('failure case, empty child', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.tabBar,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'a TabBar cannot be empty');
});
testWidgets('failure case, non tab child', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.tabBar,
explicitChildNodes: true,
child: Semantics(child: const Text('some child')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'Children of TabBar must have the tab role');
});
testWidgets('Success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.tabBar,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.tab,
selected: false,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('radioGroup', () {
testWidgets('success case, child is not mutually exclusive', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Semantics(
checked: false,
inMutuallyExclusiveGroup: false,
child: const SizedBox.square(dimension: 1),
),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isNull);
});
testWidgets('failure case, multiple checked children', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Column(
children: <Widget>[
Semantics(
checked: true,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
Semantics(
checked: true,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
],
),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'Radio groups must not have multiple checked children');
});
testWidgets('success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Column(
children: <Widget>[
Semantics(
checked: false,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
Semantics(
checked: true,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
],
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio buttons with labels', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Column(
children: <Widget>[
Semantics(
label: 'Option A',
child: Semantics(
checked: false,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
),
Semantics(
label: 'Option B',
child: Semantics(
checked: true,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
),
],
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio group with no checkable children', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Semantics(toggled: true, child: const SizedBox.square(dimension: 1)),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio group can have checkbox children', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Material(
child: Material(
child: RadioGroup<int>(
groupValue: 0,
onChanged: (int? value) {},
child: Column(
children: <Widget>[
Checkbox(value: false, onChanged: (bool? value) {}),
const Radio<int>(value: 0),
const Radio<int>(value: 1),
],
),
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio group can nest', (WidgetTester tester) async {
await tester.pumpWidget(
Material(
child: Material(
child: RadioGroup<int>(
groupValue: 0,
onChanged: (int? value) {},
child: Column(
children: <Widget>[
RadioGroup<String>(
groupValue: 'string',
onChanged: (String? value) {},
child: const Radio<String>(value: 'string'),
),
const Radio<int>(value: 0),
const Radio<int>(value: 1),
],
),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('menu', () {
testWidgets('failure case, empty child', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menu,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'a menu cannot be empty');
});
testWidgets('Success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menu,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItem,
selected: false,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('menuBar', () {
testWidgets('failure case, empty child', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuBar,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'a menu bar cannot be empty');
});
testWidgets('Success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuBar,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItem,
selected: false,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('menuItem', () {
testWidgets('failure case, no menu or menuBar as ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuItem,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'A menu item must be a child of a menu or a menu bar');
});
testWidgets('Success case with menu as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menu,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItem,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case with menuBar as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuBar,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItem,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('menuItemCheckbox', () {
testWidgets('failure case, no checked flag', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuItemCheckbox,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'a menu item checkbox must be checkable');
});
testWidgets('failure case, no menu or menuBar as its ancestor', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuItemCheckbox,
checked: false,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'A menu item checkbox must be a child of a menu or a menu bar');
});
testWidgets('Success case with menu as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menu,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItemCheckbox,
checked: true,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case with menuBar as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuBar,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItemCheckbox,
checked: false,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('menuItemRadio', () {
testWidgets('failure case, no checked flag', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuItemRadio,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'a menu item radio must be checkable');
});
testWidgets('failure case, no menu or menuBar as its ancestor', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuItemRadio,
checked: false,
child: const ExcludeSemantics(child: Text('something')),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(error.message, 'A menu item radio must be a child of a menu or a menu bar');
});
testWidgets('Success case with menu as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menu,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItemRadio,
checked: true,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case with menuBar as an ancester', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.menuBar,
explicitChildNodes: true,
child: Semantics(
role: SemanticsRole.menuItemRadio,
checked: false,
onTap: () {},
child: const Text('some child'),
),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('alert and status', () {
testWidgets('failure case, alert and live region', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.alert,
liveRegion: true,
child: const SizedBox.square(dimension: 1),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith('Node 1 has role SemanticsRole.alert but is also a live region.'),
);
});
testWidgets('failure case, status and live region', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.status,
liveRegion: true,
child: const SizedBox.square(dimension: 1),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith('Node 1 has role SemanticsRole.status but is also a live region.'),
);
});
testWidgets('success case', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
explicitChildNodes: true,
child: Column(
children: <Widget>[
Semantics(role: SemanticsRole.status, child: const SizedBox.square(dimension: 1)),
Semantics(role: SemanticsRole.alert, child: const SizedBox.square(dimension: 1)),
],
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio buttons with labels', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Column(
children: <Widget>[
Semantics(
label: 'Option A',
child: Semantics(
checked: false,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
),
Semantics(
label: 'Option B',
child: Semantics(
checked: true,
inMutuallyExclusiveGroup: true,
child: const SizedBox.square(dimension: 1),
),
),
],
),
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('success case, radio group with no checkable children', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.radioGroup,
explicitChildNodes: true,
child: Semantics(toggled: true, child: const SizedBox.square(dimension: 1)),
),
),
);
expect(tester.takeException(), isNull);
});
});
group('landmarks', () {
testWidgets('failure case, complementary role is contained by other landmark roles', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.main,
child: SizedBox(
child: Semantics(role: SemanticsRole.complementary, child: const Text('some child')),
),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The complementary landmark role should not contained within any other landmark roles.',
),
);
});
testWidgets('failure case, multiple nodes have the same complementary role', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
role: SemanticsRole.complementary,
child: const SizedBox.square(dimension: 1),
),
Semantics(
container: true,
child: SizedBox(
child: Semantics(
role: SemanticsRole.complementary,
child: const SizedBox.square(dimension: 1),
),
),
),
],
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The complementary landmark role should have a unique label as it is used more than once.',
),
);
});
testWidgets('Success case, complementary role', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.complementary, child: const Text('some child')),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case, complementary role is used more than once', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
label: 'complementary 1',
role: SemanticsRole.complementary,
child: const SizedBox.square(dimension: 1),
),
Semantics(
label: 'complementary 2',
role: SemanticsRole.complementary,
child: const SizedBox.square(dimension: 1),
),
],
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('failure case, multiple nodes have the same contentInfo role', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
role: SemanticsRole.contentInfo,
child: const SizedBox.square(dimension: 1),
),
Semantics(
container: true,
child: SizedBox(
child: Semantics(
role: SemanticsRole.contentInfo,
child: const SizedBox.square(dimension: 1),
),
),
),
],
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The contentInfo landmark role should have a unique label as it is used more than once.',
),
);
});
testWidgets('failure case, contentInfo role is contained by other landmark roles', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.complementary,
child: SizedBox(
child: Semantics(role: SemanticsRole.contentInfo, child: const Text('some child')),
),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The contentInfo landmark role should not contained within any other landmark roles.',
),
);
});
testWidgets('Success case, contentInfo role', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.contentInfo, child: const Text('some child')),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case, contentInfo role is used more than once', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
label: 'contentInfo 1',
role: SemanticsRole.contentInfo,
child: const SizedBox.square(dimension: 1),
),
Semantics(
label: 'contentInfo 2',
role: SemanticsRole.contentInfo,
child: const SizedBox.square(dimension: 1),
),
],
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('failure case, multiple nodes have the same main role', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(role: SemanticsRole.main, child: const SizedBox.square(dimension: 1)),
Semantics(
container: true,
child: SizedBox(
child: Semantics(
role: SemanticsRole.main,
child: const SizedBox.square(dimension: 1),
),
),
),
],
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The main landmark role should have a unique label as it is used more than once.',
),
);
});
testWidgets('failure case, main role is contained by other landmark roles', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
role: SemanticsRole.contentInfo,
child: SizedBox(
child: Semantics(role: SemanticsRole.main, child: const Text('some child')),
),
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith('The main landmark role should not contained within any other landmark roles.'),
);
});
testWidgets('Success case, main role', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.main, child: const Text('some child')),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case, main role is used more than once', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
label: 'main 1',
role: SemanticsRole.main,
child: const SizedBox.square(dimension: 1),
),
Semantics(
label: 'main 2',
role: SemanticsRole.main,
child: const SizedBox.square(dimension: 1),
),
],
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('failure case, multiple nodes have the same navigation role', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(role: SemanticsRole.navigation, child: const SizedBox.square(dimension: 1)),
Semantics(
container: true,
child: SizedBox(
child: Semantics(
role: SemanticsRole.navigation,
child: const SizedBox.square(dimension: 1),
),
),
),
],
),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'The navigation landmark role should have a unique label as it is used more than once.',
),
);
});
testWidgets('Success case, navigation role', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.navigation, child: const Text('some child')),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('Success case, navigation role is used more than once', (
WidgetTester tester,
) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
Semantics(
label: 'navigation 1',
role: SemanticsRole.navigation,
child: const SizedBox.square(dimension: 1),
),
Semantics(
label: 'navigation 2',
role: SemanticsRole.navigation,
child: const SizedBox.square(dimension: 1),
),
],
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets('failure case, region role without label', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(role: SemanticsRole.region, child: const SizedBox()),
),
);
final Object? exception = tester.takeException();
expect(exception, isFlutterError);
final error = exception! as FlutterError;
expect(
error.message,
startsWith(
'A region role should include a label that describes the purpose of the content.',
),
);
});
testWidgets('Success case, region role', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(label: 'Header 1', role: SemanticsRole.region, child: const SizedBox()),
),
);
expect(tester.takeException(), isNull);
});
});
}