Skip to content

Commit

Permalink
test: 💍 prepared test utils
Browse files Browse the repository at this point in the history
  • Loading branch information
prc5 committed Jun 22, 2024
1 parent 8f9f9ba commit 81d864d
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 50 deletions.
7 changes: 4 additions & 3 deletions __tests__/features/pan-touch/pan-touch.base.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ describe("Pan Touch [Base]", () => {
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
});
it("should return to position with padding enabled", async () => {
const { content, touchPan, pinch } = renderApp({
disablePadding: false,
const { content, touchPan } = renderApp({
alignmentAnimation: {
disabled: false,
},
});
pinch({ value: 1.2 });
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
touchPan({ x: 100, y: 100 });
expect(content.style.transform).toBe("translate(100px, 100px) scale(1)");
Expand Down
39 changes: 39 additions & 0 deletions __tests__/features/pan-touch/pan-touch.velocity.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { waitFor } from "@testing-library/react";

import { renderApp, sleep } from "../../utils";

describe("Pan Touch [Velocity]", () => {
describe("When panning to coords", () => {
it("should trigger velocity", async () => {
const { content, touchPan, pinch } = renderApp();
pinch({ value: 1.5 });
expect(content.style.transform).toBe("translate(0px, 0px) scale(1.5)");
await sleep(10);
touchPan({ x: 20, y: 20 });
expect(content.style.transform).toBe("translate(20px, 20px) scale(1.5)");
});
// it("should not trigger disabled velocity", async () => {
// const { content, touchPan, pinch } = renderApp({
// disablePadding: false,
// });
// pinch({ value: 1.2 });
// expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
// touchPan({ x: 100, y: 100 });
// expect(content.style.transform).toBe("translate(100px, 100px) scale(1)");
// await waitFor(() => {
// expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
// });
// });
// it("should accelerate to certain point", async () => {
// const { content, touchPan, zoom } = renderApp();
// expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
// zoom({ value: 1.5 });
// expect(content.style.transform).toBe("translate(0px, 0px) scale(1.5)");
// touchPan({ x: 100, y: 100 });
// await sleep(10);
// expect(content.style.transform).toBe(
// "translate(100px, 100px) scale(1.5)",
// );
// });
});
});
37 changes: 37 additions & 0 deletions __tests__/features/pinch/pinch.callbacks.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { renderApp } from "../../utils";

describe("Pinch [Callbacks]", () => {
describe("When pinch zooming", () => {
it("should trigger onPinch callbacks", async () => {
const spy1 = jest.fn();
const spy2 = jest.fn();
const spy3 = jest.fn();
const { content, pinch } = renderApp({
onPinchStart: spy1,
onPinch: spy2,
onPinchStop: spy3,
});
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
pinch({ value: 2 });
expect(spy1).toBeCalledTimes(1);
expect(spy2).toBeCalled();
expect(spy3).toBeCalledTimes(1);
});

it("should not trigger onZoom callbacks", async () => {
const spy1 = jest.fn();
const spy2 = jest.fn();
const spy3 = jest.fn();
const { content, pinch } = renderApp({
onZoomStart: spy1,
onZoom: spy2,
onZoomStop: spy3,
});
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
pinch({ value: 2 });
expect(spy1).toBeCalledTimes(0);
expect(spy2).toBeCalledTimes(0);
expect(spy3).toBeCalledTimes(0);
});
});
});
40 changes: 40 additions & 0 deletions __tests__/features/zoom/zoom.callbacks.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { waitFor } from "@testing-library/dom";
import { renderApp } from "../../utils";

describe("Zoom [Callbacks]", () => {
describe("When wheel zooming", () => {
it("should trigger onZoom callbacks", async () => {
const spy1 = jest.fn();
const spy2 = jest.fn();
const spy3 = jest.fn();
const { content, zoom } = renderApp({
onZoomStart: spy1,
onZoom: spy2,
onZoomStop: spy3,
});
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
zoom({ value: 2 });
await waitFor(() => {
expect(spy1).toBeCalledTimes(1);
expect(spy2).toBeCalled();
expect(spy3).toBeCalledTimes(1);
});
});

it("should not trigger onPinch callbacks", async () => {
const spy1 = jest.fn();
const spy2 = jest.fn();
const spy3 = jest.fn();
const { content, zoom } = renderApp({
onPinchStart: spy1,
onPinch: spy2,
onPinchStop: spy3,
});
expect(content.style.transform).toBe("translate(0px, 0px) scale(1)");
zoom({ value: 2 });
expect(spy1).toBeCalledTimes(0);
expect(spy2).toBeCalledTimes(0);
expect(spy3).toBeCalledTimes(0);
});
});
});
51 changes: 36 additions & 15 deletions __tests__/utils/render-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ interface RenderApp {
pinch: (options: { value: number; center?: [number, number] }) => void;
}

const waitForPreviousActionToEnd = () => {
// Synchronous await for 10ms to wait for the previous event to finish (pinching or touching)
const startTime = Date.now();
while (Date.now() - startTime < 10) {}
};

function getPinchTouches(
content: HTMLElement,
center: [number, number],
Expand Down Expand Up @@ -95,7 +101,7 @@ export const renderApp = ({
{...{ contentHeight, contentWidth, wrapperHeight, wrapperWidth }}
/>,
);
// // controls buttons
// controls buttons
const zoomInBtn = screen.getByTestId("zoom-in");
const zoomOutBtn = screen.getByTestId("zoom-out");
const resetBtn = screen.getByTestId("reset");
Expand Down Expand Up @@ -147,6 +153,8 @@ export const renderApp = ({
const { value, center = [0, 0] } = options;
if (!ref.current) throw new Error("ref.current is null");

waitForPreviousActionToEnd();

const isZoomIn = ref.current.instance.state.scale < value;
const from = isZoomIn ? 1 : 2;
const step = 0.1;
Expand All @@ -169,9 +177,9 @@ export const renderApp = ({
const scaleDifference = Math.abs(
ref.current.instance.state.scale - value,
);
const isNearScale = scaleDifference < 0.5;
const isNearScale = scaleDifference < 0.05;

const newStep = isNearScale ? step / 2 : step;
const newStep = isNearScale ? step / 6 : step;

pinchValue = pinchValue + newStep;
touches = getPinchTouches(content, center, pinchValue, from);
Expand All @@ -184,7 +192,9 @@ export const renderApp = ({
}
}

fireEvent.touchEnd(content);
fireEvent.touchEnd(content, {
touches,
});
};

const pan: RenderApp["pan"] = ({ x, y }) => {
Expand All @@ -196,17 +206,18 @@ export const renderApp = ({
};

const touchPan: RenderApp["touchPan"] = ({ x, y }) => {
const touches = [
{
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
target: content,
},
];
waitForPreviousActionToEnd();

fireEvent.touchStart(content, {
touches,
touches: [
{
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
target: content,
},
],
});
fireEvent.touchMove(content, {
touches: [
Expand All @@ -219,7 +230,17 @@ export const renderApp = ({
},
],
});
fireEvent.touchEnd(content);
fireEvent.touchEnd(content, {
touches: [
{
pageX: x,
pageY: y,
clientX: x,
clientY: y,
target: content,
},
],
});
};

return {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
"@storybook/react": "7.6.9",
"@storybook/react-vite": "^7.6.9",
"@storybook/test": "^7.6.9",
"@testing-library/dom": "^8.20.0",
"@testing-library/react": "^13.4.0",
"@testing-library/dom": "^10.1.0",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^26.0.22",
"@types/node": "^15.6.1",
Expand Down
17 changes: 9 additions & 8 deletions src/core/instance.core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ export class ZoomPanPinch {

onPinchStart = (event: TouchEvent): void => {
const { disabled } = this.setup;
const { onPinchingStart, onZoomStart } = this.props;
const { onPinchStart, onZoomStart } = this.props;

if (disabled) return;

Expand All @@ -336,13 +336,13 @@ export class ZoomPanPinch {

handlePinchStart(this, event);
handleCancelAnimation(this);
handleCallback(getContext(this), event, onPinchingStart);
handleCallback(getContext(this), event, onPinchStart);
handleCallback(getContext(this), event, onZoomStart);
};

onPinch = (event: TouchEvent): void => {
const { disabled } = this.setup;
const { onPinching, onZoom } = this.props;
const { onPinch, onZoom } = this.props;

if (disabled) return;

Expand All @@ -353,16 +353,16 @@ export class ZoomPanPinch {
event.stopPropagation();

handlePinchZoom(this, event);
handleCallback(getContext(this), event, onPinching);
handleCallback(getContext(this), event, onPinch);
handleCallback(getContext(this), event, onZoom);
};

onPinchStop = (event: TouchEvent): void => {
const { onPinchingStop, onZoomStop } = this.props;
const { onPinchStop, onZoomStop } = this.props;

if (this.pinchStartScale) {
handlePinchStop(this);
handleCallback(getContext(this), event, onPinchingStop);
handleCallback(getContext(this), event, onPinchStop);
handleCallback(getContext(this), event, onZoomStop);
}
};
Expand All @@ -372,14 +372,15 @@ export class ZoomPanPinch {
/// ///////

onTouchPanningStart = (event: TouchEvent): void => {
const { disabled } = this.setup;
const { disabled, doubleClick } = this.setup;
const { onPanningStart } = this.props;

if (disabled) return;

const isDoubleTapAllowed = !doubleClick?.disabled;
const isDoubleTap = this.lastTouch && +new Date() - this.lastTouch < 200;

if (isDoubleTap && event.touches.length === 1) {
if (isDoubleTapAllowed && isDoubleTap && event.touches.length === 1) {
this.onDoubleClick(event);
} else {
this.lastTouch = +new Date();
Expand Down
12 changes: 6 additions & 6 deletions src/models/context.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ export type ReactZoomPanPinchProps = {
ref: ReactZoomPanPinchRef,
event: TouchEvent | MouseEvent,
) => void;
onPinchingStart?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onPinching?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onPinchingStop?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onPinchStart?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onPinch?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onPinchStop?: (ref: ReactZoomPanPinchRef, event: TouchEvent) => void;
onZoomStart?: (
ref: ReactZoomPanPinchRef,
event: TouchEvent | MouseEvent,
Expand Down Expand Up @@ -192,9 +192,9 @@ export type LibrarySetup = Pick<
| "onPanningStart"
| "onPanning"
| "onPanningStop"
| "onPinchingStart"
| "onPinching"
| "onPinchingStop"
| "onPinchStart"
| "onPinch"
| "onPinchStop"
| "onZoomStart"
| "onZoom"
| "onZoomStop"
Expand Down
6 changes: 3 additions & 3 deletions src/stories/docs/props.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -495,17 +495,17 @@ export const wrapperPropsTable: ComponentProps = {
defaultValue: "undefined",
description: "Callback fired when panning event has finished",
},
onPinchingStart: {
onPinchStart: {
type: ["(ref: ReactZoomPanPinchRef, event) => void"],
defaultValue: "undefined",
description: "Callback fired when pinch event has started",
},
onPinching: {
onPinch: {
type: ["(ref: ReactZoomPanPinchRef, event) => void"],
defaultValue: "undefined",
description: "Callback fired when pinch event is ongoing",
},
onPinchingStop: {
onPinchStop: {
type: ["(ref: ReactZoomPanPinchRef, event) => void"],
defaultValue: "undefined",
description: "Callback fired when pinch event has finished",
Expand Down
Loading

0 comments on commit 81d864d

Please sign in to comment.