Skip to content

Commit

Permalink
@ r sync: added --help and --lest helpers to cli command
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jul 2, 2024
1 parent 0c3cac6 commit ded7bb5
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 44 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,22 @@ After running the command, the files will be analyzed and you will be asked to c
- `n` - Reject the received file.
- `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.

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
```bash
dart run approval_tests:review --help
```
Typing 'dart run approval_tests:review' is tedious! To reduce your typing, alias the command in your
`.zshrc` or `.bashrc` file
```
alias review='dart run approval_tests:review'
```
or PowerShell profile
```shell
function review {
dart run approval_tests:review
}
```
#### • 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`:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/Users/yelamanyelmuratov/Development/approvals/ApprovalTests.Dart/examples/flutter_example/test/widget_test.smoke_test.should_display_1.received.txt
/Users/yelamanyelmuratov/Development/approvals/ApprovalTests.Dart/examples/flutter_example/test/widget_test.smoke_test.should_display_0.received.txt
3 changes: 3 additions & 0 deletions examples/flutter_example/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ void main() {

await tester.approvalTest(
description: 'should display 0',
options: const Options(deleteReceivedFile: false),
);

await tester.tap(find.byType(FloatingActionButton));
await tester.tap(find.byType(FloatingActionButton));
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();

await tester.approvalTest(
description: 'should display 1',
options: const Options(deleteReceivedFile: false),
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

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

Text: {key: 'Counter', text: '2', count: 1}
Text: {key: 'Counter', text: '0', count: 0}
Text: {key: 'Counter', data: '3', count: 1}
Text: {key: 'Counter', data: '0', count: 0}
213 changes: 178 additions & 35 deletions packages/approval_tests/bin/review.dart
Original file line number Diff line number Diff line change
@@ -1,62 +1,190 @@
// ignore_for_file: avoid_print

import 'dart:io';

import 'package:approval_tests/approval_tests.dart';

void main() async {
final searchDirectory = Directory.current;

void main(List<String> args) async {
final List<Future<void>> tasks = [];
bool isProcessingTasks = false;

void processUnapprovedFile(File receivedFile) {
if (!receivedFile.existsSync()) {
ApprovalLogger.exception(
'Error: the file below does not exist for review comparison:',
);
ApprovalLogger.exception(receivedFile.path);
return;
}

final approvedFileName =
receivedFile.path.replaceAll('.received.txt', '.approved.txt');
final approvedFile = File(approvedFileName);

if (approvedFile.existsSync()) {
tasks.add(processFile(approvedFile, receivedFile));
} else {
tasks.add(processFile(null, receivedFile));
}
}

/// Recursively search for current files
await for (final file in searchDirectory.list(recursive: true)) {
if (file.path.endsWith('.received.txt')) {
final reviewFile = file;
final approvedFileName =
file.path.replaceAll('.received.txt', '.approved.txt');
final approvedFile = File(approvedFileName);
Future<List<File>> getUnapprovedFiles() async {
final files = <File>[];
final searchDirectory = Directory.current;

if (approvedFile.existsSync()) {
tasks.add(processFile(approvedFile, reviewFile));
await for (final file in searchDirectory.list(recursive: true)) {
if (file.path.endsWith('.received.txt')) {
files.add(file as File);
}
}

return files;
}

await Future.wait(tasks);
/// If no args, then searching the whole project
if (args.isEmpty || args[0].isEmpty) {
for (final file in await getUnapprovedFiles()) {
if (file.path.endsWith('.received.txt')) {
isProcessingTasks = true;
processUnapprovedFile(file);
}
}
} else {
/// If here, have args. If arg is an option...
if (args[0][0] == '-') {
if (args[0] == '--help') {
ApprovalLogger.log('''
Manage your package:approval_tests files.
Common usage:
dart run approval_tests:review
Reviews all project .received.txt files
dart run approval_tests:review --list
List project's .received.txt files
ApprovalLogger.success(
'Review process completed: ${tasks.length} files reviewed.',
);
Usage: dart run approval_tests:review [arguments]
Arguments:
--help Print this usage information.
--list Print a list of project .received.txt files.
<index> Review an .received.txt file indexed by --list.
<path/to/.received.txt> Review an .received.txt file.''');
} else if (args[0] == '--list') {
final unapprovedFiles = await getUnapprovedFiles();
final fileCount = unapprovedFiles.length;
for (int i = 0; i < fileCount; i++) {
ApprovalLogger.log(
'${i.toString().padLeft(3)} ${unapprovedFiles[i].path}',
);
}
ApprovalLogger.log('Found $fileCount received files.');
if (fileCount > 0) {
ApprovalLogger.log(
"\nTo review one, run: dart run approval_tests:review <index>\nTo review all, run: dart run approval_tests:review",
);
}

writeUnapprovedFiles(unapprovedFiles);
} else {
ApprovalLogger.log(
"Unknown option '${args[0]}'. See '--help' for more details.",
);
}
} else {
/// If here, arg is a path or an index in the list of paths
File? unapprovedFile;
final arg = args[0];
final int? maybeIntValue = int.tryParse(arg);
if (maybeIntValue == null) {
unapprovedFile = File(arg);
} else {
final unapprovedFilePaths = readReceivedFiles();
if (maybeIntValue >= 0 && maybeIntValue < unapprovedFilePaths.length) {
unapprovedFile = File(unapprovedFilePaths[maybeIntValue]);
} else {
ApprovalLogger.log(
'No received file with an index of $maybeIntValue',
);
}
}
if (unapprovedFile != null) {
isProcessingTasks = true;
processUnapprovedFile(unapprovedFile);
}
}
}

if (isProcessingTasks) {
if (tasks.isEmpty) {
ApprovalLogger.exception('No received test results to review!');
} else {
final tasksCount = tasks.length;
await Future.wait(tasks);
ApprovalLogger.success(
'Review completed. $tasksCount test results reviewed.',
);
}
}
}

/// Check of the files are different using "git diff"
Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
final resultString = GitReporter.gitDiffFiles(approvedFile, reviewFile);
void writeUnapprovedFiles(List<File>? unapprovedFiles) {
final file = File(ApprovalTestsConstants.receivedFilesPath)
..createSync(recursive: true);
if (unapprovedFiles == null) {
file.writeAsStringSync('');
} else {
file.writeAsStringSync(unapprovedFiles.map((file) => file.path).join('\n'));
}
}

List<String> readReceivedFiles() {
List<String> result = <String>[];

final file = File(ApprovalTestsConstants.receivedFilesPath);
if (file.existsSync()) {
final String fileContents = file.readAsStringSync();
result = fileContents.split('\n');
} else {
result = [];
}

return result;
}

/// Check of the files are different using "git diff"
Future<void> processFile(File? approvedFile, File receivedFile) async {
late String resultString;
ComparatorIDE comparatorIDE = ComparatorIDE.vsCode;

if (resultString.isNotEmpty || resultString.isNotEmpty) {
// final String fileNameWithoutExtension =
// approvedFile.path.split('/').last.split('.').first;
// GitReporter.printGitDiffs(fileNameWithoutExtension, resultString);
const CommandLineReporter().report(approvedFile.path, reviewFile.path);
if (approvedFile == null) {
final unapprovedText = receivedFile.readAsStringSync();
resultString = "Data in '${receivedFile.path}':\n$unapprovedText";
} else {
final gitDiff = GitReporter.gitDiffFiles(approvedFile, receivedFile);
resultString = gitDiff;
}

if (resultString.isNotEmpty) {
GitReporter.printGitDiffs(receivedFile.path, resultString, showTip: false);

String? firstCharacter;

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

if (response == null || response.isEmpty) {
firstCharacter = null;
} else {
firstCharacter = null;
if (response != null && response.isNotEmpty) {
firstCharacter = response[0];
}

final receivedFilename = receivedFile.path;
final approvedFilename = receivedFile.path
.replaceAll(Namer.receivedExtension, Namer.approvedExtension);

if (firstCharacter == 'y') {
await approvedFile.delete();
await reviewFile.rename(approvedFile.path);
await approvedFile?.delete();
await receivedFile.rename(approvedFilename);
ApprovalLogger.success('Approval test approved');
} else if (firstCharacter == 'v') {
stdout.write('Enter diff tool (code, studio): ');
Expand All @@ -68,12 +196,19 @@ Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
}
final diffReporter = DiffReporter(ide: comparatorIDE);
if (diffReporter.isReporterAvailable) {
final approvedFilename = approvedFile.path;
final reviewFilename = reviewFile.path;
final approvedFilename = approvedFile?.path;

ApprovalLogger.log(
"Executing '${diffReporter.defaultDiffInfo.command} ${diffReporter.defaultDiffInfo.arg} $approvedFilename $reviewFilename'",
"Executing '${diffReporter.defaultDiffInfo.command} ${diffReporter.defaultDiffInfo.arg} $approvedFilename $receivedFilename'",
);
await diffReporter.report(approvedFilename, reviewFilename);
if (approvedFilename != null) {
await diffReporter.report(approvedFilename, receivedFilename);
} else {
final processResult = Process.runSync('code', [receivedFilename]);
ApprovalLogger.log(
'______processResult: ${processResult.toString()}',
);
}
} else {
ApprovalLogger.warning(
'No diff tool available: please check:\nName: ${diffReporter.defaultDiffInfo.name}\nPath:${diffReporter.defaultDiffInfo.command}',
Expand All @@ -83,5 +218,13 @@ Future<void> processFile(File approvedFile, FileSystemEntity reviewFile) async {
ApprovalLogger.exception('Approval test rejected');
}
} while (firstCharacter == 'v');
} else {
ApprovalLogger.success('No differences found. Approval test approved.');
}
}

bool isCodeCommandAvailable() {
final result = Process.runSync('which', ['code']);

return result.exitCode == 0;
}
2 changes: 1 addition & 1 deletion packages/approval_tests/lib/approval_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:approval_tests/src/core/constants/constants.dart';
import 'package:approval_tests/src/core/enums/file_type.dart';
import 'package:diff_match_patch2/diff_match_patch.dart';
import 'package:talker/talker.dart';
Expand Down Expand Up @@ -58,3 +57,4 @@ part 'src/scrubbers/nothing_scrubber.dart';
part 'src/scrubbers/reg_exp_scrubber.dart';
part 'src/writers/approval_text_writer.dart';
part 'src/reporters/git.dart';
part 'src/core/constants/constants.dart';
5 changes: 5 additions & 0 deletions packages/approval_tests/lib/src/core/constants/constants.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
part of '../../../approval_tests.dart';

final class ApprovalTestsConstants {
static const String widgetHeader = '''
# This file was autogenerated by package:approval_tests_flutter. Please do not edit.
# Below is a list of class found in the project /lib folder.''';

static const String baseHeader = '''
# This file was generated by approval_tests. Please do not edit.\n''';

static const resourceLocalPath = './test/.approval_tests';
static const receivedFilesPath = '$resourceLocalPath/received_files.txt';
}
14 changes: 14 additions & 0 deletions packages/approval_tests/lib/src/reporters/git.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,18 @@ class GitReporter implements Reporter {
// );
// ApprovalLogger.log(differences.trim());
// }

static void printGitDiffs(
String unapprovedFullPath,
String differences, {
bool showTip = true,
}) {
ApprovalLogger.log("Results of git diff:\n${differences.trim()}");
if (showTip) {
ApprovalLogger.log(
"To review, run: dart run approved:review '$unapprovedFullPath'",
);
ApprovalLogger.log("To review all, run: dart run approved:review");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import 'package:analyzer/dart/analysis/context_builder.dart';
import 'package:analyzer/dart/analysis/context_locator.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:approval_tests/approval_tests.dart';
import 'package:approval_tests_flutter/src/common.dart';

final _widgetNamesDir = Directory('./test/approved');
final _widgetNamesDir = Directory(ApprovalTestsConstants.resourceLocalPath);
final _widgetNamesPath = '${_widgetNamesDir.path}/class_names.txt';

Future<Set<String>> getWidgetNames() async {
Expand Down
Loading

0 comments on commit ded7bb5

Please sign in to comment.