Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide test API for accessibility announcements #109661

Merged
merged 17 commits into from Oct 26, 2022

Conversation

nbayati
Copy link
Contributor

@nbayati nbayati commented Aug 17, 2022

Provide testing API for the accessibility announcements made by the Flutter framework. Currently the consumers of the code have to create a mock message handler and match the exact String value of the announcement which is a Map. So adding any new features to the announcements (like: #107568) would break the existing tests. This PR addresses the issue by providing a testing API which takes care of setting up a mock handler and returns an object for easy comparison.

Fixes #108495

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added a: tests "flutter test", flutter_test, or one of our tests. framework flutter/packages/flutter repository. See also f: labels. labels Aug 17, 2022
@nbayati nbayati requested a review from yjbanov Aug 17, 2022
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
@@ -106,6 +111,14 @@ mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
}
}

/// An accessibility announcement.
class Announcement {
Copy link
Contributor

@yjbanov yjbanov Aug 18, 2022

Choose a reason for hiding this comment

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

Let's rename this to CapturedAccessibilityAnnouncement. Otherwise it sounds too much like a production class name. Also, "announcement" does not by itself imply accessibility.

Copy link
Contributor Author

@nbayati nbayati Aug 19, 2022

Choose a reason for hiding this comment

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

The only potential issue would be lines getting longer than 80 character. I could always break lines similar to what dart formatter would do though.

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done!

packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
/// Returns a list announcements made by the Flutter framework.
List<Announcement>? takeAnnouncements() {
assert(inTest);
return _announcements;
Copy link
Contributor

@yjbanov yjbanov Aug 18, 2022

Choose a reason for hiding this comment

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

I think the semantics of "take" means "remove the returned value from the captured list".

Copy link
Contributor Author

@nbayati nbayati Aug 19, 2022

Choose a reason for hiding this comment

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

Yeah you/re right. I've changed the code to clear out the list afterwards. I don't think we'd need a peak/get function for list. What do you think?

packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
}

/// Returns the most recent announcement made by the Flutter framework.
Announcement? getLastAnnouncement(){
Copy link
Contributor

@yjbanov yjbanov Aug 18, 2022

Choose a reason for hiding this comment

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

If this is meant to return the last announcement without removing it, I'd call it peekLastAnnouncement rather than get. But I think perhaps we want take here as well, no?

Copy link
Contributor Author

@nbayati nbayati Aug 19, 2022

Choose a reason for hiding this comment

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

So take would remove the announcement from the list? In that case if the user calls takeLastAnnouncement twice, the second time what they'll get is not actually the last announcement. I'm not sure if this can cause confusion or if it's a common practice.

Copy link
Contributor

@yjbanov yjbanov Aug 22, 2022

Choose a reason for hiding this comment

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

Ah, good point. In that case maybe it should be called just takeAnnouncement.

Copy link
Contributor Author

@nbayati nbayati Oct 6, 2022

Choose a reason for hiding this comment

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

If I remember correctly, we decided that we don't need both takeAnnouncement and takeAnnouncements. So I just changed the name of the function to peekLastAnnouncement without changing.

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Based on the other comments, I'm removing this function all together because it's easy to access the last announcement through takeAnnouncements() and we don't really need a separate function.

@@ -700,13 +727,40 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}

Future<dynamic> _handleMessage(dynamic mockMessage) async {
final Map<dynamic, dynamic> data =
(mockMessage as Map<dynamic, dynamic>)['data'] as Map<dynamic, dynamic>;
Copy link
Contributor

@yjbanov yjbanov Aug 18, 2022

Choose a reason for hiding this comment

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

I don't remember, are the keys in the map really dynamic? I recall them all being Strings.

Copy link
Contributor Author

@nbayati nbayati Aug 20, 2022

Choose a reason for hiding this comment

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

I tried both
final Map<String, dynamic> data = (mockMessage as Map<dynamic, dynamic>)['data'] as Map<String, dynamic>;
and
final Map<String, dynamic> data = (mockMessage as Map<String, dynamic>)['data'] as Map<String, dynamic>;

In both cases I get a casting error:
the following _CastError was thrown running a test: type '_InternalLinkedHashMap<Object?, Object?>' is not a subtype of type 'Map<String, dynamic>' in type cast

Is there a better way to cast the mockMessage and get the values inside data?

Copy link
Contributor

@chunhtai chunhtai Aug 22, 2022

Choose a reason for hiding this comment

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

you can use .cast<K, V> to cast to a certain type https://api.flutter.dev/flutter/dart-core/Map/cast.html

Copy link
Contributor

@yjbanov yjbanov Aug 22, 2022

Choose a reason for hiding this comment

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

Oh, interesting. In that case it's fine to keep it dynamic. @chunhtai's suggestion also works.

Copy link
Contributor Author

@nbayati nbayati Oct 6, 2022

Choose a reason for hiding this comment

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

Both mockMessage and mockMessage['data'] are dynamic. It seems like cast<K,V>() is defined for Map and there isn't a cast function defined on dynamic type.

Copy link
Contributor

@mdebbar mdebbar Oct 7, 2022

Choose a reason for hiding this comment

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

@nbayati you can call any method on dynamic. So you can do mockMessage.cast<String, dynamic>() and it should work as long as mockMessage actually has that method.

packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
@nbayati nbayati requested review from chunhtai and yjbanov Aug 20, 2022
@@ -700,13 +727,40 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}

Future<dynamic> _handleMessage(dynamic mockMessage) async {
final Map<dynamic, dynamic> data =
(mockMessage as Map<dynamic, dynamic>)['data'] as Map<dynamic, dynamic>;
Copy link
Contributor

@chunhtai chunhtai Aug 22, 2022

Choose a reason for hiding this comment

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

you can use .cast<K, V> to cast to a certain type https://api.flutter.dev/flutter/dart-core/Map/cast.html

packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
packages/flutter_test/test/widget_tester_test.dart Outdated Show resolved Hide resolved
expect(TextDirection.rtl, equals(third.textDirection));
expect(Assertiveness.polite, equals(third.assertiveness));

final List<CapturedAccessibilityAnnouncement>? emptyList = tester.takeAnnouncements();
Copy link
Contributor

@yjbanov yjbanov Aug 22, 2022

Choose a reason for hiding this comment

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

Good call to check that the list was emptied out!

expect(emptyList, isNull);
});

