Skip to content

Commit

Permalink
Merge pull request #8 from zagdang/feat/input
Browse files Browse the repository at this point in the history
Input UI 설정, 스토리 북 및 테스트 코드 작성
  • Loading branch information
KimKyuHoi authored Dec 6, 2024
2 parents 436b920 + 7a7bff3 commit 57d2c32
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: 'Chromatic PR Review'
name: 'Chromatic PR Check'

permissions:
pull-requests: write
Expand Down Expand Up @@ -30,11 +30,11 @@ jobs:
- name: Install dependencies
run: |
yarn install --immutable
yarn install --immutable
yarn dlx @yarnpkg/sdks vscode
- name: Build Storybook
run: yarn workspace @zagdang/ui build-storybook
run: yarn workspace @zagdang/ui build-storybook --webpack-stats-json

- name: Create Preview
id: chromatic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: PR and Push Check
name: PR and Push Check Test

on:
pull_request:
Expand All @@ -18,7 +18,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18' # 프로젝트에서 사용하는 Node.js 버전으로 설정
node-version: '18'

- name: Cache yarn dependencies
uses: actions/cache@v3
Expand All @@ -41,4 +41,4 @@ jobs:
run: yarn format --check

- name: Build the project
run: yarn build # 빌드 체크 추가
run: yarn build
33 changes: 0 additions & 33 deletions .github/workflows/ui-packaging-test.yml

This file was deleted.

56 changes: 56 additions & 0 deletions .github/workflows/unit.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: UI Unit Test

permissions:
pull-requests: write
contents: read

on:
pull_request:
types: [opened, synchronize, reopened]
branches: [main, develop]

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/ui

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: '18'

- name: Set up Yarn 2 (Berry)
run: |
corepack enable
corepack prepare [email protected] --activate
- name: Install dependencies
run: yarn install --immutable

- name: Run tests with coverage
run: yarn test --coverage

- name: Get Coverage Info
id: coverage
run: |
COVERAGE_REPORT=$(cat coverage/coverage-summary.json)
echo "statements=$(echo $COVERAGE_REPORT | jq -r '.total.statements.pct')" >> $GITHUB_OUTPUT
echo "branches=$(echo $COVERAGE_REPORT | jq -r '.total.branches.pct')" >> $GITHUB_OUTPUT
echo "functions=$(echo $COVERAGE_REPORT | jq -r '.total.functions.pct')" >> $GITHUB_OUTPUT
echo "lines=$(echo $COVERAGE_REPORT | jq -r '.total.lines.pct')" >> $GITHUB_OUTPUT
- name: Comment PR with Coverage
uses: thollander/actions-comment-pull-request@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
message: |
## Test Coverage Report 📊
- Statements: ${{ steps.coverage.outputs.statements }}%
- Branches: ${{ steps.coverage.outputs.branches }}%
- Functions: ${{ steps.coverage.outputs.functions }}%
- Lines: ${{ steps.coverage.outputs.lines }}%
11 changes: 11 additions & 0 deletions packages/ui/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,16 @@ export default {
transform: {
'^.+\\.(ts|tsx)$': ['ts-jest'],
'\\.css$': 'jest-transform-css'
},
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['json-summary', 'text', 'lcov'],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
}
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test": "jest",
"test:watch": "jest --watch",
"test:watch": "jest --watchAll",
"test:coverage": "jest --coverage",
"test:ci": "jest --ci",
"test:changed": "jest --changedSince=HEAD",
Expand Down
16 changes: 14 additions & 2 deletions packages/ui/src/components/Button/button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';

import { Button } from './button';

Expand All @@ -17,7 +18,18 @@ describe('Button', () => {
});

it('renders with variant classes', () => {
render(<Button variant="destructive">Delete</Button>);
expect(screen.getByText('Delete')).toHaveClass('bg-destructive');
render(<Button>Default</Button>);
const button = screen.getByRole('button', { name: 'Default' });
expect(button.tagName).toBe('BUTTON');
});

