Testing an accessibility (semantic) announcement made using SemanticsService.announce is not straight forward. This article describes how to do so.
What does SemanticsService do?
SemanticsService manages the communication between Flutter and the OS using Platform Channels.
The announce method in this class is used to make a semantics announcement in cases where the system can’t. For example, if you have a countdown timer and want a semantic announcement to be made every 5 seconds. Its used in numerous places in the Flutter framework too.
To keep things simple and focus on how we test this method, we’ll make an announcement when a button is clicked. Check the sample code & the demo that follows:
Semantics Announcement Demo
Testing Semantic Announcement in Flutter
To test this if we’re making the correct announcement we need a way to intercept the announcement.
To be able to do so we’ll need some knowledge of what announce method does. Looking at the code, we see that it uses a platform channel with the channel name accessibility. It uses an object AnnounceSemanticsEvent internally to represent an announcement.
Flutter provides a way to mock platform channels in tests using TestDefaultBinaryMessenger. This class provides ways to capture and test any platform message by intercepting them and hooking into callbacks.
Check this code to see how the Flutter framework tests SemanticsService. All this code does is register a mock message handler that stores all data passed to the SystemChannel.accessibility channel into a map which is then used to assert.
This approach works well for the framework, but for us our unit tests would be depending on implementation details of the framework. Which is why is makes sense to abstract this away.
I’ve published a tiny package called semantic_announcement_tester, which makes testing Semantic announcements made using SemanticsService.announce dead simple by providing some matchers.
- Create an object for
MockSemanticAnnouncementsin your widget test.
- Write the test code as usual.
- Use one of the matchers:
To test one announcement:
To test N announcements made:
To test zero announcements made: