-
Notifications
You must be signed in to change notification settings - Fork 74
Add tests for SKLottieView AnimationFailed exception handling #330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
93576af
b215637
c4507de
7e51518
0a59b7e
5a0e527
15f9adf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -147,6 +147,75 @@ public async Task NegativeUpdatesAfterPositiveGoesBack() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(0, animationCompleted); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task AnimationFailedContainsException() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // create - use non-existent file to trigger actual load failure with exception | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var source = new SKFileLottieImageSource { File = "nonexistent.json" }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var lottie = new SKLottieView { Source = source }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SKLottieAnimationFailedEventArgs? failedEventArgs = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var tcs = new TaskCompletionSource<bool>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lottie.AnimationFailed += (s, e) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| failedEventArgs = e; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tcs.SetResult(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // wait for animation to fail (using consistent 3000ms timeout) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var completedTask = await Task.WhenAny(tcs.Task, Task.Delay(3000)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // test - verify the failure event was triggered with proper event args | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(tcs.Task, completedTask); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.NotNull(failedEventArgs); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.IsType<SKLottieAnimationFailedEventArgs>(failedEventArgs); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Verify exception is populated when file doesn't exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.NotNull(failedEventArgs.Exception); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task AnimationFailedNotTriggeredForEmptySource() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // create - empty source should NOT trigger AnimationFailed (early return) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var source = new SKFileLottieImageSource(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var lottie = new SKLottieView { Source = source }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var failedTriggered = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var loadedTriggered = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lottie.AnimationFailed += (s, e) => failedTriggered = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lottie.AnimationLoaded += (s, e) => loadedTriggered = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // wait to ensure events have time to fire (using consistent 3000ms) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Task.Delay(3000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // test - verify neither event was triggered for empty source | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+186
to
+193
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lottie.AnimationFailed += (s, e) => failedTriggered = true; | |
| lottie.AnimationLoaded += (s, e) => loadedTriggered = true; | |
| // wait to ensure events have time to fire (using consistent 3000ms) | |
| await Task.Delay(3000); | |
| // test - verify neither event was triggered for empty source | |
| var failedTcs = new TaskCompletionSource<bool>(); | |
| var loadedTcs = new TaskCompletionSource<bool>(); | |
| lottie.AnimationFailed += (s, e) => | |
| { | |
| failedTriggered = true; | |
| failedTcs.TrySetResult(true); | |
| }; | |
| lottie.AnimationLoaded += (s, e) => | |
| { | |
| loadedTriggered = true; | |
| loadedTcs.TrySetResult(true); | |
| }; | |
| // wait briefly to ensure events would have time to fire if they were going to | |
| var timeoutTask = Task.Delay(200); | |
| var completedTask = await Task.WhenAny(failedTcs.Task, loadedTcs.Task, timeoutTask); | |
| // test - verify neither event was triggered for empty source | |
| Assert.Equal(timeoutTask, completedTask); |
Copilot
AI
Feb 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AnimationLoaded/AnimationFailed handlers are attached after setting Source via the object initializer. Because Source immediately starts the async load, the failure event can fire before the subscription is added, making the test flaky on fast failures. Attach handlers first, then set lottie.Source = source (or use WaitingLottieView).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AnimationFailed handler is attached after setting
Sourcevia the object initializer. BecauseSourcetriggers an async load immediately,AnimationFailedcan fire before the subscription is added, making this test flaky. Create the view first, attach handlers, then assignlottie.Source = source(or useWaitingLottieViewwhich subscribes beforeSourceis set).