Skip to content

Commit

Permalink
test: improve coverage for pointer and keyboard events
Browse files Browse the repository at this point in the history
  • Loading branch information
nerdyman committed Oct 28, 2023
1 parent 3c78437 commit b7d8307
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const ItemLabels: StoryFn<ReactCompareSliderDetailedProps> = (props) => {
border: '2px solid white',
borderRadius: '.5rem',
backdropFilter: 'blur(0.25rem) saturate(180%) contrast(80%) brightness(120%)',
WebkitBackdropFilter: 'blur(0.25rem) saturate(180%) contrast(80%) brightness(120%)',
transition: 'opacity 0.25s ease-in-out',
};

Expand Down Expand Up @@ -83,6 +84,7 @@ export const HandleLabels: StoryFn<ReactCompareSliderDetailedProps> = (props) =>
borderRadius: '.25rem',
border: '1px solid white',
backdropFilter: 'blur(0.25rem) saturate(180%) contrast(80%) brightness(120%)',
WebkitBackdropFilter: 'blur(0.25rem) saturate(180%) contrast(80%) brightness(120%)',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
transition: 'opacity 0.25s ease-in-out',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ KeyboardInteractionsLandscape.play = async ({ canvasElement }) => {
expect(document.activeElement!.getAttribute('data-rcs')).not.toBe('handle-container');

// Focus the handle with mouse click.
fireEvent.click(canvas.getByRole('slider'), { clientX: 100, clientY: 100 });
await fireEvent.click(canvas.getByRole('slider'), { clientX: 100, clientY: 100 });
expect(document.activeElement!.getAttribute('data-rcs')).toBe('handle-container');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');

Expand Down Expand Up @@ -84,7 +84,7 @@ KeyboardInteractionsPortrait.play = async ({ canvasElement }) => {
expect(document.activeElement!.getAttribute('data-rcs')).not.toBe('handle-container');

// Focus the handle with mouse click.
fireEvent.click(canvas.getByRole('slider'), { clientX: 100, clientY: 100 });
await fireEvent.click(canvas.getByRole('slider'), { clientX: 100, clientY: 100 });
expect((document.activeElement as HTMLElement).getAttribute('data-rcs')).toBe('handle-container');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');

Expand All @@ -104,3 +104,39 @@ KeyboardInteractionsPortrait.play = async ({ canvasElement }) => {
await user.keyboard('{ArrowDown}');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
};

export const KeyboardInteractionsPixel = Template.bind({});
KeyboardInteractionsPixel.args = getArgs({
keyboardIncrement: 20,
style: { width: 200, height: 200 },
});

KeyboardInteractionsPixel.play = async ({ canvasElement }) => {
const user = userEvent.setup();
const canvas = within(canvasElement);
const sliderRoot = (await canvas.findByRole('slider')) as Element;

// Should have elements on mount.
await waitFor(() => expect(sliderRoot).toBeInTheDocument());

// Focus the handle with mouse click.
await fireEvent.click(canvas.getByRole('slider'), { clientX: 100, clientY: 100 });
expect((document.activeElement as HTMLElement).getAttribute('data-rcs')).toBe('handle-container');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');

// Move handle right.
await user.keyboard('{ArrowRight}');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('60');

// Move handle Left.
await user.keyboard('{ArrowLeft}');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');

// Move handle Right.
await user.keyboard('{ArrowUp}');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('60');

// Move handle Left.
await user.keyboard('{ArrowDown}');
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from '@storybook/jest';
import type { Meta, StoryFn } from '@storybook/react';
import { fireEvent, waitFor, within } from '@storybook/testing-library';
import { fireEvent, userEvent, waitFor, within } from '@storybook/testing-library';
import type { ReactCompareSliderDetailedProps } from 'react-compare-slider';
import { ReactCompareSlider } from 'react-compare-slider';

Expand All @@ -13,46 +13,50 @@ export default meta;

export const PointerMovementWithinBounds = Template.bind({ style: { width: 200, height: 200 } });
PointerMovementWithinBounds.args = getArgs({ style: { width: 200, height: 200 } });

PointerMovementWithinBounds.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sliderRoot = canvas.queryByTestId(
const sliderRoot = (await canvas.findByTestId(
PointerMovementWithinBounds.args?.['data-testid'],
) as Element;
)) as Element;

// Should have elements on mount.
await expect(sliderRoot).toBeInTheDocument();

await new Promise((resolve) => setTimeout(resolve, 500));
await waitFor(() => expect(sliderRoot).toBeInTheDocument());

fireEvent.pointerDown(sliderRoot, {
await fireEvent.pointerDown(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.75,
clientY: sliderRoot.clientHeight * 0.75,
});

await waitFor(() => expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('75'));
await waitFor(() =>
expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(75),
);
await new Promise((resolve) => setTimeout(resolve, 500));

fireEvent.pointerDown(sliderRoot, {
await expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('75');
await expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(75);

await new Promise((resolve) => setTimeout(resolve, 500));

await fireEvent.pointerDown(sliderRoot, {
clientX: sliderRoot.clientWidth,
clientY: sliderRoot.clientHeight,
});

await waitFor(() => expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100'));
await waitFor(() =>
expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(100),
);
await new Promise((resolve) => setTimeout(resolve, 500));

await expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100');
await expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(100);

fireEvent.pointerDown(sliderRoot, {
await new Promise((resolve) => setTimeout(resolve, 500));

await fireEvent.pointerDown(sliderRoot, {
clientX: 10,
clientY: 10,
});

await waitFor(() => expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('5'));
await waitFor(() =>
expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(5),
);
await new Promise((resolve) => setTimeout(resolve, 500));

await expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('5');
await expect(PointerMovementWithinBounds.args?.onPositionChange).toHaveBeenCalledWith(5);
};

export const PointerMovementOutsideBounds: StoryFn<ReactCompareSliderDetailedProps> = (props) => {
Expand All @@ -62,60 +66,53 @@ export const PointerMovementOutsideBounds: StoryFn<ReactCompareSliderDetailedPro
</div>
);
};

PointerMovementOutsideBounds.args = getArgs({ style: { width: 200, height: 200 } });

PointerMovementOutsideBounds.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sliderRoot = canvas.queryByTestId(
const sliderRoot = (await canvas.findByTestId(
PointerMovementOutsideBounds.args?.['data-testid'],
) as Element;
)) as Element;

await new Promise((resolve) => setTimeout(resolve, 500));
await waitFor(() => expect(sliderRoot).toBeInTheDocument());

fireEvent.pointerDown(sliderRoot, {
await fireEvent.pointerDown(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.75,
clientY: sliderRoot.clientHeight * 0.75,
});

await new Promise((resolve) => setTimeout(resolve, 100));

await waitFor(() => {
// expect(document.activeElement).toBe(canvas.getByRole('slider'));
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('75');
expect(PointerMovementOutsideBounds.args?.onPositionChange).toHaveBeenCalledWith(75);
});

console.log('!!!', sliderRoot);

await new Promise((resolve) => setTimeout(resolve, 100));

// Mouse the pointer outside of the slider.
fireEvent.pointerMove(sliderRoot, {
await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 1.5,
clientY: sliderRoot.clientHeight * 1.5,
});

await new Promise((resolve) => setTimeout(resolve, 100));

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100');
expect(PointerMovementOutsideBounds.args?.onPositionChange).toHaveBeenCalledWith(100);
});

// Move it back now y'all.
fireEvent.pointerMove(sliderRoot, {
await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.5,
clientY: sliderRoot.clientHeight * 1.5,
});

fireEvent.pointerUp(sliderRoot);
await fireEvent.pointerUp(sliderRoot);

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
expect(PointerMovementOutsideBounds.args?.onPositionChange).toHaveBeenCalledWith(50);
});
await expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
await expect(PointerMovementOutsideBounds.args?.onPositionChange).toHaveBeenCalledWith(50);
};

/**
* Ensure slider position stops when pointer is not down and moved outside of the root.
*/
export const ChangePositionOnHover: StoryFn<ReactCompareSliderDetailedProps> = (props) => {
return (
<div style={{ width: 400, height: 400, backgroundColor: 'red' }}>
Expand All @@ -124,46 +121,95 @@ export const ChangePositionOnHover: StoryFn<ReactCompareSliderDetailedProps> = (
);
};
ChangePositionOnHover.args = getArgs({
position: 0,
changePositionOnHover: true,
style: { width: 200, height: 200 },
});
ChangePositionOnHover.play = async ({ canvasElement }) => {
const user = userEvent.setup();
const canvas = within(canvasElement);
const slider = (await canvas.findByRole('slider')) as Element;
const sliderRoot = (await canvas.findByTestId(
ChangePositionOnHover.args?.['data-testid'],
)) as Element;

await waitFor(() => expect(sliderRoot).toBeInTheDocument());

await user.click(slider);

await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.5,
clientY: sliderRoot.clientHeight * 0.5,
});

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
expect(ChangePositionOnHover.args?.onPositionChange).toHaveBeenCalledWith(50);
});

// Mouse the pointer outside of the slider.
await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 1.5,
clientY: sliderRoot.clientHeight * 1.5,
});

await fireEvent.pointerLeave(sliderRoot);

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100');
expect(ChangePositionOnHover.args?.onPositionChange).toHaveBeenCalledWith(100);
});
};

/**
* Test using `changePositionOnHover` while pointer has been pressed while dragging outside of the
* container.
* Ensure slider position continues to update when pointer is down and moved outside of the root.
*/
ChangePositionOnHover.play = async ({ canvasElement }) => {
export const ChangePositionOnHoverPointerDown: StoryFn<ReactCompareSliderDetailedProps> = (
props,
) => {
return (
<div style={{ width: 400, height: 400, backgroundColor: 'red' }}>
<ReactCompareSlider {...props} />
</div>
);
};
ChangePositionOnHoverPointerDown.args = getArgs({
changePositionOnHover: true,
style: { width: 200, height: 200 },
});
ChangePositionOnHoverPointerDown.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sliderRoot = canvas.queryByTestId(ChangePositionOnHover.args?.['data-testid']) as Element;
const sliderRoot = (await canvas.findByTestId(
ChangePositionOnHoverPointerDown.args?.['data-testid'],
)) as Element;

await new Promise((resolve) => setTimeout(resolve, 500));
await waitFor(() => expect(sliderRoot).toBeInTheDocument());

fireEvent.pointerMove(sliderRoot, {
await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.5,
clientY: sliderRoot.clientHeight * 0.5,
});

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('50');
expect(ChangePositionOnHover.args?.onPositionChange).toHaveBeenCalledWith(50);
expect(ChangePositionOnHoverPointerDown.args?.onPositionChange).toHaveBeenCalledWith(50);
});

fireEvent.pointerDown(sliderRoot, {
await fireEvent.pointerDown(sliderRoot, {
clientX: sliderRoot.clientWidth * 0.5,
clientY: sliderRoot.clientHeight * 0.5,
});

// Mouse the pointer outside of the slider.
fireEvent.pointerMove(sliderRoot, {
await fireEvent.pointerMove(sliderRoot, {
clientX: sliderRoot.clientWidth * 1.5,
clientY: sliderRoot.clientHeight * 1.5,
});

fireEvent.pointerLeave(sliderRoot);
await fireEvent.pointerLeave(sliderRoot);

await waitFor(() => {
expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100');
expect(ChangePositionOnHover.args?.onPositionChange).toHaveBeenCalledWith(100);
expect(ChangePositionOnHoverPointerDown.args?.onPositionChange).toHaveBeenCalledWith(100);
});
};
29 changes: 22 additions & 7 deletions docs/storybook/content/stories/99-tests/position.test.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@ StartAt0.args = getArgs({ position: 0 });

StartAt0.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sliderRoot = canvas.queryByTestId(StartAt100.args?.['data-testid']) as Element;
const slider = canvas.getByRole('slider') as Element;

await waitFor(() => expect(sliderRoot).toBeInTheDocument());
await waitFor(() => expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('0'));
await waitFor(() => expect(slider.getAttribute('aria-valuenow')).toBe('0'));
await waitFor(() => expect(window.getComputedStyle(slider).left).toBe('0px'));
};

export const StartAt100 = Template.bind({});
StartAt100.args = getArgs({ position: 100 });
StartAt100.args = getArgs({ position: 100, style: { width: 256 } });

StartAt100.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sliderRoot = canvas.queryByTestId(StartAt100.args?.['data-testid']) as Element;
const slider = canvas.getByRole('slider') as Element;

await waitFor(() => expect(sliderRoot).toBeInTheDocument());
await waitFor(() => expect(canvas.getByRole('slider').getAttribute('aria-valuenow')).toBe('100'));
await waitFor(() => expect(slider.getAttribute('aria-valuenow')).toBe('100'));
await waitFor(() => expect(window.getComputedStyle(slider).left).toBe('256px'));
};

export const PointSamePosition = Template.bind({});
PointSamePosition.args = getArgs({ position: 50, style: { width: 256 } });

PointSamePosition.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const slider = canvas.getByRole('slider') as Element;

await waitFor(() => expect(slider.getAttribute('aria-valuenow')).toBe('50'));
await waitFor(() => expect(window.getComputedStyle(slider).left).toBe('128px'));

await fireEvent.pointerDown(slider, { clientX: 128, clientY: 128 });
await waitFor(() => expect(slider.getAttribute('aria-valuenow')).toBe('50'));
await waitFor(() => expect(window.getComputedStyle(slider).left).toBe('128px'));
};

/**
Expand Down

0 comments on commit b7d8307

Please sign in to comment.