diff --git a/src/fire-event.ts b/src/fire-event.ts index 849c01eea..ff1a4e6e7 100644 --- a/src/fire-event.ts +++ b/src/fire-event.ts @@ -154,6 +154,6 @@ function setNativeStateIfNeeded(element: ReactTestInstance, eventName: string, v isHostTextInput(element) && isTextInputEditable(element) ) { - nativeState?.elementValues.set(element, value); + nativeState?.valueForElement.set(element, value); } } diff --git a/src/helpers/text-input.ts b/src/helpers/text-input.ts index eaa10f7b9..3c4ba83ed 100644 --- a/src/helpers/text-input.ts +++ b/src/helpers/text-input.ts @@ -17,7 +17,7 @@ export function getTextInputValue(element: ReactTestInstance) { return ( element.props.value ?? - nativeState?.elementValues.get(element) ?? + nativeState?.valueForElement.get(element) ?? element.props.defaultValue ?? '' ); diff --git a/src/native-state.ts b/src/native-state.ts index 48793fd31..378c1fbf3 100644 --- a/src/native-state.ts +++ b/src/native-state.ts @@ -1,4 +1,5 @@ import { ReactTestInstance } from 'react-test-renderer'; +import { Point } from './types'; /** * Simulated native state for unmanaged controls. @@ -6,14 +7,16 @@ import { ReactTestInstance } from 'react-test-renderer'; * Values from `value` props (managed controls) should take precedence over these values. */ export type NativeState = { - elementValues: WeakMap; + valueForElement: WeakMap; + contentOffsetForElement: WeakMap; }; export let nativeState: NativeState | null = null; export function initNativeState(): void { nativeState = { - elementValues: new WeakMap(), + valueForElement: new WeakMap(), + contentOffsetForElement: new WeakMap(), }; } diff --git a/src/types.ts b/src/types.ts index 77df0fb34..293e7e818 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,19 @@ +/** + * Location of an element. + */ +export interface Point { + y: number; + x: number; +} + +/** + * Size of an element. + */ +export interface Size { + height: number; + width: number; +} + // TS autocomplete trick // Ref: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-567871939 export type StringWithAutocomplete = T | (string & {}); diff --git a/src/user-event/event-builder/scroll-view.ts b/src/user-event/event-builder/scroll-view.ts index c477b6c29..bf5e3decb 100644 --- a/src/user-event/event-builder/scroll-view.ts +++ b/src/user-event/event-builder/scroll-view.ts @@ -1,25 +1,12 @@ +import { Point, Size } from '../../types'; import { baseSyntheticEvent } from './base'; -/** - * Scroll position of a scrollable element. - */ -export interface ContentOffset { - y: number; - x: number; -} - /** * Other options for constructing a scroll event. */ export type ScrollEventOptions = { - contentSize?: { - height: number; - width: number; - }; - layoutMeasurement?: { - height: number; - width: number; - }; + contentSize?: Size; + layoutMeasurement?: Size; }; /** @@ -28,7 +15,7 @@ export type ScrollEventOptions = { * - Android: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 31.619047164916992}, "contentSize": {"height": 1624.761962890625, "width": 411.4285583496094}, "layoutMeasurement": {"height": 785.5238037109375, "width": 411.4285583496094}, "responderIgnoreScroll": true, "target": 139, "velocity": {"x": -1.3633992671966553, "y": -1.3633992671966553}}` */ export const ScrollViewEventBuilder = { - scroll: (offset: ContentOffset = { y: 0, x: 0 }, options?: ScrollEventOptions) => { + scroll: (offset: Point = { y: 0, x: 0 }, options?: ScrollEventOptions) => { return { ...baseSyntheticEvent(), nativeEvent: { diff --git a/src/user-event/event-builder/text-input.ts b/src/user-event/event-builder/text-input.ts index 61ea3c064..2ec4af977 100644 --- a/src/user-event/event-builder/text-input.ts +++ b/src/user-event/event-builder/text-input.ts @@ -1,4 +1,4 @@ -import { ContentSize } from '../utils/content-size'; +import { Size } from '../../types'; import { TextRange } from '../utils/text-range'; import { baseSyntheticEvent } from './base'; @@ -68,7 +68,7 @@ export const TextInputEventBuilder = { * - iOS: `{"contentSize": {"height": 21.666666666666668, "width": 11.666666666666666}, "target": 75}` * - Android: `{"contentSize": {"height": 61.45454406738281, "width": 352.7272644042969}, "target": 53}` */ - contentSizeChange: ({ width, height }: ContentSize) => { + contentSizeChange: ({ width, height }: Size) => { return { ...baseSyntheticEvent(), nativeEvent: { contentSize: { width, height }, target: 0 }, diff --git a/src/user-event/paste.ts b/src/user-event/paste.ts index ccdaff713..d94d9e734 100644 --- a/src/user-event/paste.ts +++ b/src/user-event/paste.ts @@ -33,7 +33,7 @@ export async function paste( dispatchEvent(element, 'selectionChange', EventBuilder.TextInput.selectionChange(rangeToClear)); // 3. Paste the text - nativeState?.elementValues.set(element, text); + nativeState?.valueForElement.set(element, text); dispatchEvent(element, 'change', EventBuilder.TextInput.change(text)); dispatchEvent(element, 'changeText', text); diff --git a/src/user-event/scroll/scroll-to.ts b/src/user-event/scroll/scroll-to.ts index c280e628e..a75ac387d 100644 --- a/src/user-event/scroll/scroll-to.ts +++ b/src/user-event/scroll/scroll-to.ts @@ -5,20 +5,14 @@ import { EventBuilder } from '../event-builder'; import { ErrorWithStack } from '../../helpers/errors'; import { isHostScrollView } from '../../helpers/host-component-names'; import { pick } from '../../helpers/object'; -import { ContentOffset } from '../event-builder/scroll-view'; +import { nativeState } from '../../native-state'; +import { Point, Size } from '../../types'; import { dispatchEvent, wait } from '../utils'; import { createScrollSteps, inertialInterpolator, linearInterpolator } from './utils'; -import { getElementScrollOffset, setElementScrollOffset } from './state'; interface CommonScrollToOptions { - contentSize?: { - height: number; - width: number; - }; - layoutMeasurement?: { - height: number; - width: number; - }; + contentSize?: Size; + layoutMeasurement?: Size; } export interface VerticalScrollToOptions extends CommonScrollToOptions { @@ -62,7 +56,7 @@ export async function scrollTo( options.contentSize?.height ?? 0, ); - const initialPosition = getElementScrollOffset(element); + const initialPosition = nativeState?.contentOffsetForElement.get(element) ?? { x: 0, y: 0 }; const dragSteps = createScrollSteps( { y: options.y, x: options.x }, initialPosition, @@ -79,13 +73,13 @@ export async function scrollTo( await emitMomentumScrollEvents(this.config, element, momentumSteps, options); const finalPosition = momentumSteps.at(-1) ?? dragSteps.at(-1) ?? initialPosition; - setElementScrollOffset(element, finalPosition); + nativeState?.contentOffsetForElement.set(element, finalPosition); } async function emitDragScrollEvents( config: UserEventConfig, element: ReactTestInstance, - scrollSteps: ContentOffset[], + scrollSteps: Point[], scrollOptions: ScrollToOptions, ) { if (scrollSteps.length === 0) { @@ -115,7 +109,7 @@ async function emitDragScrollEvents( async function emitMomentumScrollEvents( config: UserEventConfig, element: ReactTestInstance, - scrollSteps: ContentOffset[], + scrollSteps: Point[], scrollOptions: ScrollToOptions, ) { if (scrollSteps.length === 0) { diff --git a/src/user-event/scroll/state.ts b/src/user-event/scroll/state.ts deleted file mode 100644 index 49fa109d0..000000000 --- a/src/user-event/scroll/state.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ReactTestInstance } from 'react-test-renderer'; -import { ContentOffset } from '../event-builder/scroll-view'; - -const scrollOffsetForElement = new WeakMap(); - -export function getElementScrollOffset(element: ReactTestInstance): ContentOffset { - return scrollOffsetForElement.get(element) ?? { x: 0, y: 0 }; -} - -export function setElementScrollOffset(element: ReactTestInstance, scrollState: ContentOffset) { - scrollOffsetForElement.set(element, scrollState); -} diff --git a/src/user-event/scroll/utils.ts b/src/user-event/scroll/utils.ts index a683ad9da..7fe46590d 100644 --- a/src/user-event/scroll/utils.ts +++ b/src/user-event/scroll/utils.ts @@ -1,14 +1,14 @@ -import { ContentOffset } from '../event-builder/scroll-view'; +import { Point } from '../../types'; const DEFAULT_STEPS_COUNT = 5; type InterpolatorFn = (end: number, start: number, steps: number) => number[]; export function createScrollSteps( - target: Partial, - initialOffset: ContentOffset, + target: Partial, + initialOffset: Point, interpolator: InterpolatorFn, -): ContentOffset[] { +): Point[] { if (target.y != null) { return interpolator(target.y, initialOffset.y, DEFAULT_STEPS_COUNT).map((y) => ({ y, diff --git a/src/user-event/type/type.ts b/src/user-event/type/type.ts index 7d3a8e6d6..517b12bb9 100644 --- a/src/user-event/type/type.ts +++ b/src/user-event/type/type.ts @@ -95,7 +95,7 @@ export async function emitTypingEvents( return; } - nativeState?.elementValues.set(element, text); + nativeState?.valueForElement.set(element, text); dispatchEvent(element, 'change', EventBuilder.TextInput.change(text)); dispatchEvent(element, 'changeText', text); diff --git a/src/user-event/utils/content-size.ts b/src/user-event/utils/content-size.ts index 51f100080..bc3291597 100644 --- a/src/user-event/utils/content-size.ts +++ b/src/user-event/utils/content-size.ts @@ -1,7 +1,4 @@ -export interface ContentSize { - width: number; - height: number; -} +import { Size } from '../../types'; /** * Simple function for getting mock the size of given text. @@ -13,8 +10,7 @@ export interface ContentSize { * @param text text to be measure * @returns width and height of the text */ - -export function getTextContentSize(text: string): ContentSize { +export function getTextContentSize(text: string): Size { const lines = text.split('\n'); const maxLineLength = Math.max(...lines.map((line) => line.length));