it('renders as a custom component when asChild is true', () => {
render(
<Button asChild>
<a href="/test">Link</a>
</Button>,
);
const link = screen.getByRole('link', { name: 'Link' });
expect(link).toHaveAttribute('href', '/test');
});
});
93 changes: 93 additions & 0 deletions packages/ui/src/components/Input/input.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Input.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';

import { Input } from './input';

import { Button } from '@/components';

const meta = {
title: 'Components/Input',
component: Input,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof Input>;

export default meta;
type Story = StoryObj<typeof Input>;

export const Default: Story = {
args: {
placeholder: 'Enter text...',
},
};

export const Widths: Story = {
decorators: [
(Story) => (
<div className="min-w-[600px] p-4">
<div className="space-y-4">
<div className="w-full">
<p className="text-sm text-gray-500 mb-2">Full width (default)</p>
<Story />
</div>
<div className="w-96">
<p className="text-sm text-gray-500 mb-2">w-96</p>
<Input placeholder="Width: 24rem" />
</div>
<div className="w-72">
<p className="text-sm text-gray-500 mb-2">w-72</p>
<Input placeholder="Width: 18rem" />
</div>
<div className="w-1/2">
<p className="text-sm text-gray-500 mb-2">w-1/2</p>
<Input placeholder="Width: 50%" />
</div>
</div>
</div>
),
],
args: {
placeholder: 'Full width input...',
},
};

export const Disabled: Story = {
args: {
placeholder: 'Disabled input',
disabled: true,
},
};

export const WithValue_Controlled: Story = {
render: () => {
const [value, setValue] = React.useState('Sample text');

return (
<div className="flex gap-2">
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Type to change..."
/>
<Button onClick={() => alert(`Current value: ${value}`)}>Check</Button>
</div>
);
},
};

export const WithType: Story = {
args: {
type: 'password',
placeholder: 'Enter password',
},
};

export const WithError: Story = {
args: {
className: 'border-error',
placeholder: 'Error state',
},
};
39 changes: 39 additions & 0 deletions packages/ui/src/components/Input/input.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Input.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import React from 'react';

import { Input } from './input';

describe('Input Component', () => {
it('renders correctly', () => {
render(<Input placeholder="Test input" />);
const input = screen.getByPlaceholderText('Test input');
expect(input).toBeInTheDocument();
});

it('accepts value changes', () => {
render(<Input />);
const input = screen.getByRole('textbox');

fireEvent.change(input, { target: { value: 'Test value' } });
expect(input).toHaveValue('Test value');
});

it('forwards ref correctly', () => {
const ref = React.createRef<HTMLInputElement>();
render(<Input ref={ref} />);
expect(ref.current).toBeInstanceOf(HTMLInputElement);
});

it('handles disabled state', () => {
render(<Input disabled />);
const input = screen.getByRole('textbox');
expect(input).toBeDisabled();
});

it('handles different input types', () => {
render(<Input type="email" />);
const input = screen.getByRole('textbox');
expect(input).toHaveAttribute('type', 'email');
});
});
22 changes: 22 additions & 0 deletions packages/ui/src/components/Input/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';

import { cn } from '@/lib/utils';

const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
'flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = 'Input';

export { Input };
3 changes: 2 additions & 1 deletion packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Button as default } from './Button/button';
export { Button } from './Button/button';
export { Input } from './Input/input';
1 change: 1 addition & 0 deletions packages/ui/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default {
DEFAULT: 'hsl(var(--brand-600))',
foreground: 'hsl(var(--brand-600-foreground))', // error-foreground가 추가되었을 경우
},
error: 'hsl(var(--error))',
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ export default defineConfig({
rollupOptions: {
external: ['react', 'react-dom'],
},

sourcemap: true,
reportCompressedSize: false,
chunkSizeWarningLimit: 1000,
manifest: true,
},
});

0 comments on commit 57d2c32

Please sign in to comment.