Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
run: flutter test --coverage
- name: Upload golden failures
if: always()
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ migrate_working_dir/
/pubspec.lock
/coverage
/.vscode/
**/coverage/

# Web related
lib/generated_plugin_registrant.dart
Expand Down
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,48 @@ The `GoldenCaptureConfig` class allows you to customize how multiple screenshots
- `maxScreensPerRow`: Maximum screenshots per row (for grid layout)
- `device`: Optional device configuration

### Animation Testing 🎬

For testing animations at specific timestamps, use `BcGoldenCapture.animation`:

```dart
BcGoldenCapture.animation(
'Button scale animation',
AnimatedButton(),
[
GoldenAnimationStep(
timestamp: Duration.zero,
frameName: 'start',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 150),
frameName: 'scaled',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 300),
frameName: 'end',
),
],
GoldenAnimationConfig(
testName: 'button_animation',
totalDuration: Duration(milliseconds: 300),
animationSteps: [...], // Same steps as above
layoutType: CaptureLayoutType.horizontal,
showTimelineLabels: true,
),
animationSetup: (tester) async {
// Trigger the animation
await tester.tap(find.byType(AnimatedButton));
await tester.pump();
},
);
```

The animation testing feature captures frames at specific moments in your animation timeline, creating a comprehensive visual test that shows the animation's progression. This is particularly useful for:

- **UI Transitions**: Validating smooth transitions between states
- **Loading Animations**: Ensuring consistent spinner or progress animations

## bcGoldenTest (Legacy) 🏗
The is a legacy function that is still supported but deprecated. For new tests, please use `BcGoldenCapture.single` instead. This function is default tagged with "golden" and also has additional features for the tests, see the code below:

Expand Down
182 changes: 182 additions & 0 deletions example/test/src/presentation/animations/animation_golden_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import 'package:bc_golden_plugin/bc_golden_plugin.dart';
import 'package:flutter/material.dart';

void main() {
// Test de ejemplo simple para demostrar la funcionalidad
BcGoldenCapture.animation(
'Simple fade animation test',
const SimpleFadeAnimation(),
GoldenAnimationConfig(
testName: 'simple_fade',
totalDuration: const Duration(milliseconds: 500),
animationSteps: const [
GoldenAnimationStep(
timestamp: Duration.zero,
frameName: 'start_invisible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 290),
frameName: 'half_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 320),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 340),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 360),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 380),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 400),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 420),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 440),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 460),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 480),
frameName: 'fully_visible',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 500),
frameName: 'fully_visible',
),
],
layoutType: CaptureLayoutType.horizontal,
spacing: 20.0,
showTimelineLabels: true,
device: GoldenDeviceData.iPhone13,
),
);

BcGoldenCapture.animation(
'Loading spinner rotation',
const CircularProgressIndicator(),
const GoldenAnimationConfig(
testName: 'spinner_rotation',
totalDuration: Duration(milliseconds: 1000),
showTimelineLabels: true,
animationSteps: [
GoldenAnimationStep(
timestamp: Duration.zero,
frameName: '0_degrees',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 250),
frameName: '90_degrees',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 500),
frameName: '180_degrees',
),
GoldenAnimationStep(
timestamp: Duration(milliseconds: 750),
frameName: '270_degrees',
),
], // Mismos pasos
layoutType: CaptureLayoutType.grid,
maxScreensPerRow: 2,
),
);
}

/// Widget de ejemplo simple con animación de fade
class SimpleFadeAnimation extends StatefulWidget {
const SimpleFadeAnimation({super.key});

@override
State<SimpleFadeAnimation> createState() => _SimpleFadeAnimationState();
}

class _SimpleFadeAnimationState extends State<SimpleFadeAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fadeAnimation;

@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);

_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(_controller);

// Iniciar la animación automáticamente
WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.forward();
});
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: AnimatedBuilder(
animation: _fadeAnimation,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Container(
width: 200,
height: 100,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withValues(alpha: 0.3),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: const Center(
child: Text(
'Fade Animation',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
);
},
),
),
),
);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 4 additions & 6 deletions example/test/src/presentation/home/home_page_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,8 @@ void main() {
),
);

testWidgets('Manual golden test', (tester) async {
BcGoldenCapture.single('Manual golden test', (tester) async {
await tester.runAsync(() async {
GoldenScreenshot screenshotter = GoldenScreenshot();

tester.configureWindow(
GoldenDeviceData.iPhone13,
);
Expand All @@ -81,7 +79,7 @@ void main() {

await tester.pumpAndSettle();

await screenshotter.captureScreenshot();
await tester.captureGoldenScreenshot();

await tester.tap(
find.byKey(
Expand All @@ -91,9 +89,9 @@ void main() {

await tester.pumpAndSettle();

await screenshotter.captureScreenshot();
await tester.captureGoldenScreenshot();

final combinedScreenshot = await screenshotter.combineScreenshots(
final combinedScreenshot = await tester.combineGoldenScreenshots(
GoldenCaptureConfig(
testName: 'manual_golden',
device: GoldenDeviceData.iPhone13,
Expand Down
4 changes: 3 additions & 1 deletion lib/bc_golden_plugin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
/// This library provides configuration and testing tools for the bc_golden_plugin.
library bc_golden_plugin;

export 'package:logger/src/log_level.dart';
export 'package:logger/logger.dart';

export 'src/capture/golden_animation_capture.dart';
export 'src/capture/golden_screenshot.dart';
export 'src/config/bc_golden_configuration.dart';
export 'src/config/golden_animation_config.dart';
export 'src/config/golden_capture_config.dart';
export 'src/config/golden_device_data.dart';
export 'src/config/window_configuration.dart';
Expand Down
Loading