Skip to content

Commit 7dd2d25

Browse files
chiciometa-codesync[bot]
authored andcommitted
Pressability test migrated to Jest moder timers (#55410)
Summary: This PR migrates the `Pressability` tests so that it uses Jest modern timers. First, I centralized Fake timers setup in the `beforeEach` and restored in the `afterEach` (to run test in isolation with respect to timers). I migrated all the calls previously used to fire all pending timers (`jest.runOnlyPendingTimers`) to `jest.advanceTimersByTime`, setting the correct timing need for the tests to verify the entire `Pressability` flows (including minimum press duration and long press delay configurations). This should improve the correctness of the tests (demonstrated also by the test plan below). I also tried to increased the readability of the tests by extracting some constants (related to the inner configured delay/press duration of the `Pressability` class). ## Changelog: [GENERAL] [CHANGED] - Migrated `Pressability` tests to Jest modern timers Pull Request resolved: #55410 Test Plan: - Ran `Pressability-test` and verify all tests cases passed - Ran the full React Native test suite to ensure all tests pass. - Verified test correctness by intentionally breaking production code: - Modified callback invocation logic (onPressIn, onPressOut, onLongPress) to verify that tests were failing - Changed timing constants (eg. `DEFAULT_MIN_PRESS_DURATION,` DEFAULT_LONG_PRESS_DELAY_MS`)to verify that tests correctly failed Reviewed By: NickGerleman Differential Revision: D92750937 Pulled By: Abbondanzo fbshipit-source-id: 6d01f45f289138c504ccbb53104b219dbaed0bae
1 parent faebee4 commit 7dd2d25

1 file changed

Lines changed: 47 additions & 44 deletions

File tree

packages/react-native/Libraries/Pressability/__tests__/Pressability-test.js

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
* @format
99
*/
1010

11-
// TODO(legacy-fake-timers): Fix these tests to work with modern timers.
12-
jest.useFakeTimers({legacyFakeTimers: true});
13-
1411
import type {GestureResponderEvent} from '../../Types/CoreEventTypes';
1512
import type {PressabilityConfig} from '../Pressability';
1613

@@ -232,11 +229,14 @@ const createMockPressEvent = (
232229
};
233230
};
234231

