Finder Matcher Gen
Table of contents generated with markdown-toc
A Flutter package for generating custom Finders and Matchers for widget tests.
Installation 💻
❗ In order to start using Finder Matcher Gen you must have the Dart SDK installed on your machine.
Add finder_matcher_gen
to your pubspec.yaml
:
Run the following command on your terminal:
flutter pub add finder_matcher_annotation
flutter pub add finder_matcher_gen --dev
flutter pub add build_runner --dev
Or add it manually to your pubspec.yaml file.
dependencies:
finder_matcher_annotation: ^[version]
dev_dependencies:
finder_matcher_gen: ^[version]
build_runner: ^[version]
Run the command below to install.
Install it:
flutter pub get
Copy and paste the code below into your test file to import.
import 'package:finder_matcher_annotation/finder_matcher_annotation.dart';
Annotation usage
Finder-matcher-gen makes use of annotation declarations to generate code. This tool provides two annotations: @Match
and @MatchDeclaration
annotations.
@Match annotation
Apply @Match
annotation to a declaration, usually, the test main()
function to specify widgets to generate a finder or matcher counterpart.
@Match(finders: [], matchers: [])
void main() {
//Test code in here
}
The @Match
annotation accepts two parameters: a list of Type
for finders; a list of MatchWidget
for matchers.
Finders
For a widget named TrafficLightLampWidget
pass the type of the widget to the finders param of the @Match
annotation to generate a finder counterpart.
@Match(finders: [TrafficLightLampWidget])
You can pass any number of widget types to the
finders
param to generate a finder counterpart.
Matcher
Pass a list of MatchWidget
to the matchers
param. MatchWidgets
accepts three params.
-
A required
type
: The runtime representation of this widget to generate a matcher counterpart. -
A required
matchSpecification
: An enum ofMatchSpecification
to define the kind of Matcher to generate for this widget. -
An optional
secondaryType
: The runtime representation of another widget that this Matcher will utilise.Some Matcher specifications involve a different widget. For example, to generate a matcher that asserts if
WidgetA
is contained inWidgetB
,WidgetB
will be passed as thesecondaryType
.
@Match(matchers: [
MatchWidget(TrafficLightLampWidget, MatchSpecification.matchesOneWidget),
])
To learn more about the different match specifications you can set, click here.
@MatchDeclaration annotation
In most cases, declarations (getters, fields, functions) defined in a widget are essential to the widget’s identity. In other words, they will be used for asserting this widget behaviour.
Annotate widget fields, getters, or functions with @MatchDeclaration
to mark them for use in the validation code. The @MatchDeclaration
annotation accepts a defaultValue
argument used to compare to the actual value of the widget found in the test environment. A constructor field for this declaration will be added to the generated code if no default value is provided.
class RedTrafficLightLampWidget extends StatelessWidget{
@MatchDeclaration()
final Color lightColor;
@MatchDeclaration(defaultValue: 'STOP')
final String text;
}
The code below highlights the result of providing a default value and otherwise.
/// Where `_lightColor` is a constructor field of this generated code
return widget.lightColor == _lightColor && widget.text == 'STOP';
Linting
A common pitfall while using this annotation is passing a wrong data type (different from the data type of the annotated property) to the defaultValue
.
Fortunately, this package provides static analysis to throw an error when this kind of mistake is made.
Note: The annotation
@MatchDeclaration
can only be used on getters, fields, and non-void methods
Generate code
Run the command below to generate the custom finder and matcher code.
flutter pub run build_runner build
After a successful run, you should notice two newly generated files.
- A
${my_test_file}.finders.dart
file containing generated finders. - A
${my_test_file}.matchers.dart
file containing generated matchers.
For more information, see generate section to explore how to use generated files.
Detailed Documentation
For more detailed information of using this tool, visit the documentation.
Continuous Integration 🤖
Finder Matcher Gen comes with a built-in GitHub Actions workflow powered by Very Good Workflows but you can also add your preferred CI/CD solution.
Out of the box, on each pull request and push, the CI formats
, lints
, and tests
the code. This ensures the code remains consistent and behaves correctly as you add functionality or make changes. The project uses Very Good Analysis for a strict set of analysis options used by our team. Code coverage is enforced using the Very Good Workflows.
Running Tests 🧪
To run all unit tests:
dart pub global activate coverage 1.2.0
dart test --coverage=coverage
dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info
To view the generated coverage report you can use lcov.
# Generate Coverage Report
genhtml coverage/lcov.info -o coverage/
# Open Coverage Report
open coverage/index.html