Skip to content

Commit

Permalink
Add callback tests and guess fixes for null pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
Marek Rozmus committed Jan 30, 2020
1 parent 3ddeb66 commit 5496b2f
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 55 deletions.
35 changes: 30 additions & 5 deletions examples/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import { MailIcon, ReplyIcon, DeleteIcon } from '../images/icons';
import styles from './app.module.css';

function App() {
const [triggeredSimpleItemAction, triggerSimpleItemAction] = useState('');
const [triggeredSimpleItemAction, triggerSimpleItemAction] = useState('None');
const [triggeredComplexItemAction, triggerComplexItemAction] = useState('');
const [swipeProgress, handleSwipeProgress] = useState('0');
const [swipeAction, handleSwipeAction] = useState('None');

const swipeRightDataSimple = name => ({
content: (
Expand Down Expand Up @@ -64,30 +66,53 @@ function App() {
triggerComplexItemAction(`Reply action triggered on "${name}" item`)
});

const handleSwipeStart = () => {
triggerSimpleItemAction('None');
handleSwipeAction('Swipe started');
};

const handleSwipeEnd = () => {
handleSwipeAction('Swipe ended');
};

return (
<div className={styles.example}>
<h3>react-swipeable-list example</h3>
<h5>(try also mobile view in dev tools for touch events)</h5>
<h3>Simple example (with default 0.5 action trigger threshold)</h3>
<span className={styles.actionInfo}>{triggeredSimpleItemAction}</span>
<span className={styles.actionInfo}>
Triggered action: {triggeredSimpleItemAction}
</span>
<span className={styles.actionInfo}>
Callback swipe action: {swipeAction}
</span>
<span className={styles.actionInfo}>
Callback swipe progress: {swipeProgress}
</span>
<div className={styles.listContainer}>
<SwipeableList>
<SwipeableListItem
swipeRight={swipeRightDataSimple('Item with swipe right')}
onSwipeStart={handleSwipeStart}
onSwipeEnd={handleSwipeEnd}
onSwipeProgress={handleSwipeProgress}
>
{itemContentSimple('Item with swipe right')}
</SwipeableListItem>
<SwipeableListItem
swipeLeft={swipeLeftDataSimple('Item with swipe left')}
onSwipeStart={handleSwipeStart}
onSwipeEnd={handleSwipeEnd}
onSwipeProgress={handleSwipeProgress}
>
{itemContentSimple('Item with swipe left')}
</SwipeableListItem>
<SwipeableListItem
swipeRight={swipeRightDataSimple('Item with both swipes')}
swipeLeft={swipeLeftDataSimple('Item with both swipes')}
onSwipeStart={() => console.log('Swipe started')}
onSwipeEnd={() => console.log('Swipe ended')}
onSwipeProgress={progress => console.log(progress)}
onSwipeStart={handleSwipeStart}
onSwipeEnd={handleSwipeEnd}
onSwipeProgress={handleSwipeProgress}
>
{itemContentSimple('Item with both swipes')}
</SwipeableListItem>
Expand Down
6 changes: 3 additions & 3 deletions examples/src/app.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ html {
}

h3 {
margin-bottom: 0;
margin-bottom: 8px;
text-align: center;
}

Expand Down Expand Up @@ -95,8 +95,8 @@ footer a:hover {
}

.actionInfo {
padding: 16px;
font-weight: 600;
padding: 0 8px 4px 8px;
font-weight: 400;
font-size: 14px;
}

Expand Down
84 changes: 39 additions & 45 deletions src/SwipeableListItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class SwipeableListItem extends PureComponent {
this.contentLeft = null;
this.contentRight = null;
this.listElement = null;
this.requestedAnimationFrame = null;
this.wrapper = null;

this.startTime = null;
Expand Down Expand Up @@ -61,6 +62,8 @@ class SwipeableListItem extends PureComponent {
}

componentWillUnmount() {
cancelAnimationFrame(this.requestedAnimationFrame);

this.wrapper.removeEventListener('mousedown', this.handleDragStartMouse);

this.wrapper.removeEventListener('touchstart', this.handleDragStartTouch);
Expand Down Expand Up @@ -102,7 +105,7 @@ class SwipeableListItem extends PureComponent {
}

this.startTime = Date.now();
requestAnimationFrame(this.updatePosition);
this.requestedAnimationFrame = requestAnimationFrame(this.updatePosition);
};

handleMouseMove = event => {
Expand All @@ -115,11 +118,11 @@ class SwipeableListItem extends PureComponent {
event.stopPropagation();
event.preventDefault();

const delta = clientX - this.dragStartPoint.x;
this.left = clientX - this.dragStartPoint.x;

if (this.shouldMoveItem(delta)) {
this.left = delta;
}
this.requestedAnimationFrame = requestAnimationFrame(
this.updatePosition
);
}
}
};
Expand All @@ -138,11 +141,11 @@ class SwipeableListItem extends PureComponent {
event.stopPropagation();
event.preventDefault();

const delta = clientX - this.dragStartPoint.x;
this.left = clientX - this.dragStartPoint.x;

if (this.shouldMoveItem(delta)) {
this.left = delta;
}
this.requestedAnimationFrame = requestAnimationFrame(
this.updatePosition
);
}
}
};
Expand All @@ -151,8 +154,10 @@ class SwipeableListItem extends PureComponent {
window.removeEventListener('mouseup', this.handleDragEndMouse);
window.removeEventListener('mousemove', this.handleMouseMove);

this.wrapper.removeEventListener('mouseup', this.handleDragEndMouse);
this.wrapper.removeEventListener('mousemove', this.handleMouseMove);
if (this.wrapper) {
this.wrapper.removeEventListener('mouseup', this.handleDragEndMouse);
this.wrapper.removeEventListener('mousemove', this.handleMouseMove);
}

this.handleDragEnd();
};
Expand All @@ -179,8 +184,11 @@ class SwipeableListItem extends PureComponent {
}

this.resetState();
this.listElement.className = styles.contentReturn;
this.listElement.style.transform = `translateX(${this.left}px)`;

if (this.listElement) {
this.listElement.className = styles.contentReturn;
this.listElement.style.transform = `translateX(${this.left}px)`;
}

// hide backgrounds
if (this.contentLeft) {
Expand All @@ -194,21 +202,6 @@ class SwipeableListItem extends PureComponent {
}
};

shouldMoveItem = delta => {
const {
swipeLeft: { content: contentLeft } = {},
swipeRight: { content: contentRight } = {},
blockSwipe
} = this.props;
const swipingLeft = delta < 0;
const swipingRight = delta > 0;

return (
!blockSwipe &&
((swipingLeft && contentLeft) || (swipingRight && contentRight))
);
};

dragStartedWithinItem = () => {
const { x, y } = this.dragStartPoint;

Expand All @@ -233,7 +226,10 @@ class SwipeableListItem extends PureComponent {

switch (octant) {
case 0:
if (horizontalDistance > this.dragHorizontalDirectionThreshold) {
if (
this.contentRight &&
horizontalDistance > this.dragHorizontalDirectionThreshold
) {
this.dragDirection = DragDirection.RIGHT;
}
break;
Expand All @@ -245,7 +241,10 @@ class SwipeableListItem extends PureComponent {
}
break;
case 4:
if (horizontalDistance > this.dragHorizontalDirectionThreshold) {
if (
this.contentLeft &&
horizontalDistance > this.dragHorizontalDirectionThreshold
) {
this.dragDirection = DragDirection.LEFT;
}
break;
Expand All @@ -258,28 +257,23 @@ class SwipeableListItem extends PureComponent {
break;
}

if (
this.props.onSwipeStart &&
(this.dragDirection === DragDirection.LEFT ||
this.dragDirection === DragDirection.RIGHT)
) {
if (this.props.onSwipeStart && this.isSwiping()) {
this.props.onSwipeStart();
}
}
};

isSwiping = () =>
this.dragStartedWithinItem() &&
(this.dragDirection === DragDirection.LEFT ||
this.dragDirection === DragDirection.RIGHT);

updatePosition = () => {
isSwiping = () => {
const { blockSwipe } = this.props;
return (
!blockSwipe &&
this.dragStartedWithinItem() &&
(this.dragDirection === DragDirection.LEFT ||
this.dragDirection === DragDirection.RIGHT)
);
};

if (this.dragStartedWithinItem() && !blockSwipe) {
requestAnimationFrame(this.updatePosition);
}

updatePosition = () => {
const now = Date.now();
const elapsed = now - this.startTime;

Expand Down
89 changes: 87 additions & 2 deletions src/__tests__/SwipeableListItem.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ test('right swipe action triggering if no left swipe defined', () => {

const contentContainer = getByTestId('content');

swipeLeftMouse(contentContainer);
swipeLeftTouch(contentContainer);
// swipeLeftMouse(contentContainer);
// swipeLeftTouch(contentContainer);
swipeRightMouse(contentContainer);
swipeRightTouch(contentContainer);

Expand Down Expand Up @@ -242,3 +242,88 @@ test('swipe actions triggering if block swipe prop is set', () => {
expect(callbackLeft).toHaveBeenCalledTimes(0);
expect(callbackRight).toHaveBeenCalledTimes(0);
});

test('start and end callbacks not triggered if swipe content not defined', () => {
const callbackSwipeStart = jest.fn();
const callbackSwipeEnd = jest.fn();

const { getByTestId } = render(
<SwipeableListItem
onSwipeStart={callbackSwipeStart}
onSwipeEnd={callbackSwipeEnd}
>
<span>Item content</span>
</SwipeableListItem>
);

const contentContainer = getByTestId('content');
swipeLeftMouse(contentContainer);
swipeLeftTouch(contentContainer);
swipeRightMouse(contentContainer);
swipeRightTouch(contentContainer);

expect(callbackSwipeStart).toHaveBeenCalledTimes(0);
expect(callbackSwipeEnd).toHaveBeenCalledTimes(0);
});

test('start and end callbacks not triggered if blockSwipe is set', () => {
const callbackSwipeStart = jest.fn();
const callbackSwipeEnd = jest.fn();
const callbackLeft = jest.fn();

const { getByTestId } = render(
<SwipeableListItem
blockSwipe
swipeLeft={{
content: <span>Left swipe content</span>,
action: callbackLeft
}}
onSwipeStart={callbackSwipeStart}
onSwipeEnd={callbackSwipeEnd}
>
<span>Item content</span>
</SwipeableListItem>
);

const contentContainer = getByTestId('content');
swipeLeftMouse(contentContainer);
swipeLeftTouch(contentContainer);
swipeRightMouse(contentContainer);
swipeRightTouch(contentContainer);

expect(callbackSwipeStart).toHaveBeenCalledTimes(0);
expect(callbackSwipeEnd).toHaveBeenCalledTimes(0);
});

test('start and end callbacks triggered if swipe content is defined', () => {
const callbackSwipeStart = jest.fn();
const callbackSwipeEnd = jest.fn();
const callbackLeft = jest.fn();
const callbackRight = jest.fn();

const { getByTestId } = render(
<SwipeableListItem
swipeLeft={{
content: <span>Left swipe content</span>,
action: callbackLeft
}}
swipeRight={{
content: <span>Right swipe content</span>,
action: callbackRight
}}
onSwipeStart={callbackSwipeStart}
onSwipeEnd={callbackSwipeEnd}
>
<span>Item content</span>
</SwipeableListItem>
);

const contentContainer = getByTestId('content');
swipeLeftMouse(contentContainer);
swipeLeftTouch(contentContainer);
swipeRightMouse(contentContainer);
swipeRightTouch(contentContainer);

expect(callbackSwipeStart).toHaveBeenCalledTimes(4);
expect(callbackSwipeEnd).toHaveBeenCalledTimes(4);
});

0 comments on commit 5496b2f

Please sign in to comment.