Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ac02921
config: 아키텍쳐 변경에 따른 스크립트 수정
BHyeonKim May 26, 2025
6f4704b
config: 기존 컨테이너 및 이미지 삭제
BHyeonKim May 26, 2025
d812fdb
config: 단위테스트 환경 구성
BHyeonKim May 28, 2025
2d6c4c0
test: 스위치 컴포넌트 단위테스트 추가
BHyeonKim May 28, 2025
6cf6094
test: NumberInput 컴포넌트 단위 테스트 추가
BHyeonKim May 28, 2025
d141ee4
config: vitest 절대경로 설정 추가
BHyeonKim May 28, 2025
e25f613
test: logo 컴포넌트 단위테스트 추가
BHyeonKim May 28, 2025
23adab0
test: LogoWithTitle 컴포넌트 단위 테스트 추가
BHyeonKim May 28, 2025
e92967c
test: Button 컴포넌트 단위 테스트 추가
BHyeonKim May 28, 2025
6bca61d
config: lint unsafe fix 제거
BHyeonKim May 28, 2025
178a628
test: util 함수 test 추가
BHyeonKim May 28, 2025
0547245
test: ContainerTitle 컴포넌트 단위테스트 추가
BHyeonKim May 29, 2025
ca416e7
test: useClickOutside 훅 테스트
BHyeonKim May 29, 2025
0f5c941
test: useScrollToBottom 훅 단위테스트 추가
BHyeonKim May 29, 2025
4244874
test: useDimensions 훅 단위테스트 추가
BHyeonKim May 29, 2025
2e3d162
fix: useDimensions 훅 수정
BHyeonKim May 29, 2025
beceefc
config: workflows 추가
BHyeonKim May 30, 2025
cf6d4dd
config workflow 추가
BHyeonKim May 30, 2025
def077e
config: sonarqube 설정 추가
BHyeonKim May 30, 2025
6aa7a2e
test: CoinPriceWithName 컴포넌트 단위테스트 추가
BHyeonKim May 30, 2025
31238a7
test: QuantityInput 컴포넌트 단위테스트 추가
BHyeonKim May 30, 2025
50d2e9b
test: AIChatBot 컴포넌트 단위테스트 추가
BHyeonKim May 30, 2025
5434121
test: ChatButton 단위테스트 추가
BHyeonKim May 30, 2025
d1ae2a5
test: ChatWindow 컴포넌트 단위 테스트 추가
BHyeonKim May 30, 2025
57738ee
test: ChatWindow 컴포넌트 단위 테스트 추가
BHyeonKim Jun 1, 2025
6c578df
refactor: ChatWindow 불필요 코드 제거
BHyeonKim Jun 1, 2025
963bb4c
config: sonarqube 커버리지 설정
BHyeonKim Jun 1, 2025
a59cb08
test: MessageBox 컴포넌트 단위 테스트 추가
BHyeonKim Jun 1, 2025
ddd8e7d
test: 테스트 불필요 파일 커버리지에서 제외
BHyeonKim Jun 1, 2025
98d4fb1
docs: pr template 수정
BHyeonKim Jun 1, 2025
984574c
test: CoinWithIconAndName 컴포넌트 단위 테스트 추가
BHyeonKim Jun 1, 2025
9a08ba1
test: CoinListItem 컴포넌트 단위 테스트 추가
BHyeonKim Jun 1, 2025
685d61b
test: CoinListWithSearchBar 컴포넌트 단위 테스트 추가
BHyeonKim Jun 1, 2025
f60f511
test: formMachine 단위 테스트 추가
BHyeonKim Jun 1, 2025
c579098
refactor: formMachine 로직 수정
BHyeonKim Jun 2, 2025
90dea01
test: StompPrivider 단위테스트 추가
BHyeonKim Jun 2, 2025
e539bd7
test: OrderForm 컴포넌트 단위테스트 추가
BHyeonKim Jun 2, 2025
2d05ee3
test: ExecutionItem 컴포넌트 단위 테스트 추가
BHyeonKim Jun 2, 2025
b3db4f0
test: ExecutionList 컴포넌트 단위 테스트 추가
BHyeonKim Jun 2, 2025
09a7594
refactor: || => ?? 으로 변경
BHyeonKim Jun 2, 2025
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
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이
## ✅ PR Checklist
PR이 다음 요구 사항을 충족하는지 확인하세요.

[ ] 커밋 메시지 컨벤션에 맞게 작성했습니다.
[ ] 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).
- [ ] 커밋 메시지 컨벤션에 맞게 작성했습니다.
- [ ] 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

<br/>
Closes 이슈키-이슈번호
55 changes: 55 additions & 0 deletions .github/workflows/code-analyze-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Code Analyze Pull Request

run-name: Run code analyze triggered with pull request by ${{github.actor}}