test('New test API is not breaking existing tests', () async {
Copy link
Contributor

@yjbanov yjbanov Aug 22, 2022

Choose a reason for hiding this comment

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

We do plan to break existing tests in the future by always specifying assertiveness in the protocol, right? So I'm not sure if this test provides real protection 🤔

Copy link
Contributor Author

@nbayati nbayati Oct 6, 2022

Choose a reason for hiding this comment

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

My initial thought was to make sure that the current way of testing still works in general. Meaning that if someone wants to setup their own message handler, they're still able to do so. In another word, the new API doesn't overwrite what the user has specified as the message handler.
You had a good point about the future change though. So I've removed the announcements that didn't have assertiveness specified, since having only one would still accomplish what I had in mind.
Let me know if you still think we don't need this test.

packages/flutter_test/test/widget_tester_test.dart Outdated Show resolved Hide resolved
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
packages/flutter_test/lib/src/binding.dart Outdated Show resolved Hide resolved
@goderbauer
Copy link
Member

goderbauer commented Sep 13, 2022

(triage): @nbayati do you still have plans to follow up on the feedback given above?

@nbayati
Copy link
Contributor Author

nbayati commented Sep 14, 2022

(triage): @nbayati do you still have plans to follow up on the feedback given above?

Yes. I have been focusing on another high priority PR, but this is still on my list and I should be able to get back to it pretty soon.

@nbayati nbayati requested review from mdebbar, chunhtai and yjbanov Oct 6, 2022
Copy link
Contributor

@mdebbar mdebbar left a comment

Overall, the PR looks good to me, but I'll defer to @chunhtai and @yjbanov for final approval since they are more familiar with this part of the codebase.

@nbayati nbayati removed request for yjbanov and chunhtai Oct 13, 2022
@nbayati nbayati marked this pull request as ready for review Oct 14, 2022
@nbayati nbayati requested review from yjbanov and chunhtai Oct 15, 2022
@@ -62,6 +62,11 @@ enum EnginePhase {
sendSemanticsUpdate,
}

/// Signature of callbacks to intercept messages on a given channel.
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: "...callbacks used to intercept..."

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done!

@@ -62,6 +62,11 @@ enum EnginePhase {
sendSemanticsUpdate,
}

/// Signature of callbacks to intercept messages on a given channel.
///
/// see [TestDefaultBinaryMessenger.setMockDecodedMessageHandler] for more details.
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: s/see/See/

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done

@@ -106,6 +111,32 @@ mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
}
}

