Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
235a3252
Unverified
Commit
235a3252
authored
Oct 26, 2022
by
nbayati
Committed by
GitHub
Oct 26, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Provide test API for accessibility announcements (#109661)
parent
609b8f32
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
166 additions
and
0 deletions
+166
-0
binding.dart
packages/flutter_test/lib/src/binding.dart
+86
-0
widget_tester.dart
packages/flutter_test/lib/src/widget_tester.dart
+7
-0
widget_tester_test.dart
packages/flutter_test/test/widget_tester_test.dart
+73
-0
No files found.
packages/flutter_test/lib/src/binding.dart
View file @
235a3252
...
...
@@ -62,6 +62,11 @@ enum EnginePhase {
sendSemanticsUpdate
,
}
/// Signature of callbacks used to intercept messages on a given channel.
///
/// See [TestDefaultBinaryMessenger.setMockDecodedMessageHandler] for more details.
typedef
_MockMessageHandler
=
Future
<
void
>
Function
(
Object
?);
/// Parts of the system that can generate pointer events that reach the test
/// binding.
///
...
...
@@ -106,6 +111,32 @@ mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
}
}
/// Accessibility announcement data passed to [SemanticsService.announce] captured in a test.
///
/// This class is intended to be used by the testing API to store the announcements
/// in a structured form so that tests can verify announcement details. The fields
/// of this class correspond to parameters of the [SemanticsService.announce] method.
///
/// See also:
///
/// * [WidgetTester.takeAnnouncements], which is the test API that uses this class.
class
CapturedAccessibilityAnnouncement
{
const
CapturedAccessibilityAnnouncement
.
_
(
this
.
message
,
this
.
textDirection
,
this
.
assertiveness
,
);
/// The accessibility message announced by the framework.
final
String
message
;
/// The direction in which the text of the [message] flows.
final
TextDirection
textDirection
;
/// Determines the assertiveness level of the accessibility announcement.
final
Assertiveness
assertiveness
;
}
/// Base class for bindings used by widgets library tests.
///
/// The [ensureInitialized] method creates (if necessary) and returns an
...
...
@@ -611,6 +642,24 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
late
StackTraceDemangler
_oldStackTraceDemangler
;
FlutterErrorDetails
?
_pendingExceptionDetails
;
_MockMessageHandler
?
_announcementHandler
;
List
<
CapturedAccessibilityAnnouncement
>
_announcements
=
<
CapturedAccessibilityAnnouncement
>[];
/// {@template flutter.flutter_test.TakeAccessibilityAnnouncements}
/// Returns a list of all the accessibility announcements made by the Flutter
/// framework since the last time this function was called.
///
/// It's safe to call this when there hasn't been any announcements; it will return
/// an empty list in that case.
/// {@endtemplate}
List
<
CapturedAccessibilityAnnouncement
>
takeAnnouncements
()
{
assert
(
inTest
);
final
List
<
CapturedAccessibilityAnnouncement
>
announcements
=
_announcements
;
_announcements
=
<
CapturedAccessibilityAnnouncement
>[];
return
announcements
;
}
static
const
TextStyle
_messageStyle
=
TextStyle
(
color:
Color
(
0xFF917FFF
),
fontSize:
40.0
,
...
...
@@ -700,6 +749,24 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}
Future
<
void
>
_handleAnnouncementMessage
(
Object
?
mockMessage
)
async
{
final
Map
<
Object
?,
Object
?>
message
=
mockMessage
!
as
Map
<
Object
?,
Object
?>;
if
(
message
[
'type'
]
==
'announce'
)
{
final
Map
<
Object
?,
Object
?>
data
=
message
[
'data'
]!
as
Map
<
Object
?,
Object
?>;
final
String
dataMessage
=
data
[
'message'
].
toString
();
final
TextDirection
textDirection
=
TextDirection
.
values
[
data
[
'textDirection'
]!
as
int
];
final
int
assertivenessLevel
=
(
data
[
'assertiveness'
]
as
int
?)
??
0
;
final
Assertiveness
assertiveness
=
Assertiveness
.
values
[
assertivenessLevel
];
final
CapturedAccessibilityAnnouncement
announcement
=
CapturedAccessibilityAnnouncement
.
_
(
dataMessage
,
textDirection
,
assertiveness
);
_announcements
.
add
(
announcement
);
}
}
Future
<
void
>
_runTest
(
Future
<
void
>
Function
()
testBody
,
VoidCallback
invariantTester
,
...
...
@@ -707,6 +774,16 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
)
{
assert
(
description
!=
null
);
assert
(
inTest
);
// Set the handler only if there is currently none.
if
(
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
checkMockMessageHandler
(
SystemChannels
.
accessibility
.
name
,
null
))
{
_announcementHandler
=
_handleAnnouncementMessage
;
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
setMockDecodedMessageHandler
<
dynamic
>(
SystemChannels
.
accessibility
,
_announcementHandler
);
}
_oldExceptionHandler
=
FlutterError
.
onError
;
_oldStackTraceDemangler
=
FlutterError
.
demangleStackTrace
;
int
exceptionCount
=
0
;
// number of un-taken exceptions
...
...
@@ -988,6 +1065,15 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
_parentZone
=
null
;
buildOwner
!.
focusManager
.
dispose
();
if
(
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
checkMockMessageHandler
(
SystemChannels
.
accessibility
.
name
,
_announcementHandler
))
{
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
setMockDecodedMessageHandler
(
SystemChannels
.
accessibility
,
null
);
_announcementHandler
=
null
;
}
_announcements
=
<
CapturedAccessibilityAnnouncement
>[];
ServicesBinding
.
instance
.
keyEventManager
.
keyMessageHandler
=
null
;
buildOwner
!.
focusManager
=
FocusManager
()..
registerGlobalHandlers
();
...
...
packages/flutter_test/lib/src/widget_tester.dart
View file @
235a3252
...
...
@@ -946,6 +946,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
return
binding
.
takeException
();
}
/// {@macro flutter.flutter_test.TakeAccessibilityAnnouncements}
///
/// See [TestWidgetsFlutterBinding.takeAnnouncements] for details.
List
<
CapturedAccessibilityAnnouncement
>
takeAnnouncements
()
{
return
binding
.
takeAnnouncements
();
}
/// Acts as if the application went idle.
///
/// Runs all remaining microtasks, including those scheduled as a result of
...
...
packages/flutter_test/test/widget_tester_test.dart
View file @
235a3252
...
...
@@ -11,6 +11,7 @@ import 'package:flutter/gestures.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:test_api/src/expect/async_matcher.dart'
;
// ignore: implementation_imports
// ignore: deprecated_member_use
...
...
@@ -821,6 +822,78 @@ void main() {
binding
.
postTest
();
});
});
group
(
'Accessibility announcements testing API'
,
()
{
testWidgets
(
'Returns the list of announcements'
,
(
WidgetTester
tester
)
async
{
// Make sure the handler is properly set
expect
(
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
checkMockMessageHandler
(
SystemChannels
.
accessibility
.
name
,
null
),
isFalse
);
await
SemanticsService
.
announce
(
'announcement 1'
,
TextDirection
.
ltr
);
await
SemanticsService
.
announce
(
'announcement 2'
,
TextDirection
.
rtl
,
assertiveness:
Assertiveness
.
assertive
);
await
SemanticsService
.
announce
(
'announcement 3'
,
TextDirection
.
rtl
);
final
List
<
CapturedAccessibilityAnnouncement
>
list
=
tester
.
takeAnnouncements
();
expect
(
list
,
hasLength
(
3
));
final
CapturedAccessibilityAnnouncement
first
=
list
[
0
];
expect
(
first
.
message
,
'announcement 1'
);
expect
(
first
.
textDirection
,
TextDirection
.
ltr
);
final
CapturedAccessibilityAnnouncement
second
=
list
[
1
];
expect
(
second
.
message
,
'announcement 2'
);
expect
(
second
.
textDirection
,
TextDirection
.
rtl
);
expect
(
second
.
assertiveness
,
Assertiveness
.
assertive
);
final
CapturedAccessibilityAnnouncement
third
=
list
[
2
];
expect
(
third
.
message
,
'announcement 3'
);
expect
(
third
.
textDirection
,
TextDirection
.
rtl
);
expect
(
third
.
assertiveness
,
Assertiveness
.
polite
);
final
List
<
CapturedAccessibilityAnnouncement
>
emptyList
=
tester
.
takeAnnouncements
();
expect
(
emptyList
,
<
CapturedAccessibilityAnnouncement
>[]);
});
test
(
'New test API is not breaking existing tests'
,
()
async
{
final
List
<
Map
<
dynamic
,
dynamic
>>
log
=
<
Map
<
dynamic
,
dynamic
>>[];
Future
<
dynamic
>
handleMessage
(
dynamic
mockMessage
)
async
{
final
Map
<
dynamic
,
dynamic
>
message
=
mockMessage
as
Map
<
dynamic
,
dynamic
>;
log
.
add
(
message
);
}
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
setMockDecodedMessageHandler
<
dynamic
>(
SystemChannels
.
accessibility
,
handleMessage
);
await
SemanticsService
.
announce
(
'announcement 1'
,
TextDirection
.
rtl
,
assertiveness:
Assertiveness
.
assertive
);
expect
(
log
,
equals
(<
Map
<
String
,
dynamic
>>[
<
String
,
dynamic
>{
'type'
:
'announce'
,
'data'
:
<
String
,
dynamic
>{
'message'
:
'announcement 1'
,
'textDirection'
:
0
,
'assertiveness'
:
1
}
},
]));
// Remove the handler
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
setMockDecodedMessageHandler
<
dynamic
>(
SystemChannels
.
accessibility
,
null
);
});
tearDown
(()
{
// Make sure that the handler is removed in [TestWidgetsFlutterBinding.postTest]
expect
(
TestDefaultBinaryMessengerBinding
.
instance
!.
defaultBinaryMessenger
.
checkMockMessageHandler
(
SystemChannels
.
accessibility
.
name
,
null
),
isTrue
);
});
});
}
class
FakeMatcher
extends
AsyncMatcher
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment