|
| 1 | +import React from 'react'; |
| 2 | +import { fireEvent, render } from '@testing-library/react'; |
| 3 | +import VirtualizedList from '../'; |
| 4 | + |
| 5 | +function setScrollMetrics(node, horizontal, offset, length = 500) { |
| 6 | + const position = horizontal ? 'scrollLeft' : 'scrollTop'; |
| 7 | + let current = offset; |
| 8 | + Object.defineProperties(node, { |
| 9 | + [horizontal ? 'scrollWidth' : 'scrollHeight']: { |
| 10 | + configurable: true, |
| 11 | + value: length |
| 12 | + }, |
| 13 | + [horizontal ? 'clientWidth' : 'clientHeight']: { |
| 14 | + configurable: true, |
| 15 | + value: 100 |
| 16 | + }, |
| 17 | + [position]: { |
| 18 | + configurable: true, |
| 19 | + get: () => current, |
| 20 | + set: (value) => { |
| 21 | + current = Math.max(0, Math.min(value, length - 100)); |
| 22 | + } |
| 23 | + } |
| 24 | + }); |
| 25 | + return () => current; |
| 26 | +} |
| 27 | + |
| 28 | +describe.each([false, true])( |
| 29 | + 'VirtualizedList inverted wheel, horizontal=%s', |
| 30 | + (horizontal) => { |
| 31 | + function setup(inverted = true) { |
| 32 | + const { getByTestId } = render( |
| 33 | + <VirtualizedList |
| 34 | + data={[0]} |
| 35 | + getItem={(data, index) => data[index]} |
| 36 | + getItemCount={(data) => data.length} |
| 37 | + getItemLayout={(data, index) => ({ length: 500, offset: 0, index })} |
| 38 | + horizontal={horizontal} |
| 39 | + inverted={inverted} |
| 40 | + keyExtractor={String} |
| 41 | + renderItem={() => ( |
| 42 | + <div data-testid="item"> |
| 43 | + <div data-testid="nested">Nested scrollable</div> |
| 44 | + </div> |
| 45 | + )} |
| 46 | + testID="list" |
| 47 | + /> |
| 48 | + ); |
| 49 | + const list = getByTestId('list'); |
| 50 | + const position = setScrollMetrics(list, horizontal, 200); |
| 51 | + return { list, position, getByTestId }; |
| 52 | + } |
| 53 | + |
| 54 | + function wheel(target, delta) { |
| 55 | + const event = new WheelEvent('wheel', { |
| 56 | + bubbles: true, |
| 57 | + cancelable: true, |
| 58 | + [horizontal ? 'deltaX' : 'deltaY']: delta |
| 59 | + }); |
| 60 | + fireEvent(target, event); |
| 61 | + return event; |
| 62 | + } |
| 63 | + |
| 64 | + test.each([ |
| 65 | + [200, 20, 180], |
| 66 | + [200, -20, 220], |
| 67 | + [390, 20, 370] |
| 68 | + ])( |
| 69 | + 'scrolls its own surface from %s by inverted delta %s', |
| 70 | + (offset, delta, expected) => { |
| 71 | + const { list } = setup(); |
| 72 | + const position = setScrollMetrics(list, horizontal, offset); |
| 73 | + const event = wheel(list, delta); |
| 74 | + expect(position()).toBe(expected); |
| 75 | + expect(event.defaultPrevented).toBe(true); |
| 76 | + } |
| 77 | + ); |
| 78 | + |
| 79 | + test('inverts a wheel over a non-scrollable row', () => { |
| 80 | + const { position, getByTestId } = setup(); |
| 81 | + const item = getByTestId('item'); |
| 82 | + setScrollMetrics(item, horizontal, 0, 100); |
| 83 | + expect(wheel(item, 20).defaultPrevented).toBe(true); |
| 84 | + expect(position()).toBe(180); |
| 85 | + }); |
| 86 | + |
| 87 | + test.each([ |
| 88 | + [50, 20, 70, 200], |
| 89 | + [195, 20, 200, 185], |
| 90 | + [5, -20, 0, 215] |
| 91 | + ])( |
| 92 | + 'consumes a descendant at %s before passing leftover delta %s', |
| 93 | + (offset, delta, expectedChild, expectedList) => { |
| 94 | + const { position, getByTestId } = setup(); |
| 95 | + const nested = getByTestId('nested'); |
| 96 | + const childPosition = setScrollMetrics(nested, horizontal, offset, 300); |
| 97 | + expect(wheel(nested, delta).defaultPrevented).toBe(true); |
| 98 | + expect(childPosition()).toBe(expectedChild); |
| 99 | + expect(position()).toBe(expectedList); |
| 100 | + } |
| 101 | + ); |
| 102 | + |
| 103 | + test('leaves non-inverted wheel scrolling to the browser', () => { |
| 104 | + const { list, position } = setup(false); |
| 105 | + expect(wheel(list, 20).defaultPrevented).toBe(false); |
| 106 | + expect(position()).toBe(200); |
| 107 | + }); |
| 108 | + } |
| 109 | +); |
0 commit comments