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
310 changes: 310 additions & 0 deletions packages/mix/test/src/animation/animation_config_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:mix/mix.dart';
import 'package:mix/src/animation/animation_config.dart';

import '../../helpers/testing_utils.dart';

void main() {
group('AnimationConfig', () {
group('CurveAnimationConfig', () {
Expand Down Expand Up @@ -63,6 +65,182 @@ void main() {
config.onEnd!();
expect(called, true);
});

group('delay', () {
test('defaults to Duration.zero', () {
final config = AnimationConfig.curve(
duration: const Duration(seconds: 1),
curve: Curves.linear,
);

expect((config as CurveAnimationConfig).delay, Duration.zero);
});

test('stores custom delay value', () {
final config = AnimationConfig.curve(
duration: const Duration(seconds: 1),
curve: Curves.linear,
delay: const Duration(milliseconds: 500),
);

expect(
(config as CurveAnimationConfig).delay,
const Duration(milliseconds: 500),
);
});

test('delay is included in equality check', () {
final config1 = AnimationConfig.curve(
duration: const Duration(seconds: 1),
curve: Curves.linear,
delay: const Duration(milliseconds: 100),
);
final config2 = AnimationConfig.curve(
duration: const Duration(seconds: 1),
curve: Curves.linear,
delay: const Duration(milliseconds: 200),
);

expect(config1, isNot(equals(config2)));
});
});

group('totalDuration', () {
test('equals duration when no delay', () {
const config = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.linear,
);

expect(config.totalDuration, const Duration(seconds: 1));
});

test('equals duration plus delay', () {
const config = CurveAnimationConfig(
duration: Duration(milliseconds: 500),
curve: Curves.linear,
delay: Duration(milliseconds: 200),
);

expect(config.totalDuration, const Duration(milliseconds: 700));
});
});

group('copyWith', () {
test('returns new instance with same values when no args', () {
const original = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.easeIn,
delay: Duration(milliseconds: 100),
);

final copy = original.copyWith();

expect(copy.duration, original.duration);
expect(copy.curve, original.curve);
expect(copy.delay, original.delay);
expect(copy, isNot(same(original)));
});

test('updates duration only', () {
const original = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.easeIn,
);

final copy = original.copyWith(
duration: const Duration(seconds: 2),
);

expect(copy.duration, const Duration(seconds: 2));
expect(copy.curve, Curves.easeIn);
});

test('updates curve only', () {
const original = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.easeIn,
);

final copy = original.copyWith(curve: Curves.bounceOut);

expect(copy.duration, const Duration(seconds: 1));
expect(copy.curve, Curves.bounceOut);
});

test('updates delay only', () {
const original = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.linear,
);

final copy = original.copyWith(
delay: const Duration(milliseconds: 500),
);

expect(copy.delay, const Duration(milliseconds: 500));
});

test('updates onEnd callback', () {
bool called = false;
const original = CurveAnimationConfig(
duration: Duration(seconds: 1),
curve: Curves.linear,
);

final copy = original.copyWith(onEnd: () => called = true);

expect(copy.onEnd, isNotNull);
copy.onEnd!();
expect(called, true);
});
});

group('withDefaults', () {
test('creates config with default duration', () {
final config = AnimationConfig.withDefaults();

expect(config.duration, const Duration(milliseconds: 200));
});

test('creates config with linear curve', () {
final config = AnimationConfig.withDefaults();

expect(config.curve, Curves.linear);
});
});

group('spring factory methods', () {
test('spring creates CurveAnimationConfig with SpringCurve', () {
final config = CurveAnimationConfig.spring(
const Duration(milliseconds: 500),
mass: 1.0,
stiffness: 200.0,
damping: 15.0,
);

expect(config.duration, const Duration(milliseconds: 500));
expect(config.curve, isNotNull);
});

test('springWithDampingRatio creates config with ratio', () {
final config = CurveAnimationConfig.springWithDampingRatio(
const Duration(milliseconds: 500),
ratio: 0.8,
);

expect(config.duration, const Duration(milliseconds: 500));
});

test('springDurationBased creates config with bounce', () {
final config = CurveAnimationConfig.springDurationBased(
const Duration(milliseconds: 500),
bounce: 0.3,
);

expect(config.duration, const Duration(milliseconds: 500));
});
});
});

group('SpringAnimationConfig', () {
Expand Down Expand Up @@ -169,4 +347,136 @@ void main() {
});
});
});

group('PhaseAnimationConfig', () {
test('stores all required parameters', () {
final trigger = ValueNotifier(false);
final styles = [MockStyle(0.0), MockStyle(1.0)];
final curveConfigs = [
const CurveAnimationConfig(
duration: Duration(milliseconds: 100),
curve: Curves.easeIn,
),
const CurveAnimationConfig(
duration: Duration(milliseconds: 200),
curve: Curves.easeOut,
),
];

final config = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger,
);

expect(config.styles, styles);
expect(config.curveConfigs, curveConfigs);
expect(config.trigger, trigger);
expect(config.onEnd, isNull);

trigger.dispose();
});

test('stores optional onEnd callback', () {
var called = false;
final trigger = ValueNotifier(false);

final config = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: [MockStyle(0.0)],
curveConfigs: [
const CurveAnimationConfig(
duration: Duration(milliseconds: 100),
curve: Curves.linear,
),
],
trigger: trigger,
onEnd: () => called = true,
);

expect(config.onEnd, isNotNull);
config.onEnd!();
expect(called, true);

trigger.dispose();
});

test('props contains styles, trigger, and curveConfigs for equality', () {
final trigger = ValueNotifier(false);
final styles = [MockStyle(0.0)];
final curveConfigs = [
const CurveAnimationConfig(
duration: Duration(milliseconds: 100),
curve: Curves.linear,
),
];

final config = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger,
);

expect(config.props, contains(styles));
expect(config.props, contains(trigger));
expect(config.props, contains(curveConfigs));

trigger.dispose();
});

test('equal configs have same props', () {
final trigger = ValueNotifier(false);
final styles = [MockStyle(0.0)];
final curveConfigs = [
const CurveAnimationConfig(
duration: Duration(milliseconds: 100),
curve: Curves.linear,
),
];

final config1 = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger,
);

final config2 = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger,
);

expect(config1.props, equals(config2.props));

trigger.dispose();
});

test('different triggers produce different configs', () {
final trigger1 = ValueNotifier(false);
final trigger2 = ValueNotifier(false);
final styles = [MockStyle(0.0)];
final curveConfigs = [
const CurveAnimationConfig(
duration: Duration(milliseconds: 100),
curve: Curves.linear,
),
];

final config1 = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger1,
);

final config2 = PhaseAnimationConfig<MockSpec<double>, MockStyle<double>>(
styles: styles,
curveConfigs: curveConfigs,
trigger: trigger2,
);

expect(config1, isNot(equals(config2)));

trigger1.dispose();
trigger2.dispose();
});
});
}
Loading
Loading