Skip to content

Commit ded7bb5

Browse files
committed
@ r sync: added --help and --lest helpers to cli command
1 parent 0c3cac6 commit ded7bb5

File tree

13 files changed

+230
-44
lines changed

13 files changed

+230
-44
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,22 @@ After running the command, the files will be analyzed and you will be asked to c
149149
- `n` - Reject the received file.
150150
- `v`iew - 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.
151151

152+
The command `dart run approval_tests:review` has additional options, including listing files, selecting
153+
files to review from this list by index, and more. For its current capabilities, run
154+
```bash
155+
dart run approval_tests:review --help
156+
```
157+
Typing 'dart run approval_tests:review' is tedious! To reduce your typing, alias the command in your
158+
`.zshrc` or `.bashrc` file
159+
```
160+
alias review='dart run approval_tests:review'
161+
```
162+
or PowerShell profile
163+
```shell
164+
function review {
165+
dart run approval_tests:review
166+
}
167+
```
152168
#### • Via approveResult property
153169
If you want the result to be automatically saved after running the test, you need to use the `approveResult` property in `Options`:
154170

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/Users/yelamanyelmuratov/Development/approvals/ApprovalTests.Dart/examples/flutter_example/test/widget_test.smoke_test.should_display_1.received.txt
2+
/Users/yelamanyelmuratov/Development/approvals/ApprovalTests.Dart/examples/flutter_example/test/widget_test.smoke_test.should_display_0.received.txt

examples/flutter_example/test/widget_test.dart

+3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ void main() {
1313

1414
await tester.approvalTest(
1515
description: 'should display 0',
16+
options: const Options(deleteReceivedFile: false),
1617
);
1718

19+
await tester.tap(find.byType(FloatingActionButton));
1820
await tester.tap(find.byType(FloatingActionButton));
1921
await tester.tap(find.byType(FloatingActionButton));
2022
await tester.pumpAndSettle();
2123

2224
await tester.approvalTest(
2325
description: 'should display 1',
26+
options: const Options(deleteReceivedFile: false),
2427
);
2528
});
2629
});

examples/flutter_example/test/widget_test.smoke_test.should_display_0.approved.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
MyApp: {count: 1}
44
MyHomePage: {count: 1}
5-
Text: {text: 'You have pushed the button this many times:', count: 1}
6-
Text: {key: 'Counter', text: '0', count: 1}
7-
Text: {text: 'Approved Example', count: 1}
5+
Text: {data: 'You have pushed the button this many times:', count: 1}
6+
Text: {key: 'Counter', data: '0', count: 1}
7+
Text: {data: 'Approved Example', count: 1}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# This file was generated by approval_tests. Please do not edit.
22

3-
Text: {key: 'Counter', text: '2', count: 1}
4-
Text: {key: 'Counter', text: '0', count: 0}
3+
Text: {key: 'Counter', data: '3', count: 1}
4+
Text: {key: 'Counter', data: '0', count: 0}
+178-35
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,190 @@
1-
// ignore_for_file: avoid_print
2-
31
import 'dart:io';
42

53
import 'package:approval_tests/approval_tests.dart';
64

