Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input UI 설정, 스토리 북 및 테스트 코드 작성 #8

Merged
merged 14 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
},
});
Loading