/// An accessibility announcement made by the Flutter framework.
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: this class does not represent the announcement itself, but the data captured in the test. I'd describe it as "Accessibility announcement data passed to [SemanticsService.announce] captured in a test."

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Thanks for the suggestion. I wasn't sure how to word this one.

@@ -106,6 +111,32 @@ mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
}
}

/// An accessibility announcement made by the Flutter framework.
///
/// This class is mostly used by the testing api to store the announcements
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: s/mostly/intended to be/
nit: s/api/API/

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done!

/// An accessibility announcement made by the Flutter framework.
///
/// This class is mostly used by the testing api to store the announcements
/// in a user-friendly structure so that the code consumers can check the details
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: hopefully all our API is user-friendly 😄 Instead, I'd just say "in a structured form"
nit: "code consumer" sounds confusing. Maybe say "so that tests can verify announcement details"?

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Thanks for the suggestions, Done!

return announcements;
}

/// Returns the most recent announcement made by the Flutter framework.
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

The docs should also explain what it means when this method returns null

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Changed the function to return an empty list in that case. Do you still have concerns with the documentation?

Future<void> _runTest(
Future<void> Function() testBody,
VoidCallback invariantTester,
String description,
) {
assert(description != null);
assert(inTest);

if (TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

Consider leaving a comment explaining what this does.

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Done!

@@ -821,6 +822,78 @@ void main() {
binding.postTest();
});
});

group('Accessibility announcements testing API', () {
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

We should also test that clean-up logic from postTest works. Since the clean-up takes place as part of testWidgets after the test code is done, it can be done in tearDown, for example:

tearDown(() {
  expect(checkMockMessageHandler(SystemChannels.accessibility.name, null), isTrue);
});

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Done!

@@ -821,6 +822,78 @@ void main() {
binding.postTest();
});
});

group('Accessibility announcements testing API', () {
testWidgets('Returns last announcement', (WidgetTester tester) async {
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

Similarly, as a sanity check, we could verify that the mock handler is installed, for example:

expect(checkMockMessageHandler(SystemChannels.accessibility.name, null), isFalse);

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Good point! Added the sanity check to the test.

},
]));

//remove the handler
Copy link
Contributor

@yjbanov yjbanov Oct 17, 2022

Choose a reason for hiding this comment

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

nit: // Remove...

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done!

/// Signature of callbacks to intercept messages on a given channel.
///
/// see [TestDefaultBinaryMessenger.setMockDecodedMessageHandler] for more details.
typedef _MockMessageHandler = Future<dynamic> Function(dynamic);
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

Please avoid dynamic. It turns off dart's type system. If you don't have a more specific type, Object? should work.

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Thanks for the explanation, done!

///
/// See [TestWidgetsFlutterBinding.takeAnnouncements].
class CapturedAccessibilityAnnouncement {

Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

nit: remove blank line

Copy link
Contributor Author

@nbayati nbayati Oct 17, 2022

Choose a reason for hiding this comment

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

Done!

@@ -700,13 +751,43 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}

Future<dynamic> _handleMessage(dynamic mockMessage) async {
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

Future<void> as return type and Object? mockMessage as argument?

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Good point! Done!

@@ -700,13 +751,43 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}