on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- main
- develop
env:
NODE_VERSION: 18.12.0

jobs:
code_analysis:

runs-on: ubuntu-latest

steps:
- name: 'Checkout repository on branch: ${{ github.REF }}'
uses: actions/checkout@v3
with:
ref: ${{ github.HEAD_REF }}

- name: Retrieve entire repository history
run: |
git fetch --prune --unshallow

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}

- name: Cache node modules
uses: actions/cache@v3
id: npm-cache
with:
path: '**/node_modules'
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install Dependencies
if: steps.npm-cache.outputs.cache-hit != 'true'
run: npm install

- name: Coverage Test
continue-on-error: true
run: npm run coverage

- name: Run an analysis of the ${{ github.REF }} branch ${{ github.BASE_REF }} base
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
48 changes: 48 additions & 0 deletions .github/workflows/code-analyze-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Code Analyze branch

run-name: Run code analyze triggered with push by ${{github.actor}}

on:
push:
branches:
- main
- develop

jobs:
code_analysis:
runs-on: ubuntu-latest

steps:
- name: 'Checkout repository on branch: ${{ github.REF }}'
uses: actions/checkout@v3
with:
ref: ${{ github.REF }}
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}

- name: Cache node modules
uses: actions/cache@v3
id: npm-cache
with:
path: '**/node_modules'
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install Dependencies
if: steps.npm-cache.outputs.cache-hit != 'true'
run: yarn install

- name: Coverage Test
continue-on-error: true
run: yarn run coverage

- name: 'Run an analysis of the ${{ github.REF }} branch'
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
20 changes: 18 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Deploy remix app

run-name: Deploy remix app to docker hub by ${{github.actor}}
run-name: Deploy remix app to docker hub and start services by ${{github.actor}}

on:
push:
Expand All @@ -19,6 +19,8 @@ jobs:
echo "VITE_OAUTH_URL=${{ secrets.VITE_OAUTH_URL }}" > .env
echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" >> .env
echo "VITE_STOMP_URL=${{ secrets.VITE_STOMP_URL }}" >> .env
echo "VITE_AI_URL=${{ secrets.VITE_AI_URL }}" >> .env

- name: Build image
run: |
docker build -t ${{secrets.DOCKER_USERNAME}}/if-fe:latest .
Expand All @@ -29,4 +31,18 @@ jobs:
password: ${{secrets.DOCKER_TOKEN}}
- name: Push image to Docker hub
run: |
docker push ${{secrets.DOCKER_USERNAME}}/if-fe:latest
docker push ${{secrets.DOCKER_USERNAME}}/if-fe:latest
- name: Connect to cloud server
uses: appleboy/[email protected]
with:
host: ${{secrets.FRONTEND_HOST}}
username: ${{secrets.FRONTEND_USERNAME}}
key: ${{secrets.FRONTEND_SECRET_KEY}}
port: ${{secrets.FRONTEND_PORT}}
script: |
cd ~
docker stop frontend || true
docker rm frontend || true
docker rmi ${{secrets.DOCKER_USERNAME}}/if-fe:latest || true
docker pull ${{secrets.DOCKER_USERNAME}}/if-fe:latest
docker run -d --name frontend -p 3000:3000 ${{secrets.DOCKER_USERNAME}}/if-fe:latest
27 changes: 0 additions & 27 deletions .github/workflows/start-services.yml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ dist-ssr
/.react-router/
/build/