7-
void main() async {
8-
final searchDirectory = Directory.current;
9-
5+
void main(List<String> args) async {
106
final List<Future<void>> tasks = [];
7+
bool isProcessingTasks = false;
8+
9+
void processUnapprovedFile(File receivedFile) {
10+
if (!receivedFile.existsSync()) {
11+
ApprovalLogger.exception(
12+
'Error: the file below does not exist for review comparison:',
13+
);
14+
ApprovalLogger.exception(receivedFile.path);
15+
return;
16+
}
17+
18+
final approvedFileName =
19+
receivedFile.path.replaceAll('.received.txt', '.approved.txt');
20+
final approvedFile = File(approvedFileName);
21+
22+
if (approvedFile.existsSync()) {
23+
tasks.add(processFile(approvedFile, receivedFile));
24+
} else {
25+
tasks.add(processFile(null, receivedFile));
26+
}
27+
}
1128

12-
/// Recursively search for current files
13-
await for (final file in searchDirectory.list(recursive: true)) {
14-
if (file.path.endsWith('.received.txt')) {
15-
final reviewFile = file;
16-
final approvedFileName =
17-
file.path.replaceAll('.received.txt', '.approved.txt');
18-
final approvedFile = File(approvedFileName);
29+
Future<List<File>> getUnapprovedFiles() async {
30+
final files = <File>[];
31+
final searchDirectory = Directory.current;
1932

20-
if (approvedFile.existsSync()) {
21-
tasks.add(processFile(approvedFile, reviewFile));
33+
await for (final file in searchDirectory.list(recursive: true)) {
34+
if (file.path.endsWith('.received.txt')) {
35+
files.add(file as File);
2236
}
2337
}
38+
39+
return files;
2440
}
2541

26-
await Future.wait(tasks);
42+
/// If no args, then searching the whole project
43+
if (args.isEmpty || args[0].isEmpty) {
44+
for (final file in await getUnapprovedFiles()) {
45+
if (file.path.endsWith('.received.txt')) {
46+
isProcessingTasks = true;
47+
processUnapprovedFile(file);
48+
}
49+
}
50+
} else {
51+
/// If here, have args. If arg is an option...
52+
if (args[0][0] == '-') {
53+
if (args[0] == '--help') {
54+
ApprovalLogger.log('''
55+
Manage your package:approval_tests files.
56+
57+
Common usage:
58+
59+
dart run approval_tests:review
60+
Reviews all project .received.txt files
61+
62+
dart run approval_tests:review --list
63+
List project's .received.txt files
2764
28-
ApprovalLogger.success(
29-
'Review process completed: ${tasks.length} files reviewed.',
30-
);
65+
Usage: dart run approval_tests:review [arguments]
66+
67+
Arguments:
68+
--help Print this usage information.
69+
--list Print a list of project .received.txt files.
70+
<index> Review an .received.txt file indexed by --list.
71+
<path/to/.received.txt> Review an .received.txt file.''');
72+
} else if (args[0] == '--list') {
73+
final unapprovedFiles = await getUnapprovedFiles();
74+
final fileCount = unapprovedFiles.length;
75+
for (int i = 0; i < fileCount; i++) {
76+
ApprovalLogger.log(
77+
'${i.toString().padLeft(3)} ${unapprovedFiles[i].path}',
78+
);
79+
}
80+
ApprovalLogger.log('Found $fileCount received files.');
81+
if (fileCount > 0) {
82+
ApprovalLogger.log(
83+
"\nTo review one, run: dart run approval_tests:review <index>\nTo review all, run: dart run approval_tests:review",
84+
);
85+
}
86+
87+
writeUnapprovedFiles(unapprovedFiles);
88+
} else {
89+
ApprovalLogger.log(
90+
"Unknown option '${args[0]}'. See '--help' for more details.",
91+
);
92+
}
93+
} else {
94+
/// If here, arg is a path or an index in the list of paths
95+
File? unapprovedFile;
96+
final arg = args[0];
97+
final int? maybeIntValue = int.tryParse(arg);
98+
if (maybeIntValue == null) {
99+
unapprovedFile = File(arg);
100+
} else {
101+
final unapprovedFilePaths = readReceivedFiles();
102+
if (maybeIntValue >= 0 && maybeIntValue < unapprovedFilePaths.length) {
103+
unapprovedFile = File(unapprovedFilePaths[maybeIntValue]);
104+
} else {
105+
ApprovalLogger.log(
106+
'No received file with an index of $maybeIntValue',
107+
);
108+
}
109+
}
110+
if (unapprovedFile != null) {
111+
isProcessingTasks = true;
112+
processUnapprovedFile(unapprovedFile);
113+
}
114+
}
115+
}
116+
117+
if (isProcessingTasks) {
118+
if (tasks.isEmpty) {
119+
ApprovalLogger.exception('No received test results to review!');
120+
} else {
121+
final tasksCount = tasks.length;
122+
await Future.wait(tasks);
123+
ApprovalLogger.success(
124+
'Review completed. $tasksCount test results reviewed.',
125+
);
126+
}
127+
}
31128
}
32129

33-
/// Check of the files are different using "git diff"
34-
Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
35-
final resultString = GitReporter.gitDiffFiles(approvedFile, reviewFile);
130+
void writeUnapprovedFiles(List<File>? unapprovedFiles) {
131+
final file = File(ApprovalTestsConstants.receivedFilesPath)
132+
..createSync(recursive: true);
133+
if (unapprovedFiles == null) {
134+
file.writeAsStringSync('');
135+
} else {
136+
file.writeAsStringSync(unapprovedFiles.map((file) => file.path).join('\n'));
137+
}
138+
}
139+
140+
List<String> readReceivedFiles() {
141+
List<String> result = <String>[];
36142

143+
final file = File(ApprovalTestsConstants.receivedFilesPath);
144+
if (file.existsSync()) {
145+
final String fileContents = file.readAsStringSync();
146+
result = fileContents.split('\n');
147+
} else {
148+
result = [];
149+
}
150+
151+
return result;
152+
}
153+
154+
/// Check of the files are different using "git diff"
155+
Future<void> processFile(File? approvedFile, File receivedFile) async {
156+
late String resultString;
37157
ComparatorIDE comparatorIDE = ComparatorIDE.vsCode;
38158

39-
if (resultString.isNotEmpty || resultString.isNotEmpty) {
40-
// final String fileNameWithoutExtension =
41-
// approvedFile.path.split('/').last.split('.').first;
42-
// GitReporter.printGitDiffs(fileNameWithoutExtension, resultString);
43-
const CommandLineReporter().report(approvedFile.path, reviewFile.path);
159+
if (approvedFile == null) {
160+
final unapprovedText = receivedFile.readAsStringSync();
161+
resultString = "Data in '${receivedFile.path}':\n$unapprovedText";
162+
} else {
163+
final gitDiff = GitReporter.gitDiffFiles(approvedFile, receivedFile);
164+
resultString = gitDiff;
165+
}
166+
167+
if (resultString.isNotEmpty) {
168+
GitReporter.printGitDiffs(receivedFile.path, resultString, showTip: false);
44169

45170
String? firstCharacter;
46171

47172
do {
48173
stdout.write('Accept changes? (y/N/[v]iew): ');
49174
final response = stdin.readLineSync()?.trim().toLowerCase();
50175

51-
if (response == null || response.isEmpty) {
52-
firstCharacter = null;
53-
} else {
176+
firstCharacter = null;
177+
if (response != null && response.isNotEmpty) {
54178
firstCharacter = response[0];
55179
}
56180

181+
final receivedFilename = receivedFile.path;
182+
final approvedFilename = receivedFile.path
183+
.replaceAll(Namer.receivedExtension, Namer.approvedExtension);
184+
57185
if (firstCharacter == 'y') {
58-
await approvedFile.delete();
59-
await reviewFile.rename(approvedFile.path);
186+
await approvedFile?.delete();
187+
await receivedFile.rename(approvedFilename);
60188
ApprovalLogger.success('Approval test approved');
61189
} else if (firstCharacter == 'v') {
62190
stdout.write('Enter diff tool (code, studio): ');
@@ -68,12 +196,19 @@ Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
68196
}
69197
final diffReporter = DiffReporter(ide: comparatorIDE);
70198
if (diffReporter.isReporterAvailable) {
71-
final approvedFilename = approvedFile.path;
72-
final reviewFilename = reviewFile.path;
199+
final approvedFilename = approvedFile?.path;
200+
73201
ApprovalLogger.log(
74-
"Executing '${diffReporter.defaultDiffInfo.command} ${diffReporter.defaultDiffInfo.arg} $approvedFilename $reviewFilename'",
202+
"Executing '${diffReporter.defaultDiffInfo.command} ${diffReporter.defaultDiffInfo.arg} $approvedFilename $receivedFilename'",
75203
);
76-
await diffReporter.report(approvedFilename, reviewFilename);
204+
if (approvedFilename != null) {
205+
await diffReporter.report(approvedFilename, receivedFilename);
206+
} else {
207+
final processResult = Process.runSync('code', [receivedFilename]);
208+
ApprovalLogger.log(
209+
'______processResult: ${processResult.toString()}',
210+
);
211+
}
77212
} else {
78213
ApprovalLogger.warning(
79214
'No diff tool available: please check:\nName: ${diffReporter.defaultDiffInfo.name}\nPath:${diffReporter.defaultDiffInfo.command}',
@@ -83,5 +218,13 @@ Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
83218
ApprovalLogger.exception('Approval test rejected');
84219
}
85220
} while (firstCharacter == 'v');
221+
} else {
222+
ApprovalLogger.success('No differences found. Approval test approved.');
86223
}
87224
}
225+
226+
bool isCodeCommandAvailable() {
227+
final result = Process.runSync('which', ['code']);
228+
229+
return result.exitCode == 0;
230+
}

packages/approval_tests/lib/approval_tests.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import 'dart:convert';
2020
import 'dart:io';
2121
import 'dart:math';
2222

23-
import 'package:approval_tests/src/core/constants/constants.dart';
2423
import 'package:approval_tests/src/core/enums/file_type.dart';
2524
import 'package:diff_match_patch2/diff_match_patch.dart';
2625
import 'package:talker/talker.dart';
@@ -58,3 +57,4 @@ part 'src/scrubbers/nothing_scrubber.dart';
5857
part 'src/scrubbers/reg_exp_scrubber.dart';
5958
part 'src/writers/approval_text_writer.dart';
6059
part 'src/reporters/git.dart';
60+
part 'src/core/constants/constants.dart';
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
part of '../../../approval_tests.dart';
2+
13
final class ApprovalTestsConstants {
24
static const String widgetHeader = '''
35
# This file was autogenerated by package:approval_tests_flutter. Please do not edit.
46
# Below is a list of class found in the project /lib folder.''';
57

68
static const String baseHeader = '''
79
# This file was generated by approval_tests. Please do not edit.\n''';
10+
11+
static const resourceLocalPath = './test/.approval_tests';
12+
static const receivedFilesPath = '$resourceLocalPath/received_files.txt';
813
}

packages/approval_tests/lib/src/reporters/git.dart

+14
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,18 @@ class GitReporter implements Reporter {
8383
// );
8484
// ApprovalLogger.log(differences.trim());
8585
// }
86+
87+
static void printGitDiffs(
88+
String unapprovedFullPath,
89+
String differences, {
90+
bool showTip = true,
91+
}) {
92+
ApprovalLogger.log("Results of git diff:\n${differences.trim()}");
93+
if (showTip) {
94+
ApprovalLogger.log(
95+
"To review, run: dart run approved:review '$unapprovedFullPath'",
96+
);
97+
ApprovalLogger.log("To review all, run: dart run approved:review");
98+
}
99+
}
86100
}

packages/approval_tests_flutter/lib/src/get_widget_names.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import 'package:analyzer/dart/analysis/context_builder.dart';
66
import 'package:analyzer/dart/analysis/context_locator.dart';
77
import 'package:analyzer/dart/analysis/results.dart';
88
import 'package:analyzer/dart/ast/ast.dart';
9+
import 'package:approval_tests/approval_tests.dart';
910
import 'package:approval_tests_flutter/src/common.dart';
1011

11-
final _widgetNamesDir = Directory('./test/approved');
12+
final _widgetNamesDir = Directory(ApprovalTestsConstants.resourceLocalPath);
1213
final _widgetNamesPath = '${_widgetNamesDir.path}/class_names.txt';
1314

1415
Future<Set<String>> getWidgetNames() async {

0 commit comments

Comments
 (0)