Skip to content

Commit e0deaf6

Browse files
committed
Merge branch 'tests'
Dodanie testów jednostkowych dla komponentów.
2 parents 4f70847 + 36b3421 commit e0deaf6

11 files changed

Lines changed: 1215 additions & 1 deletion

File tree

package-lock.json

Lines changed: 783 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
"dev": "vite",
1010
"build": "tsc -b && vite build",
1111
"lint": "eslint .",
12-
"preview": "vite preview"
12+
"preview": "vite preview",
13+
"test": "vitest",
14+
"test:ui": "vitest --ui"
1315
},
1416
"dependencies": {
1517
"@supabase/supabase-js": "^2.89.0",
@@ -20,6 +22,9 @@
2022
},
2123
"devDependencies": {
2224
"@eslint/js": "^9.39.1",
25+
"@testing-library/jest-dom": "^6.9.1",
26+
"@testing-library/react": "^16.3.1",
27+
"@testing-library/user-event": "^14.6.1",
2328
"@types/node": "^24.10.1",
2429
"@types/react": "^19.2.5",
2530
"@types/react-dom": "^19.2.3",
@@ -30,6 +35,7 @@
3035
"eslint-plugin-react-hooks": "^7.0.1",
3136
"eslint-plugin-react-refresh": "^0.4.24",
3237
"globals": "^16.5.0",
38+
"jsdom": "^27.4.0",
3339
"postcss": "^8.5.6",
3440
"supabase": "^2.70.5",
3541
"tailwindcss": "^3.4.19",

src/components/Login.test.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { render, screen, fireEvent } from '@testing-library/react'
2+
import { describe, it, expect, vi, beforeEach } from 'vitest'
3+
import Login from './Login'
4+
5+
// Mock auth store
6+
vi.mock('../store/authStore', () => ({
7+
useAuthStore: vi.fn(() => ({
8+
signIn: vi.fn().mockResolvedValue({ error: null }),
9+
})),
10+
}))
11+
12+
describe('Login', () => {
13+
const mockOnSwitchToRegister = vi.fn()
14+
15+
beforeEach(() => {
16+
vi.clearAllMocks()
17+
})
18+
19+
it('renders login form', () => {
20+
render(<Login onSwitchToRegister={mockOnSwitchToRegister} />)
21+
22+
expect(screen.getByText('Menadżer Zadań')).toBeInTheDocument()
23+
expect(screen.getByText('Zaloguj się do swojego konta')).toBeInTheDocument()
24+
expect(screen.getByLabelText(/Email/)).toBeInTheDocument()
25+
expect(screen.getByLabelText(/Hasło/)).toBeInTheDocument()
26+
expect(screen.getByRole('button', { name: /Zaloguj się/ })).toBeInTheDocument()
27+
})
28+
29+
it('calls onSwitchToRegister when register link is clicked', () => {
30+
render(<Login onSwitchToRegister={mockOnSwitchToRegister} />)
31+
32+
const registerButton = screen.getByRole('button', { name: /Zarejestruj się/ })
33+
fireEvent.click(registerButton)
34+
35+
expect(mockOnSwitchToRegister).toHaveBeenCalledTimes(1)
36+
})
37+
38+
it('updates email and password inputs', () => {
39+
render(<Login onSwitchToRegister={mockOnSwitchToRegister} />)
40+
41+
const emailInput = screen.getByLabelText(/Email/)
42+
const passwordInput = screen.getByLabelText(/Hasło/)
43+
44+
fireEvent.change(emailInput, { target: { value: 'test@example.com' } })
45+
fireEvent.change(passwordInput, { target: { value: 'password123' } })
46+
47+
expect(emailInput).toHaveValue('test@example.com')
48+
expect(passwordInput).toHaveValue('password123')
49+
})
50+
51+
it('submits form when button is clicked', () => {
52+
render(<Login onSwitchToRegister={mockOnSwitchToRegister} />)
53+
54+
const emailInput = screen.getByLabelText(/Email/)
55+
const passwordInput = screen.getByLabelText(/Hasło/)
56+
const submitButton = screen.getByRole('button', { name: /Zaloguj się/ })
57+
58+
fireEvent.change(emailInput, { target: { value: 'test@example.com' } })
59+
fireEvent.change(passwordInput, { target: { value: 'password123' } })
60+
fireEvent.click(submitButton)
61+
62+
// Form submission is handled by component, mock prevents actual API call
63+
expect(emailInput).toHaveValue('test@example.com')
64+
expect(passwordInput).toHaveValue('password123')
65+
})
66+
})

src/components/Register.test.tsx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { render, screen, fireEvent } from '@testing-library/react'
2+
import { describe, it, expect, vi, beforeEach } from 'vitest'
3+
import Register from './Register'
4+
5+
// Mock auth store
6+
const mockSignUp = vi.fn()
7+
vi.mock('../store/authStore', () => ({
8+
useAuthStore: vi.fn(() => ({
9+
signUp: mockSignUp,
10+
})),
11+
}))
12+
13+
describe('Register', () => {
14+
const mockOnSwitchToLogin = vi.fn()
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks()
18+
})
19+
20+
it('renders registration form', () => {
21+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
22+
23+
expect(screen.getByText('IT Task Manager')).toBeInTheDocument()
24+
expect(screen.getByText('Utwórz nowe konto')).toBeInTheDocument()
25+
expect(screen.getByLabelText(/Imię i nazwisko/)).toBeInTheDocument()
26+
expect(screen.getByLabelText(/Email/)).toBeInTheDocument()
27+
expect(screen.getByLabelText(/^Hasło$/)).toBeInTheDocument()
28+
expect(screen.getByLabelText(/Potwierdź hasło/)).toBeInTheDocument()
29+
expect(screen.getByRole('button', { name: /Zarejestruj się/ })).toBeInTheDocument()
30+
})
31+
32+
it('calls onSwitchToLogin when login link is clicked', () => {
33+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
34+
35+
const loginButton = screen.getByRole('button', { name: /Zaloguj się/ })
36+
fireEvent.click(loginButton)
37+
38+
expect(mockOnSwitchToLogin).toHaveBeenCalledTimes(1)
39+
})
40+
41+
it('updates form inputs', () => {
42+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
43+
44+
const nameInput = screen.getByLabelText(/Imię i nazwisko/)
45+
const emailInput = screen.getByLabelText(/Email/)
46+
const passwordInput = screen.getByLabelText(/^Hasło$/)
47+
const confirmPasswordInput = screen.getByLabelText(/Potwierdź hasło/)
48+
49+
fireEvent.change(nameInput, { target: { value: 'Jan Kowalski' } })
50+
fireEvent.change(emailInput, { target: { value: 'test@example.com' } })
51+
fireEvent.change(passwordInput, { target: { value: 'password123' } })
52+
fireEvent.change(confirmPasswordInput, { target: { value: 'password123' } })
53+
54+
expect(nameInput).toHaveValue('Jan Kowalski')
55+
expect(emailInput).toHaveValue('test@example.com')
56+
expect(passwordInput).toHaveValue('password123')
57+
expect(confirmPasswordInput).toHaveValue('password123')
58+
})
59+
60+
it('validates password confirmation', () => {
61+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
62+
63+
const passwordInput = screen.getByLabelText(/^Hasło$/)
64+
const confirmPasswordInput = screen.getByLabelText(/Potwierdź hasło/)
65+
66+
fireEvent.change(passwordInput, { target: { value: 'password123' } })
67+
fireEvent.change(confirmPasswordInput, { target: { value: 'different' } })
68+
69+
expect(passwordInput).toHaveValue('password123')
70+
expect(confirmPasswordInput).toHaveValue('different')
71+
})
72+
73+
it('validates password length', () => {
74+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
75+
76+
const passwordInput = screen.getByLabelText(/^Hasło$/)
77+
78+
fireEvent.change(passwordInput, { target: { value: '123' } })
79+
80+
expect(passwordInput).toHaveValue('123')
81+
})
82+
83+
it('submits form when all fields are filled', () => {
84+
render(<Register onSwitchToLogin={mockOnSwitchToLogin} />)
85+
86+
const nameInput = screen.getByLabelText(/Imię i nazwisko/)
87+
const emailInput = screen.getByLabelText(/Email/)
88+
const passwordInput = screen.getByLabelText(/^Hasło$/)
89+
const confirmPasswordInput = screen.getByLabelText(/Potwierdź hasło/)
90+
const termsCheckbox = screen.getByLabelText(/Akceptuję/)
91+
const submitButton = screen.getByRole('button', { name: /Zarejestruj się/ })
92+
93+
fireEvent.change(nameInput, { target: { value: 'Jan Kowalski' } })
94+
fireEvent.change(emailInput, { target: { value: 'test@example.com' } })
95+
fireEvent.change(passwordInput, { target: { value: 'password123' } })
96+
fireEvent.change(confirmPasswordInput, { target: { value: 'password123' } })
97+
fireEvent.click(termsCheckbox)
98+
fireEvent.click(submitButton)
99+
100+
// Form submission is handled by component, mock prevents actual API call
101+
expect(nameInput).toHaveValue('Jan Kowalski')
102+
expect(emailInput).toHaveValue('test@example.com')
103+
})
104+
})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { render, screen } from '@testing-library/react'
2+
import { describe, it, expect } from 'vitest'
3+
import Contact from './Contact'
4+
5+
describe('Contact', () => {
6+
it('renders contact title', () => {
7+
render(<Contact />)
8+
9+
expect(screen.getByText('Kontakt')).toBeInTheDocument()
10+
})
11+
12+
it('renders contact content', () => {
13+
render(<Contact />)
14+
15+
expect(screen.getByText('Skontaktuj się z nami')).toBeInTheDocument()
16+
})
17+
18+
it('renders contact information', () => {
19+
render(<Contact />)
20+
21+
expect(screen.getByText('Email')).toBeInTheDocument()
22+
expect(screen.getByText('biuro@maxsoft.pl')).toBeInTheDocument()
23+
expect(screen.getByText('Telefon')).toBeInTheDocument()
24+
expect(screen.getByText('+48791821908')).toBeInTheDocument()
25+
expect(screen.getByText('Godziny pracy')).toBeInTheDocument()
26+
})
27+
28+
it('renders warning message', () => {
29+
render(<Contact />)
30+
31+
expect(screen.getByText(/W przypadku problemów technicznych/)).toBeInTheDocument()
32+
})
33+
})

src/components/help/Help.test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { render, screen } from '@testing-library/react'
2+
import { describe, it, expect } from 'vitest'
3+
import Help from './Help'
4+
5+
describe('Help', () => {
6+
it('renders help title', () => {
7+
render(<Help />)
8+
9+
expect(screen.getByText('Pomoc')).toBeInTheDocument()
10+
})
11+
12+
it('renders help content', () => {
13+
render(<Help />)
14+
15+
expect(screen.getByText('Jak korzystać z aplikacji')).toBeInTheDocument()
16+
expect(screen.getByText('Zarządzanie zadaniami')).toBeInTheDocument()
17+
expect(screen.getByText('Zarządzanie użytkownikami (tylko administratorzy)')).toBeInTheDocument()
18+
})
19+
20+
it('renders help sections', () => {
21+
render(<Help />)
22+
23+
expect(screen.getByText(/Przejdź do sekcji "Zadania"/)).toBeInTheDocument()
24+
expect(screen.getByText(/Użyj przycisku "Dodaj zadanie"/)).toBeInTheDocument()
25+
expect(screen.getByText(/Dashboard/)).toBeInTheDocument()
26+
})
27+
})
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { render, screen } from '@testing-library/react'
2+
import { describe, it, expect, vi } from 'vitest'
3+
import Footer from './Footer'
4+
5+
// Mock useNavigation hook
6+
const mockSetCurrentView = vi.fn()
7+
vi.mock('../../context/NavigationContext', () => ({
8+
useNavigation: () => ({
9+
setCurrentView: mockSetCurrentView,
10+
}),
11+
}))
12+
13+
describe('Footer', () => {
14+
it('renders copyright text', () => {
15+
render(<Footer />)
16+
expect(screen.getByText(/© \d{4} Menadżer Zadań/)).toBeInTheDocument()
17+
})
18+
19+
it('renders Pomoc button', () => {
20+
render(<Footer />)
21+
const helpButton = screen.getByRole('button', { name: /Pomoc/i })
22+
expect(helpButton).toBeInTheDocument()
23+
})
24+
25+
it('renders Kontakt button', () => {
26+
render(<Footer />)
27+
const contactButton = screen.getByRole('button', { name: /Kontakt/i })
28+
expect(contactButton).toBeInTheDocument()
29+
})
30+
31+
it('calls setCurrentView when Pomoc button is clicked', () => {
32+
render(<Footer />)
33+
const helpButton = screen.getByRole('button', { name: /Pomoc/i })
34+
helpButton.click()
35+
expect(mockSetCurrentView).toHaveBeenCalledWith('help')
36+
})
37+
38+
it('calls setCurrentView when Kontakt button is clicked', () => {
39+
render(<Footer />)
40+
const contactButton = screen.getByRole('button', { name: /Kontakt/i })
41+
contactButton.click()
42+
expect(mockSetCurrentView).toHaveBeenCalledWith('contact')
43+
})
44+
})
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { render, screen, fireEvent } from '@testing-library/react'
2+
import { describe, it, expect, vi } from 'vitest'
3+
import Settings from './Settings'
4+
5+
// Mock child components
6+
vi.mock('./TaskTable', () => ({
7+
default: () => <div data-testid="task-table">TaskTable Component</div>,
8+
}))
9+
10+
vi.mock('./AddTask', () => ({
11+
default: ({ onSuccess }: { onSuccess: () => void }) => (
12+
<div data-testid="add-task">
13+
AddTask Component
14+
<button onClick={onSuccess} data-testid="add-task-success">Success</button>
15+
</div>
16+
),
17+
}))
18+
19+
describe('Settings', () => {
20+
it('renders with default active tab as list', () => {
21+
render(<Settings />)
22+
23+
expect(screen.getByText('Zadania')).toBeInTheDocument()
24+
expect(screen.getByText('Lista zadań')).toBeInTheDocument()
25+
expect(screen.getByText('Dodaj zadanie')).toBeInTheDocument()
26+
expect(screen.getByTestId('task-table')).toBeInTheDocument()
27+
})
28+
29+
it('switches to add task tab when clicked', () => {
30+
render(<Settings />)
31+
32+
const addTaskTab = screen.getByRole('button', { name: /Dodaj zadanie/ })
33+
fireEvent.click(addTaskTab)
34+
35+
expect(screen.getByTestId('add-task')).toBeInTheDocument()
36+
expect(screen.queryByTestId('task-table')).not.toBeInTheDocument()
37+
})
38+
39+
it('switches back to list tab when success callback is called', () => {
40+
render(<Settings />)
41+
42+
// Switch to add task
43+
const addTaskTab = screen.getByRole('button', { name: /Dodaj zadanie/ })
44+
fireEvent.click(addTaskTab)
45+
46+
expect(screen.getByTestId('add-task')).toBeInTheDocument()
47+
48+
// Trigger success callback
49+
const successButton = screen.getByTestId('add-task-success')
50+
fireEvent.click(successButton)
51+
52+
expect(screen.getByTestId('task-table')).toBeInTheDocument()
53+
expect(screen.queryByTestId('add-task')).not.toBeInTheDocument()
54+
})
55+
56+
it('applies active styles to current tab', () => {
57+
render(<Settings />)
58+
59+
const listTab = screen.getByRole('button', { name: /Lista zadań/ })
60+
const addTab = screen.getByRole('button', { name: /Dodaj zadanie/ })
61+
62+
// List tab should be active by default
63+
expect(listTab).toHaveClass('border-indigo-500', 'text-indigo-600')
64+
expect(addTab).toHaveClass('border-transparent', 'text-gray-500')
65+
66+
// Switch to add tab
67+
fireEvent.click(addTab)
68+
69+
expect(addTab).toHaveClass('border-indigo-500', 'text-indigo-600')
70+
expect(listTab).toHaveClass('border-transparent', 'text-gray-500')
71+
})
72+
})

0 commit comments

Comments
 (0)