Hi there, I already wrote an article about ApprovalTests for unit tests.
In this article we will touch on Widget tests and how this package can be useful for us.
Let’s briefly go through again what exactly are ApprovalTests?
In manual code testing, developers usually write automated tests to guard against regressions, specifying the expected outcomes directly in the code. ApprovalTests uses a similar method but stores the expected outcomes in a file instead. This file is generated by the test library rather than the developer, making the process of writing and maintaining tests more efficient. As a result, developers can spend more time on the functional code rather than the test code.
📋 How it works step by step
The first run of the test automatically creates an approved file if there is no such file.
If the changed results match the approved file perfectly, the test passes.
If there’s a difference, a reporter tool will highlight the mismatch and the test fails.
If the test is passed, the received file is deleted automatically. You can change this by changing the deleteReceivedFile value in options. If the test fails, the received file remains for analysis.
Instead of writing:
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
expect(find.text(‘You have pushed the button this many times:’), findsOneWidget);
expect(find.text(‘0’), findsOneWidget);
expect(find.byWidgetPredicate(
(Widget widget) => widget is Text && widget.data == ‘hello’ &&
widget.key == ValueKey(‘myKey’),
), findsOneWidget);
expect(find.text(‘Approved Example’), findsOneWidget);
});
Write this:
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
await tester.approvalTest();
});
To include your project’s custom widget types in your test, and to perform post-test checks, add calls to Approved.setUpAll() to your tests’ setUpAll calls, like so:
setUpAll(() {
Approved.setUpAll();
});
}
And the result will be something like this:
But if we for example change something and run the text, it will show us the difference, where it differs. There are several types of Reporter in the project, but the standard is CommandLineReporter, which gives the difference on the command line. Other reporters can be found in the project’s Github repository.
Approving Results
Approving results just means saving the .approved.txt file with your desired results.
We’ll provide more explanation in due course, but, briefly, here are the most common approaches to do this.
• Via Diff Tool
Most diff tools have the ability to move text from left to right, and save the result.
How to use diff tools is just below, there is a Comparator class for that.
• Via CLI command
You can run the command in a terminal to review your files:
After running the command, the files will be analyzed and you will be asked to choose one of the options:
y – Approve the received file.
n – Reject the received file.
view – View the differences between the received and approved files. After selecting v you will be asked which IDE you want to use to view the differences.
The command dart run approval_tests:review has additional options, including listing files, selecting
files to review from this list by index, and more. For its current capabilities, run
• Via approveResult property
If you want the result to be automatically saved after running the test, you need to use the approveResult property in Options:
test(‘test JSON object’, () {
final complexObject = {
‘name’: ‘JsonTest’,
‘features’: [‘Testing’, ‘JSON’],
‘version’: 0.1,
};
Approvals.verifyAsJson(
complexObject,
options: const Options(
approveResult: true,
),
);
});
}
this will result in the following file
example_test.test_JSON_object.approved.txt
“name”: “JsonTest”,
“features”: [
“Testing”,
“JSON”
],
“version”: 0.1
}
• Via file rename
You can just rename the .received file to .approved.
❓ Which File Artifacts to Exclude from Source Control
You must add any approved files to your source control system. But received files can change with any run and should be ignored. For Git, add this to your .gitignore:
Show some 💙 and star the repo to support the project! 🫰
For any questions, feel free to reach out via Telegram or email at yelaman.yelmuratov@gmail.com.