diff --git a/src/Counter/jihyun.test.tsx b/src/Counter/jihyun.test.tsx
new file mode 100644
index 0000000..42c71ec
--- /dev/null
+++ b/src/Counter/jihyun.test.tsx
@@ -0,0 +1,192 @@
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import Counter from '.';
+
+const getButton = (name: string) => screen.getByRole('button', { name });
+
+describe('Counter 컴포넌트 기본 기능', () => {
+  it('카운터가 초기값 0으로 렌더링되어야 한다', () => {
+    render(<Counter />);
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent('0');
+  });
+
+  it('증가 버튼 클릭시 기본 step 값(1)만큼 증가해야 한다', async () => {
+    render(<Counter />);
+    await userEvent.click(screen.getByTestId('increment-button'));
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent('1');
+  });
+
+  it('리셋 버튼 클릭시 초기값으로 돌아가야 한다', async () => {
+    render(<Counter />);
+    await userEvent.click(screen.getByTestId('increment-button'));
+    await userEvent.click(screen.getByTestId('reset-button'));
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent('0');
+  });
+
+  it('커스텀 초기값이 정상적으로 적용되어야 한다', async () => {
+    const 커스텀초기값 = 5;
+    render(<Counter initialValue={커스텀초기값} />);
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent(커스텀초기값.toString());
+  });
+
+  it('설정된 step 값만큼 증가/감소해야 한다', async () => {
+    const 커스텀스텝 = 2;
+    render(<Counter step={커스텀스텝} />);
+
+    await userEvent.click(getButton('증가'));
+    expect(screen.getByTestId('count-display')).toHaveTextContent(커스텀스텝.toString());
+    await userEvent.click(getButton('감소'));
+    expect(screen.getByTestId('count-display')).toHaveTextContent('0');
+  });
+
+  it('최대값에 도달하면 증가 버튼이 비활성화되어야 한다', async () => {
+    const 최대값 = 5;
+    render(<Counter initialValue={최대값} maxValue={최대값} />);
+
+    expect(getButton('증가')).toBeDisabled();
+  });
+
+  it('최소값에 도달하면 감소 버튼이 비활성화되어야 한다', async () => {
+    const 최소값 = 5;
+    render(<Counter initialValue={최소값} minValue={최소값} />);
+
+    expect(getButton('감소')).toBeDisabled();
+  });
+
+  it('값이 변경될 때마다 onCountChange 콜백이 호출되어야 한다', async () => {
+    const mockedOnCountChange = jest.fn();
+    render(<Counter onCountChange={mockedOnCountChange} />);
+
+    await userEvent.click(getButton('증가'));
+
+    expect(mockedOnCountChange).toHaveBeenCalledTimes(1);
+  });
+
+  it('최대값 도달 시 onMaxReached 콜백이 호출되어야 한다', async () => {
+    const mockedOnMaxReached = jest.fn();
+    const 초기값 = 0;
+    const 최대값 = 10;
+    render(<Counter initialValue={초기값} maxValue={최대값} onMaxReached={mockedOnMaxReached} />);
+
+    for (let i = 초기값; i < 최대값; i++) {
+      await userEvent.click(getButton('증가'));
+    }
+
+    expect(mockedOnMaxReached).toHaveBeenCalled();
+  });
+
+  it('실행 취소 버튼 클릭 시 이전 값으로 돌아가야 한다', async () => {
+    render(<Counter />);
+
+    await userEvent.click(getButton('증가'));
+    await userEvent.click(getButton('실행 취소'));
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent('0');
+  });
+
+  it('최근 3개의 값이 히스토리에 표시되어야 한다', async () => {
+    render(<Counter />);
+
+    await userEvent.click(getButton('증가'));
+    await userEvent.click(getButton('증가'));
+    await userEvent.click(getButton('증가'));
+
+    expect(screen.getByTestId('history-display')).toHaveTextContent('1, 2, 3');
+  });
+
+  it('여러 번의 증가/감소 후 실행 취소가 정상적으로 동작해야 한다', async () => {
+    render(<Counter />);
+
+    await userEvent.click(getButton('증가'));
+    await userEvent.click(getButton('감소'));
+    await userEvent.click(getButton('실행 취소'));
+
+    expect(screen.getByTestId('count-display')).toHaveTextContent('1');
+  });
+});
+
+describe('Counter 컴포넌트 UI 테스트', () => {
+  it('제목이 "카운터"로 표시되어야 한다', () => {
+    render(<Counter />);
+
+    expect(screen.getByRole('heading')).toHaveTextContent('카운터');
+  });
+
+  it('숫자를 표시하는 영역이 있어야 한다', () => {
+    render(<Counter />);
+
+    expect(screen.getByTestId('count-display')).toBeInTheDocument();
+  });
+
+  it('버튼 그룹이 순서대로 [감소-증가-리셋-실행취소] 버튼을 포함해야 한다', () => {
+    render(<Counter />);
+
+    expect(screen.getAllByRole('button').map((버튼) => 버튼.textContent)).toEqual([
+      '1만큼 감소',
+      '1만큼 증가',
+      '리셋',
+      '실행 취소',
+    ]);
+  });
+
+  it('증가/감소 버튼에는 step 값이 표시되어야 한다', () => {
+    render(<Counter />);
+
+    expect(getButton('증가')).toHaveTextContent('1');
+    expect(getButton('감소')).toHaveTextContent('1');
+  });
+
+  it('히스토리 영역에는 "최근 기록: "이라는 텍스트가 포함되어야 한다', () => {
+    render(<Counter />);
+
+    expect(screen.getByTestId('history-display')).toHaveTextContent('최근 기록: ');
+  });
+
+  describe('버튼 스타일', () => {
+    it('모든 버튼은 동일한 크기여야 한다', () => {
+      render(<Counter />);
+
+      screen.getAllByRole('button').forEach((버튼) => {
+        expect(버튼).toHaveClass('px-4 py-2');
+      });
+    });
+
+    it('비활성화된 버튼은 시각적으로 구분되어야 한다', () => {
+      render(<Counter />);
+
+      expect(getButton('증가')).not.toHaveClass('disabled:opacity-50 disabled:cursor-not-allowed');
+      expect(getButton('실행 취소')).toHaveClass('disabled:opacity-50 disabled:cursor-not-allowed');
+    });
+  });
+
+  describe('숫자 표시 영역', () => {
+    it('숫자는 중앙 정렬되어야 한다', () => {
+      render(<Counter />);
+
+      expect(screen.getByTestId('count-display')).toHaveClass('flex items-center justify-center');
+    });
+  });
+
+  describe('히스토리 표시', () => {
+    it('히스토리는 쉼표로 구분되어 표시되어야 한다', async () => {
+      render(<Counter />);
+
+      await userEvent.click(getButton('증가'));
+
+      expect(screen.getByTestId('history-display')).toHaveTextContent('0, 1');
+    });
+
+    it('실행 취소 시 히스토리도 함께 업데이트되어야 한다', async () => {
+      render(<Counter />);
+
+      await userEvent.click(getButton('증가'));
+      await userEvent.click(getButton('실행 취소'));
+
+      expect(screen.getByTestId('history-display')).toHaveTextContent('0');
+    });
+  });
+});