232+
const CONFIGURED_DEFAULT_MIN_PRESS_DURATION = 130;
233+
const ONE_MILLISECOND_BEFORE_CONFIGURED_LONG_PRESS_DURATION = 500 - 1;
234+
235235
describe('Pressability', () => {
236236
beforeEach(() => {
237+
jest.useFakeTimers();
237238
jest.resetModules();
238239
jest.restoreAllMocks();
239-
jest.spyOn(Date, 'now');
240240
jest.spyOn(HoverState, 'isHoverEnabled');
241241
});
242242

@@ -427,7 +427,9 @@ describe('Pressability', () => {
427427
);
428428
// $FlowExpectedError[not-a-function]
429429
handlers.onMouseLeave(createMockMouseEvent('onMouseLeave'));
430-
jest.advanceTimersByTime(499);
430+
jest.advanceTimersByTime(
431+
ONE_MILLISECOND_BEFORE_CONFIGURED_LONG_PRESS_DURATION,
432+
);
431433
expect(config.onHoverOut).not.toBeCalled();
432434
jest.advanceTimersByTime(1);
433435
expect(config.onHoverOut).toBeCalled();
@@ -461,7 +463,9 @@ describe('Pressability', () => {
461463
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
462464
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
463465

464-
jest.advanceTimersByTime(499);
466+
jest.advanceTimersByTime(
467+
ONE_MILLISECOND_BEFORE_CONFIGURED_LONG_PRESS_DURATION,
468+
);
465469
expect(config.onLongPress).not.toBeCalled();
466470
jest.advanceTimersByTime(1);
467471
expect(config.onLongPress).toBeCalled();
@@ -476,7 +480,9 @@ describe('Pressability', () => {
476480
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
477481
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
478482

479-
jest.advanceTimersByTime(499);
483+
jest.advanceTimersByTime(
484+
ONE_MILLISECOND_BEFORE_CONFIGURED_LONG_PRESS_DURATION,
485+
);
480486
expect(config.onLongPress).not.toBeCalled();
481487
jest.advanceTimersByTime(1);
482488
expect(config.onLongPress).toBeCalled();
@@ -489,7 +495,9 @@ describe('Pressability', () => {
489495
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
490496
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
491497

492-
jest.advanceTimersByTime(499);
498+
jest.advanceTimersByTime(
499+
ONE_MILLISECOND_BEFORE_CONFIGURED_LONG_PRESS_DURATION,
500+
);
493501
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
494502
jest.advanceTimersByTime(1);
495503

@@ -525,7 +533,7 @@ describe('Pressability', () => {
525533
}),
526534
);
527535

528-
jest.advanceTimersByTime(130);
536+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
529537
handlers.onResponderMove(
530538
// NOTE: Delta from (0, 0) is ~9.9 < 10.
531539
createMockPressEvent({
@@ -616,25 +624,21 @@ describe('Pressability', () => {
616624

617625
describe('onPress', () => {
618626
it('is called even when `measure` does not finish', () => {
619-
// Disable onLongPress. Since we run all timers, we otherwise end up
620-
// interpreting these events as a long press.
621-
const {config, handlers} = createMockPressability({
622-
onLongPress: undefined,
623-
});
627+
const {config, handlers} = createMockPressability();
624628

625629
handlers.onStartShouldSetResponder();
626630
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
627631

628632
expect(UIManager.measure).toBeCalled();
629633

630634
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
631-
jest.runOnlyPendingTimers();
635+
jest.advanceTimersByTime(0);
632636
expect(config.onPressIn).toBeCalled();
633637

634638
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
635639

636640
expect(config.onPress).toBeCalled();
637-
jest.runOnlyPendingTimers();
641+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
638642
expect(config.onPressOut).toBeCalled();
639643
});
640644
});
@@ -646,7 +650,7 @@ describe('Pressability', () => {
646650
handlers.onStartShouldSetResponder();
647651
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
648652

649-
jest.runOnlyPendingTimers();
653+
jest.advanceTimersByTime(0);
650654
expect(config.onPressIn).toBeCalled();
651655
});
652656

@@ -703,24 +707,24 @@ describe('Pressability', () => {
703707
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
704708

705709
expect(config.onPressOut).not.toBeCalled();
706-
jest.runOnlyPendingTimers();
710+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
707711
expect(config.onPressOut).toBeCalled();
708712
});
709713

710-
it('is called after `onResponderRelease` after `delayPressIn`', () => {
714+
it('is called after `onResponderRelease` after a configured `delayPressIn`', () => {
711715
const {config, handlers} = createMockPressability({
712-
delayPressIn: Number.EPSILON,
716+
delayPressIn: 500,
713717
});
714718

715719
handlers.onStartShouldSetResponder();
716720
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
717721
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
718-
jest.runOnlyPendingTimers();
722+
jest.advanceTimersByTime(500);
719723
expect(config.onPressIn).toBeCalled();
720724
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
721725

722726
expect(config.onPressOut).not.toBeCalled();
723-
jest.runOnlyPendingTimers();
727+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
724728
expect(config.onPressOut).toBeCalled();
725729
});
726730

@@ -737,24 +741,26 @@ describe('Pressability', () => {
737741
);
738742

739743
expect(config.onPressOut).not.toBeCalled();
740-
jest.runOnlyPendingTimers();
744+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
741745
expect(config.onPressOut).not.toBeCalled();
742746
});
743747

744748
it('is not called after `onResponderTerminate` after `delayPressIn`', () => {
745-
const {config, handlers} = createMockPressability();
749+
const {config, handlers} = createMockPressability({
750+
delayPressIn: 100,
751+
});
746752

747753
handlers.onStartShouldSetResponder();
748754
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
749755
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
750-
jest.runOnlyPendingTimers();
756+
jest.advanceTimersByTime(100);
751757
expect(config.onPressIn).toBeCalled();
752758
handlers.onResponderTerminate(
753759
createMockPressEvent('onResponderTerminate'),
754760
);
755761

756762
expect(config.onPressOut).not.toBeCalled();
757-
jest.runOnlyPendingTimers();
763+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
758764
expect(config.onPressOut).toBeCalled();
759765
});
760766

@@ -767,7 +773,7 @@ describe('Pressability', () => {
767773
handlers.onStartShouldSetResponder();
768774
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
769775
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
770-
jest.runOnlyPendingTimers();
776+
jest.advanceTimersByTime(1);
771777
expect(config.onPressIn).toBeCalled();
772778
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
773779

@@ -784,22 +790,14 @@ describe('Pressability', () => {
784790
handlers.onStartShouldSetResponder();
785791
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
786792
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
787-
jest.runOnlyPendingTimers();
793+
jest.advanceTimersByTime(0);
788794
expect(config.onPressIn).toBeCalled();
789-
790-
// WORKAROUND: Jest does not advance `Date.now()`.
791-
expect(Date.now).toHaveBeenCalledTimes(1);
792-
const touchActivateTime = Date.now.mock.results[0].value;
793795
jest.advanceTimersByTime(120);
794-
Date.now.mockReturnValue(touchActivateTime + 120);
795-
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
796796

797+
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
797798
expect(config.onPressOut).not.toBeCalled();
798799
jest.advanceTimersByTime(10);
799-
Date.now.mockReturnValue(touchActivateTime + 130);
800800
expect(config.onPressOut).toBeCalled();
801-
802-
Date.now.mockRestore();
803801
});
804802

805803
it('is called synchronously if minimum press duration is 0ms', () => {
@@ -810,7 +808,7 @@ describe('Pressability', () => {
810808
handlers.onStartShouldSetResponder();
811809
handlers.onResponderGrant(createMockPressEvent('onResponderGrant'));
812810
handlers.onResponderMove(createMockPressEvent('onResponderMove'));
813-
jest.runOnlyPendingTimers();
811+
jest.advanceTimersByTime(0);
814812
expect(config.onPressIn).toBeCalled();
815813
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
816814

@@ -851,7 +849,7 @@ describe('Pressability', () => {
851849

852850
expect(config.onPressIn).toBeCalled();
853851
expect(config.onPress).toBeCalled();
854-
jest.runOnlyPendingTimers();
852+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
855853
expect(config.onPressOut).toBeCalled();
856854
});
857855

@@ -891,7 +889,7 @@ describe('Pressability', () => {
891889
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
892890

893891
expect(config.onPress).toBeCalled();
894-
jest.runOnlyPendingTimers();
892+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
895893
expect(config.onPressOut).toBeCalled();
896894
});
897895
});
@@ -915,12 +913,12 @@ describe('Pressability', () => {
915913
pageY: mockRegion.height * 2,
916914
}),
917915
);
918-
jest.runOnlyPendingTimers();
916+
jest.advanceTimersByTime(0);
919917
expect(config.onPressIn).toBeCalled();
920918

921919
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
922920
expect(config.onPress).not.toBeCalled();
923-
jest.runOnlyPendingTimers();
921+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
924922
expect(config.onPressOut).toBeCalled();
925923
});
926924

@@ -942,12 +940,13 @@ describe('Pressability', () => {
942940
pageY: mockRegion.height * 2,
943941
}),
944942
);
945-
jest.runOnlyPendingTimers();
943+
jest.advanceTimersByTime(500);
946944
expect(config.onPressIn).not.toBeCalled();
947945

948946
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
949947

950948
expect(config.onPress).not.toBeCalled();
949+
jest.advanceTimersByTime(CONFIGURED_DEFAULT_MIN_PRESS_DURATION);
951950
expect(config.onPressOut).not.toBeCalled();
952951
});
953952

@@ -978,9 +977,13 @@ describe('Pressability', () => {
978977
handlers.onResponderRelease(createMockPressEvent('onResponderRelease'));
979978

980979
expect(config.onPress).toBeCalled();
981-
jest.runOnlyPendingTimers();
980+
jest.advanceTimersByTime(630); // 1000 - 500 (onPressIn activation, already advanced before) + DEFAULT_MIN_PRESS_DURATION
982981
expect(config.onPressOut).toBeCalled();
983982
});
984983
});
985984
});
985+
986+
afterEach(() => {
987+
jest.useRealTimers();
988+
});
986989
});

0 commit comments

Comments
 (0)