Skip to content

Commit 192da67

Browse files
committed
feat: front tests with vitest
1 parent c01e685 commit 192da67

File tree

32 files changed

+2461
-2
lines changed

32 files changed

+2461
-2
lines changed

.github/workflows/preview.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,37 @@ permissions:
77
deployments: write
88
pull-requests: write
99
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: '20'
19+
cache: 'npm'
20+
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Run tests
25+
run: npm run test:run
26+
27+
- name: Generate coverage report
28+
run: npm run test:coverage
29+
continue-on-error: true
30+
31+
- name: Upload coverage report
32+
uses: actions/upload-artifact@v4
33+
if: always()
34+
with:
35+
name: coverage-report
36+
path: coverage/
37+
retention-days: 30
38+
1039
deploy:
40+
needs: test
1141
runs-on: ubuntu-latest
1242
steps:
1343
- uses: actions/checkout@v4

.github/workflows/production.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,37 @@ permissions:
77
deployments: write
88
pull-requests: write
99
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: '20'
19+
cache: 'npm'
20+
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Run tests
25+
run: npm run test:run
26+
27+
- name: Generate coverage report
28+
run: npm run test:coverage
29+
continue-on-error: true
30+
31+
- name: Upload coverage report
32+
uses: actions/upload-artifact@v4
33+
if: always()
34+
with:
35+
name: coverage-report-production
36+
path: coverage/
37+
retention-days: 90
38+
1039
deploy:
40+
needs: test
1141
runs-on: ubuntu-latest
1242
steps:
1343
- uses: actions/checkout@v4

.github/workflows/test.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Run Tests
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [20.x]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
cache: 'npm'
26+
27+
- name: Install dependencies
28+
run: npm ci
29+
30+
- name: Run linter
31+
run: npm run lint
32+
continue-on-error: true
33+
34+
- name: Run tests
35+
run: npm run test:run
36+
37+
- name: Generate coverage report
38+
run: npm run test:coverage
39+
40+
- name: Upload coverage to artifacts
41+
uses: actions/upload-artifact@v4
42+
if: always()
43+
with:
44+
name: coverage-report-${{ github.sha }}
45+
path: coverage/
46+
retention-days: 30
47+

package.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
"dev": "next dev",
77
"build": "next build",
88
"start": "next start",
9-
"lint": "next lint"
9+
"lint": "next lint",
10+
"test": "vitest",
11+
"test:ui": "vitest --ui",
12+
"test:run": "vitest run",
13+
"test:coverage": "vitest run --coverage"
1014
},
1115
"dependencies": {
1216
"@tanstack/react-query": "4",
@@ -20,15 +24,25 @@
2024
},
2125
"devDependencies": {
2226
"@eslint/js": "^9.39.1",
27+
"@testing-library/dom": "^10.4.1",
28+
"@testing-library/jest-dom": "^6.9.1",
29+
"@testing-library/react": "^16.3.0",
30+
"@testing-library/user-event": "^14.6.1",
2331
"@types/node": "^20",
2432
"@types/react": "^19",
2533
"@types/react-dom": "^19",
2634
"@types/react-icons": "^3.0.0",
35+
"@vitejs/plugin-react": "^5.1.1",
36+
"@vitest/coverage-v8": "^4.0.15",
37+
"@vitest/ui": "^4.0.15",
2738
"eslint": "^9.39.1",
2839
"eslint-config-next": "^16.0.5",
2940
"globals": "^16.5.0",
3041
"jiti": "^2.6.1",
42+
"jsdom": "^27.2.0",
43+
"msw": "^2.12.3",
3144
"typescript": "^5",
32-
"typescript-eslint": "^8.48.0"
45+
"typescript-eslint": "^8.48.0",
46+
"vitest": "^4.0.15"
3347
}
3448
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { IComment } from '@/interfaces/comment'
2+
import { mockAuthor } from './user.mock'
3+
4+
export const mockComment: IComment = {
5+
id: 'comment-123',
6+
ideaId: '123',
7+
content: 'Ótima ideia! Gostaria de colaborar.',
8+
parentCommentId: null,
9+
author: mockAuthor,
10+
replies: 2,
11+
likes: 3,
12+
isLiked: false,
13+
createdAt: '2024-01-01T00:00:00.000Z',
14+
}
15+
16+
export const mockCommentReply: IComment = {
17+
...mockComment,
18+
id: 'comment-124',
19+
parentCommentId: 'comment-123',
20+
content: 'Obrigado! Vamos conversar mais sobre isso.',
21+
replies: 0,
22+
}
23+

src/__tests__/mocks/handlers.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { http, HttpResponse } from 'msw'
2+
import { mockIdea, mockIdeaLiked } from './idea.mock'
3+
import { mockComment } from './comment.mock'
4+
import { mockCurrentUser, mockAuthor } from './user.mock'
5+
6+
const API_URL = 'http://localhost:3000/v1'
7+
8+
export const handlers = [
9+
http.post(`${API_URL}/like`, () => {
10+
return HttpResponse.json({ success: true })
11+
}),
12+
13+
http.post(`${API_URL}/view`, () => {
14+
return HttpResponse.json({ success: true })
15+
}),
16+
17+
http.post(`${API_URL}/comment`, () => {
18+
return HttpResponse.json(mockComment)
19+
}),
20+
21+
http.post(`${API_URL}/collaboration-request`, () => {
22+
return HttpResponse.json({ success: true })
23+
}),
24+
25+
http.patch(`${API_URL}/collaboration-approval`, () => {
26+
return HttpResponse.json({ success: true })
27+
}),
28+
29+
http.post(`${API_URL}/follow`, () => {
30+
return HttpResponse.json({ success: true })
31+
}),
32+
33+
http.post(`${API_URL}/idea`, () => {
34+
return HttpResponse.json(mockIdea)
35+
}),
36+
37+
http.patch(`${API_URL}/idea/:id`, ({ params }) => {
38+
return HttpResponse.json({
39+
...mockIdea,
40+
id: params.id,
41+
})
42+
}),
43+
44+
http.delete(`${API_URL}/idea/:id`, () => {
45+
return HttpResponse.json({ success: true })
46+
}),
47+
48+
http.get(`${API_URL}/idea`, () => {
49+
return HttpResponse.json({
50+
data: [mockIdea, mockIdeaLiked],
51+
total: 2,
52+
page: 0,
53+
quantity: 10,
54+
})
55+
}),
56+
57+
http.get(`${API_URL}/idea/:id`, ({ params }) => {
58+
return HttpResponse.json({
59+
...mockIdea,
60+
id: params.id,
61+
})
62+
}),
63+
64+
http.get(`${API_URL}/comment`, () => {
65+
return HttpResponse.json({
66+
data: [mockComment],
67+
total: 1,
68+
page: 0,
69+
quantity: 10,
70+
})
71+
}),
72+
73+
http.get(`${API_URL}/user/my-user`, () => {
74+
return HttpResponse.json(mockCurrentUser)
75+
}),
76+
77+
http.get(`${API_URL}/user/:id`, () => {
78+
return HttpResponse.json(mockAuthor)
79+
}),
80+
81+
http.get(`${API_URL}/user`, ({ request }) => {
82+
const url = new URL(request.url)
83+
const pathname = url.pathname
84+
85+
if (pathname.endsWith('/my-user')) {
86+
return HttpResponse.json(mockCurrentUser)
87+
}
88+
89+
if (pathname.match(/\/user\/[^/]+$/)) {
90+
return HttpResponse.json(mockAuthor)
91+
}
92+
93+
return HttpResponse.json({
94+
data: [mockCurrentUser, mockAuthor],
95+
total: 2,
96+
page: 0,
97+
quantity: 10,
98+
})
99+
}),
100+
101+
http.patch(`${API_URL}/user`, () => {
102+
return HttpResponse.json(mockCurrentUser)
103+
}),
104+
105+
http.delete(`${API_URL}/user`, () => {
106+
return HttpResponse.json({ success: true })
107+
}),
108+
]
109+

src/__tests__/mocks/idea.mock.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { IIdea } from '@/interfaces/idea'
2+
import { mockAuthor } from './user.mock'
3+
4+
export const mockIdea: IIdea = {
5+
id: '123',
6+
title: 'Aplicativo de Receitas com IA',
7+
content: 'Um app que sugere receitas baseadas nos ingredientes que você tem em casa',
8+
images: ['/card.png'],
9+
links: ['https://example.com'],
10+
projectId: null,
11+
author: mockAuthor,
12+
tags: ['mobile', 'ia', 'culinária'],
13+
comments: 5,
14+
likes: 10,
15+
views: 50,
16+
isLiked: false,
17+
isViewed: false,
18+
createdAt: '2024-01-01T00:00:00.000Z',
19+
updatedAt: '2024-01-01T00:00:00.000Z',
20+
hasPendingCollaborationRequest: false,
21+
}
22+
23+
export const mockIdeaLiked: IIdea = {
24+
...mockIdea,
25+
id: '124',
26+
title: 'Sistema de Gerenciamento de Tarefas',
27+
isLiked: true,
28+
}
29+
30+
export const mockIdeaWithoutTags: IIdea = {
31+
...mockIdea,
32+
id: '125',
33+
tags: [],
34+
}
35+

src/__tests__/mocks/user.mock.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { IAuthor } from '@/interfaces/user'
2+
3+
export const mockAuthor: IAuthor = {
4+
id: 'user-123',
5+
displayName: 'johndoe',
6+
name: 'John Doe',
7+
avatarUrl: 'https://example.com/avatar.jpg',
8+
bio: 'Desenvolvedor Full Stack',
9+
}
10+
11+
export const mockCurrentUser: IAuthor = {
12+
id: 'current-user-456',
13+
displayName: 'currentuser',
14+
name: 'Current User',
15+
avatarUrl: 'https://example.com/current-avatar.jpg',
16+
bio: 'Usuário atual',
17+
}
18+

src/__tests__/setup/msw.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { setupServer } from 'msw/node'
2+
import { handlers } from '../mocks/handlers'
3+
4+
export const server = setupServer(...handlers)
5+

0 commit comments

Comments
 (0)