Skip to content

fix: Animated.loop and Animated.sequence crash if resetBeforeIteration is false, original author asyler (from PR 44031 on RN repo) #2783

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import Animated from '..';
import Easing from '../../Easing';
import AnimatedImplementation from '../../../vendor/react-native/Animated/AnimatedImplementation';

const AnimatedInterpolation = Animated.Interpolation;

Expand Down Expand Up @@ -329,4 +330,74 @@ describe('Animated', () => {
expect(interpolation(2 / 3)).toBe('rgba(0, 0, 0, 0.667)');
});
});

describe('sequence and loop', () => {
it('supports restarting sequence after it was stopped during execution', () => {
const anim1 = { start: jest.fn(), stop: jest.fn() };
const anim2 = { start: jest.fn(), stop: jest.fn() };
const cb = jest.fn();

const seq = AnimatedImplementation.sequence([anim1, anim2]);

seq.start(cb);

anim1.start.mock.calls[0][0]({ finished: true });
seq.stop();

// anim1 should be finished so anim2 should also start
expect(anim1.start).toHaveBeenCalledTimes(1);
expect(anim2.start).toHaveBeenCalledTimes(1);

seq.start(cb);

// after restart the sequence should resume from the anim2
expect(anim1.start).toHaveBeenCalledTimes(1);
expect(anim2.start).toHaveBeenCalledTimes(2);
});

it('supports restarting sequence after it was finished without a reset', () => {
const anim1 = { start: jest.fn(), stop: jest.fn() };
const anim2 = { start: jest.fn(), stop: jest.fn() };
const cb = jest.fn();

const seq = AnimatedImplementation.sequence([anim1, anim2]);

seq.start(cb);
anim1.start.mock.calls[0][0]({ finished: true });
anim2.start.mock.calls[0][0]({ finished: true });

// sequence should be finished
expect(cb).toBeCalledWith({ finished: true });

seq.start(cb);

// sequence should successfully restart from the anim1
expect(anim1.start).toHaveBeenCalledTimes(2);
expect(anim2.start).toHaveBeenCalledTimes(1);
});

it('restarts sequence normally in a loop if resetBeforeIteration is false', () => {
const anim1 = { start: jest.fn(), stop: jest.fn() };
const anim2 = { start: jest.fn(), stop: jest.fn() };
const seq = AnimatedImplementation.sequence([anim1, anim2]);

const loop = AnimatedImplementation.loop(seq, {
resetBeforeIteration: false
});

loop.start();

expect(anim1.start).toHaveBeenCalledTimes(1);

anim1.start.mock.calls[0][0]({ finished: true });

expect(anim2.start).toHaveBeenCalledTimes(1);

anim2.start.mock.calls[0][0]({ finished: true });

// after anim2 is finished, the sequence is finished,
// hence the loop iteration is finished, so the next iteration starts
expect(anim1.start).toHaveBeenCalledTimes(2);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ const sequence = function (
current++;

if (current === animations.length) {
// if the start is called, even without a reset, it should start from the beginning
current = 0;
callback && callback(result);
return;
}
Expand Down