Future<dynamic> _handleMessage(dynamic mockMessage) async {
final Map<dynamic, dynamic> message = mockMessage as Map<dynamic, dynamic>;
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

Here and elsewhere: Object? instead of dynamic

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Done!

final CapturedAccessibilityAnnouncement announcement;

announcement = CapturedAccessibilityAnnouncement(
dataMessage, textDirection,
assertiveness: assertiveness);
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

combine this?

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Done!


/// Returns the most recent announcement made by the Flutter framework.
CapturedAccessibilityAnnouncement? peekLastAnnouncement() {
return _announcements?.last;
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

should this have the inTest assert?

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

Removed this function based on the other comments.

/// Returns the most recent announcement made by the Flutter framework.
///
/// See [TestWidgetsFlutterBinding.peekLastAnnouncement] for details.
CapturedAccessibilityAnnouncement? peekLastAnnouncement() {
Copy link
Member

@goderbauer goderbauer Oct 17, 2022

Choose a reason for hiding this comment

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

Do we need both of these APIs? Wouldn't it be enough to just have the takeAnnouncements one? If we go with both, the API docs should link to the other one in a "see also" section.

Copy link
Contributor Author

@nbayati nbayati Oct 18, 2022

Choose a reason for hiding this comment

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

I agree. Removed peekLastAnnouncement() since having the takeAnnouncements() seems enough.

@nbayati nbayati requested review from yjbanov, mdebbar and goderbauer and removed request for mdebbar Oct 18, 2022
Copy link
Contributor

@yjbanov yjbanov left a comment

LGTM but since this is a framework-side change that affects more than just the web, I think we should also look for an approval from either @chunhtai or @goderbauer.

///
/// 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.
Copy link
Contributor

@yjbanov yjbanov Oct 19, 2022

Choose a reason for hiding this comment

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

s/the/The/

Separate paragraphs by one empty line. Or if this was meant to be a continuation of the previous paragraph, there's still space on the previous line to begin this sentence.

Copy link
Contributor Author

@nbayati nbayati Oct 19, 2022

Choose a reason for hiding this comment

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

Done!

/// The accessibility message announced by the framework.
final String message;

/// The direction in which text flows.
Copy link
Contributor

@yjbanov yjbanov Oct 19, 2022

Choose a reason for hiding this comment

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

nit: I'd add "the text of the [message] flows"

Copy link
Contributor Author

@nbayati nbayati Oct 19, 2022

Choose a reason for hiding this comment

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

Done!

@@ -700,13 +747,41 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
}

Future<void> _handleMessage(Object? mockMessage) async {
Copy link
Contributor

@yjbanov yjbanov Oct 19, 2022

Choose a reason for hiding this comment

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

nit: _handleMessage sounds too generic. This is handling announcement messages specifically. Maybe call it _handleAnnouncementMessage?

Copy link
Contributor Author

@nbayati nbayati Oct 19, 2022

Choose a reason for hiding this comment

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

Done!

/// Returns a list of all the accessibility announcements made by the Flutter
/// framework since the last time this function was called.
///
/// See [TestWidgetsFlutterBinding.takeAnnouncements] for details.
Copy link
Contributor

@yjbanov yjbanov Oct 19, 2022

Choose a reason for hiding this comment

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

If the documentation can be identical, instead of pointing to another place, you can use dartdoc templates. Here's an example:

Copy link
Contributor Author

@nbayati nbayati Oct 19, 2022

Choose a reason for hiding this comment

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

Cool feature! Thanks for pointing it out.

Copy link
Contributor

@chunhtai chunhtai left a comment

LGTM once all the comments from other reviewers are addressed

Copy link
Member

@goderbauer goderbauer left a comment

LGTM

@@ -611,6 +642,24 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
late StackTraceDemangler _oldStackTraceDemangler;
FlutterErrorDetails? _pendingExceptionDetails;

_MockMessageHandler? _announcementHandler;
Copy link
Member

@goderbauer goderbauer Oct 26, 2022

Choose a reason for hiding this comment

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

Why do we need this variable? Could you just use _handleAnnouncementMessage directly wherever it is used?

expect(third.assertiveness, Assertiveness.polite);

final List<CapturedAccessibilityAnnouncement> emptyList = tester.takeAnnouncements();
expect(emptyList, <CapturedAccessibilityAnnouncement>[]);
Copy link
Member

@goderbauer goderbauer Oct 26, 2022

Choose a reason for hiding this comment

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

nit: There is the isEmpty matcher, which I think would make this slightly more readable:

Suggested change
expect(emptyList, <CapturedAccessibilityAnnouncement>[]);
expect(emptyList, isEmpty);

@nbayati nbayati added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 26, 2022
@auto-submit auto-submit bot merged commit 235a325 into flutter:master Oct 26, 2022
64 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: tests "flutter test", flutter_test, or one of our tests. autosubmit Merge PR when tree becomes green via auto submit App framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide a testing API for the announce functionality
5 participants