coverage
.env
6 changes: 3 additions & 3 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"options": {
"strictCase": false,
"requireAscii": true,
"filenameCases": ["camelCase", "export"]
"filenameCases": ["PascalCase", "camelCase", "export"]
}
}
},
Expand All @@ -60,8 +60,8 @@
{
"include": [
"test/**/*",
"*.test.{ts,tsx,js,jsx}",
"*.spec.{ts,tsx,js,jsx}",
"**/*.test.{ts,tsx,js,jsx}",
"**/*.spec.{ts,tsx,js,jsx}",
"src/app/routes/*"
],
"linter": {
Expand Down
17 changes: 12 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"build": "react-router build",
"start": "react-router-serve ./build/server/index.js",
"typecheck": "react-router typegen && tsc",
"lint": "biome check --write --unsafe .",
"test": "vitest",
"coverage": "vitest run --coverage",
"lint": "biome check --write .",
"postinstall": "husky"
},
"lint-staged": {
Expand Down Expand Up @@ -38,23 +40,28 @@
"@react-router/dev": "^7.5.3",
"@svgr/rollup": "^8.1.0",
"@tailwindcss/vite": "^4.1.5",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^22.15.3",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.3",
"@vitest/coverage-v8": "^3.1.4",
"globals": "^16.0.0",
"husky": "^9.1.7",
"jsdom": "^26.1.0",
"lint-staged": "^15.5.1",
"msw": "^2.8.2",
"tailwindcss": "^4.1.5",
"typescript": "~5.7.2",
"vite": "^6.3.1",
"vite-plugin-svgr": "^4.3.0",
"vite-tsconfig-paths": "^5.1.4"
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.1.4"
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"msw": {
"workerDirectory": [
"public"
]
"workerDirectory": ["public"]
}
}
1 change: 1 addition & 0 deletions setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
30 changes: 30 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 프로젝트 식별자
sonar.projectKey=CleanEngine_cleanengine-fe_c6875537-ed9d-4dfe-b79c-ea5cb6d2a0e3

# 프로젝트 이름
sonar.projectName=CleanEngine Frontend

# 소스 코드 위치
sonar.sources=src

# 테스트 파일 위치 및 패턴
sonar.tests=src
sonar.test.inclusions=**/*.test.tsx,**/*.test.ts,**/*.spec.tsx,**/*.spec.ts

# TypeScript/JavaScript 설정
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.typescript.tsconfigPath=tsconfig.json

# 분석에서 제외할 파일/디렉토리
sonar.exclusions=node_modules/**,build/**,dist/**,coverage/**,public/**,**/*.test.tsx,**/*.test.ts,**/*.spec.tsx,**/*.spec.ts

# 코드 중복 검사 제외
sonar.cpd.exclusions=**/*.test.tsx,**/*.test.ts

# 언어 설정
sonar.language=ts
sonar.typescript.file.suffixes=.ts,.tsx
sonar.javascript.file.suffixes=.js,.jsx

# 커버리지 파일 위치
sonar.javascript.lcov.reportPaths=./coverage/lcov.info
3 changes: 3 additions & 0 deletions src/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* v8 ignore start */
import { StrictMode, startTransition } from 'react';
import { hydrateRoot } from 'react-dom/client';
import { HydratedRouter } from 'react-router/dom';
Expand All @@ -21,3 +22,5 @@ prepareApp().then(() => {
);
});
});

/* v8 ignore end */
3 changes: 3 additions & 0 deletions src/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* v8 ignore start */
import { PassThrough } from 'node:stream';

import { createReadableStreamFromReadable } from '@react-router/node';
Expand Down Expand Up @@ -73,3 +74,5 @@ export default function handleRequest(
setTimeout(abort, streamTimeout + 1000);
});
}

/* v8 ignore end */
36 changes: 36 additions & 0 deletions src/app/provider/StompProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

import StompProvider, { useStompClient } from './StompProvider';

vi.mock('@stomp/stompjs', () => {
return {
Client: vi.fn().mockImplementation(() => {
return {
activate: vi.fn(),
deactivate: vi.fn(),
onConnect: null,
onDisconnect: null,
onWebSocketError: null,
onStompError: null,
};
}),
};
});

describe('useStompClient 테스트', () => {
it('useStompClient hook은 StompProvider 외부에서 사용하면 에러를 던진다.', () => {
expect(() => renderHook(() => useStompClient())).toThrowError();
});

it('useStompClient hook은 StompProvider 내부에서 사용하면 정상 작동한다.', () => {
const { result } = renderHook(() => useStompClient(), {
wrapper: ({ children }) => (
<StompProvider brokerURL="">{children}</StompProvider>
),
});

expect(result.current).toHaveProperty('client');
expect(result.current).toHaveProperty('connected');
});
});
16 changes: 10 additions & 6 deletions src/app/provider/StompProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ type StompContextType = {
connected: boolean;
};

export const StompContext = createContext<StompContextType>({
client: null,
connected: false,
});
export const StompContext = createContext<StompContextType | null>(null);

export default function StompProvider({
children,
Expand Down Expand Up @@ -69,6 +66,13 @@ export default function StompProvider({
}

export function useStompClient() {
const { client, connected } = useContext(StompContext);
return { client, connected };
const stompContext = useContext(StompContext);

if (!stompContext) {
throw new Error(
'useStompClient hook은 StompProvider 내부에서 사용해야 합니다.',
);
}

return { client: stompContext.client, connected: stompContext.connected };
}
2 changes: 2 additions & 0 deletions src/app/routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* v8 ignore start */
import type { RouteConfig } from '@react-router/dev/routes';
import { flatRoutes } from '@react-router/fs-routes';

export default flatRoutes() satisfies RouteConfig;
/* v8 ignore end */
2 changes: 2 additions & 0 deletions src/entities/coin/api/coin.endpoint.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* v8 ignore start */
import httpClient from '~/shared/api/httpClient';
import type { CoinListResponse } from '../types/coin.type';

Expand All @@ -6,3 +7,4 @@ export default {
return httpClient.get<CoinListResponse>('api/asset');
},
};
/* v8 ignore end */
Loading