diff --git a/src/useDragIndexCarousel/_useDragIndexCarousel.test.tsx b/src/useDragIndexCarousel/_useDragIndexCarousel.test.tsx
new file mode 100644
index 0000000..33a0305
--- /dev/null
+++ b/src/useDragIndexCarousel/_useDragIndexCarousel.test.tsx
@@ -0,0 +1,96 @@
+import { renderHook, act } from '@testing-library/react';
+import { _useDragIndexCarousel } from './useDragIndexCarousel';
+
+describe('_useDragIndexCarousel 기능 테스트', () => {
+ it('초기 상태 테스트 index로 시작할 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3));
+
+ expect(result.current.index).toBe(0);
+ });
+
+ it('index를 next, prev로 조작할 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(2));
+
+ expect(result.current.index).toBe(0);
+ act(() => result.current.next());
+ expect(result.current.index).toBe(1);
+ act(() => result.current.prev());
+ expect(result.current.index).toBe(0);
+ expect(result.current.isStart).toBe(true);
+ act(() => result.current.next());
+ act(() => result.current.next());
+ expect(result.current.isEnd).toBe(true);
+ });
+
+ it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 많이, 오른쪽으로 슬라이드하면 index를 증가시킬 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 60));
+ const touchEvent = { touches: [{ clientX: 0 }] };
+ const touchMove = { touches: [{ clientX: -100 }] };
+
+ act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
+ act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(1);
+ });
+
+ it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 많이, 왼쪽으로 슬라이드하면 index를 감소시킬 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 60, 1));
+ const touchEvent = { touches: [{ clientX: 0 }] };
+ const touchMove = { touches: [{ clientX: 100 }] };
+
+ act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
+ act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(0);
+ });
+
+ it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 적게, 슬라이드하면 index를 유지시킬 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 100));
+ const touchEvent = { touches: [{ clientX: 0 }] };
+ const touchMove = { touches: [{ clientX: -90 }] };
+
+ act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
+ act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(0);
+ });
+
+ it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 많이, 오른쪽으로 슬라이드하면 index를 증가시킬 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 60));
+ const touchEvent = { pageX: 0 };
+ const touchMove = { pageX: -100 };
+
+ act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
+ act(() => result.current.handleScrollMove(touchMove as MouseEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(1);
+ });
+
+ it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 많이, 왼쪽으로 슬라이드하면 index를 감소시킬수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 60, 1));
+ const touchEvent = { pageX: 0 };
+ const touchMove = { pageX: 100 };
+
+ act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
+ act(() => result.current.handleScrollMove(touchMove as MouseEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(0);
+ });
+
+ it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 적게 슬라이드하면 index를 유지시킬 수 있다.', () => {
+ const { result } = renderHook(() => _useDragIndexCarousel(3, 100, 1));
+ const touchEvent = { pageX: 0 };
+ const touchMove = { pageX: 60 };
+
+ act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
+ act(() => result.current.handleScrollMove(touchMove as MouseEvent));
+ act(() => result.current.handleMoveEnd());
+
+ expect(result.current.index).toBe(1);
+ });
+});
diff --git a/src/useDragIndexCarousel/useDragIndexCarousel.test.tsx b/src/useDragIndexCarousel/useDragIndexCarousel.test.tsx
index fbd32b3..cbde555 100644
--- a/src/useDragIndexCarousel/useDragIndexCarousel.test.tsx
+++ b/src/useDragIndexCarousel/useDragIndexCarousel.test.tsx
@@ -1,96 +1,236 @@
-import { renderHook, act } from '@testing-library/react';
-import { _useDragIndexCarousel } from './useDragIndexCarousel';
-
-describe('useDragIndexCarousel', () => {
- it('초기 상태 테스트 index로 시작할 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3));
-
- expect(result.current.index).toBe(0);
+import { fireEvent, render } from '@testing-library/react';
+import useDragIndexCarousel from './useDragIndexCarousel';
+import React from 'react';
+
+const DATA = [1, 2, 3, 4];
+const WRAPPER_WIDTH = 500;
+const START_INDEX = 2;
+
+function TestComponent() {
+ const { CarouselWrapper, ref } = useDragIndexCarousel(DATA.length);
+
+ return (
+
+ {DATA.map((index) => (
+
+ ))}
+
+ );
+}
+
+function IndexConfigureTestComponent() {
+ const { CarouselWrapper, ref } = useDragIndexCarousel(DATA.length, { startIndex: START_INDEX });
+
+ return (
+
+ {DATA.map((index) => (
+
+ ))}
+
+ );
+}
+
+function InfinityTestComponent() {
+ const { CarouselWrapper, ref } = useDragIndexCarousel(DATA.length, {
+ infinity: true,
});
- it('index를 next, prev로 조작할 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(2));
-
- expect(result.current.index).toBe(0);
- act(() => result.current.next());
- expect(result.current.index).toBe(1);
- act(() => result.current.prev());
- expect(result.current.index).toBe(0);
- expect(result.current.isStart).toBe(true);
- act(() => result.current.next());
- act(() => result.current.next());
- expect(result.current.isEnd).toBe(true);
+ return (
+
+ {DATA.map((index) => (
+
+ ))}
+
+ );
+}
+
+beforeAll(() => {
+ Object.defineProperty(HTMLElement.prototype, 'clientWidth', {
+ configurable: true,
+ value: WRAPPER_WIDTH,
});
- it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 많이, 오른쪽으로 슬라이드하면 index를 증가시킬 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 60));
- const touchEvent = { touches: [{ clientX: 0 }] };
- const touchMove = { touches: [{ clientX: -100 }] };
-
- act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
- act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(1);
+ Object.defineProperties(MouseEvent.prototype, {
+ pageX: {
+ get() {
+ return this.clientX;
+ },
+ },
+ pageY: {
+ get() {
+ return this.clientY;
+ },
+ },
});
+});
- it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 많이, 왼쪽으로 슬라이드하면 index를 감소시킬 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 60, 1));
- const touchEvent = { touches: [{ clientX: 0 }] };
- const touchMove = { touches: [{ clientX: 100 }] };
-
- act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
- act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(0);
+describe('useDragIndexCarousel 컴포넌트 기능 테스트', () => {
+ it('스크롤을 통해 Carousel을 넘길 수 있다.', () => {
+ const { container } = render();
+ const wrapper = container.querySelector('.wrapper')!;
+ const carousel = wrapper.querySelector('div')!;
+
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: -100 });
+ fireEvent.mouseUp(carousel);
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH}px)`);
+
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: -100 });
+ fireEvent.mouseUp(carousel);
+ expect(carousel.style.transform).toBe(`translateX(${-2 * WRAPPER_WIDTH}px)`);
});
- it('모바일 터치이벤트 테스트: 절대값으로 minMove보다 적게, 슬라이드하면 index를 유지시킬 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 100));
- const touchEvent = { touches: [{ clientX: 0 }] };
- const touchMove = { touches: [{ clientX: -90 }] };
-
- act(() => result.current.handleTouchStart(touchEvent as unknown as TouchEvent));
- act(() => result.current.handleTouchMove(touchMove as unknown as TouchEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(0);
+ it('스크롤을 해도 첫 인덱스나 마지막 인덱스이면 Carousel이 넘어가지 않는다.', () => {
+ const { container } = render();
+ const wrapper = container.querySelector('.wrapper')!;
+ const carousel = wrapper.querySelector('div')!;
+ const scrollRight = () => {
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: -100 });
+ fireEvent.mouseUp(carousel);
+ };
+
+ const scrollLeft = () => {
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: 100 });
+ fireEvent.mouseUp(carousel);
+ };
+
+ Array.from({ length: 10 }).forEach(() => scrollRight());
+ expect(carousel.style.transform).toBe(`translateX(${-3 * WRAPPER_WIDTH}px)`);
+ Array.from({ length: 10 }).forEach(() => scrollLeft());
+ expect(carousel.style.transform).toBe(`translateX(${0}px)`);
});
+});
- it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 많이, 오른쪽으로 슬라이드하면 index를 증가시킬 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 60));
- const touchEvent = { pageX: 0 };
- const touchMove = { pageX: -100 };
-
- act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
- act(() => result.current.handleScrollMove(touchMove as MouseEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(1);
+describe('useDragIndexCarousel Infinity 컴포넌트 테스트', () => {
+ it('Infinity option이 true인 경우, translateX는 WRAPPER_WIDTH (index=1)로 시작한다.', () => {
+ const { container } = render();
+ const wrapper = container.querySelector('.wrapper')!;
+ const carousel = wrapper.querySelector('div')!;
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH}px)`);
});
- it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 많이, 왼쪽으로 슬라이드하면 index를 감소시킬수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 60, 1));
- const touchEvent = { pageX: 0 };
- const touchMove = { pageX: 100 };
-
- act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
- act(() => result.current.handleScrollMove(touchMove as MouseEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(0);
+ it('Infinity option이 true인 경우, 인덱스 양끝단을 오갈 수 있다.', () => {
+ const { container } = render();
+ const wrapper = container.querySelector('.wrapper')!;
+ const carousel = wrapper.querySelector('div')!;
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH}px)`);
+
+ const scrollRight = () => {
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: -100 });
+ fireEvent.mouseUp(carousel);
+ };
+
+ const scrollLeft = () => {
+ fireEvent.mouseDown(carousel, { clientX: 0 });
+ fireEvent.mouseMove(carousel, { clientX: 100 });
+ fireEvent.mouseUp(carousel);
+ };
+
+ scrollLeft();
+ expect(carousel.style.transform).toBe(`translateX(${0}px)`);
+ fireEvent.transitionEnd(carousel);
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH * DATA.length}px)`);
+
+ Array.from({ length: 2 }).forEach(() => scrollRight());
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH * (DATA.length + 1)}px)`);
+ fireEvent.transitionEnd(carousel);
+ expect(carousel.style.transform).toBe(`translateX(${-WRAPPER_WIDTH}px)`);
});
+});
- it('PC 스크롤이벤트 테스트: 절대값으로 minMove보다 적게 슬라이드하면 index를 유지시킬 수 있다.', () => {
- const { result } = renderHook(() => _useDragIndexCarousel(3, 100, 1));
- const touchEvent = { pageX: 0 };
- const touchMove = { pageX: 60 };
-
- act(() => result.current.handleScrollStart(touchEvent as MouseEvent));
- act(() => result.current.handleScrollMove(touchMove as MouseEvent));
- act(() => result.current.handleMoveEnd());
-
- expect(result.current.index).toBe(1);
+describe('startIndex 지정 테스트', () => {
+ it('startIndex를 지정할 수 있다.', () => {
+ const { container } = render();
+ const wrapper = container.querySelector('.wrapper')!;
+ const carousel = wrapper.querySelector('div')!;
+ expect(carousel.style.transform).toBe(`translateX(${-START_INDEX * WRAPPER_WIDTH}px)`);
});
});
diff --git a/src/useDragIndexCarousel/useDragIndexCarousel.tsx b/src/useDragIndexCarousel/useDragIndexCarousel.tsx
index 17cf97c..49f4314 100644
--- a/src/useDragIndexCarousel/useDragIndexCarousel.tsx
+++ b/src/useDragIndexCarousel/useDragIndexCarousel.tsx
@@ -34,10 +34,9 @@ export function _useDragIndexCarousel(pageLimit: number, minMove = 60, startInde
};
const getSliderWidth = () => {
- if (ref.current) {
- return ref.current.clientWidth;
- }
- return window.innerWidth;
+ // getSliderWidth는 상단의 useEffect에서 호출하는데, 여기서 ref.current를 확인하므로
+ // ref.current가 반드시 존재한다.
+ return ref!.current!.clientWidth;
};
const handleMoveEnd = () => {