Skip to content

Commit 0e8ebf5

Browse files
refactor(web): rewrite tests in React and revert core changes
1 parent d504503 commit 0e8ebf5

12 files changed

Lines changed: 148 additions & 285 deletions

File tree

apps/web/package-lock.json

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

apps/web/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
},
1818
"devDependencies": {
1919
"@eslint/js": "^10.0.1",
20-
"@sveltejs/vite-plugin-svelte": "^7.1.2",
2120
"@testing-library/jest-dom": "^6.9.1",
22-
"@testing-library/svelte": "^5.3.1",
21+
"@testing-library/react": "^16.3.2",
2322
"@types/node": "^24.12.3",
2423
"@types/react": "^19.2.14",
2524
"@types/react-dom": "^19.2.3",
@@ -29,7 +28,6 @@
2928
"eslint-plugin-react-refresh": "^0.5.2",
3029
"globals": "^17.6.0",
3130
"jsdom": "^29.1.1",
32-
"svelte": "^5.56.3",
3331
"typescript": "~6.0.2",
3432
"typescript-eslint": "^8.59.2",
3533
"vite": "^8.0.12",

apps/web/src/components/Navbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Link } from 'react-router-dom';
2-
import { useTheme } from '../lib/useTheme';
2+
import { useTheme } from '../lib/theme';
33
import './Navbar.css';
44

55
export default function Navbar() {

apps/web/src/lib/theme.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createContext, useEffect, useState, type ReactNode } from 'react';
1+
import { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
22

33
type Theme = 'light' | 'dark';
44

@@ -40,4 +40,8 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
4040
);
4141
}
4242

43-
export { ThemeContext };
43+
export function useTheme(): ThemeContextValue {
44+
const ctx = useContext(ThemeContext);
45+
if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
46+
return ctx;
47+
}

apps/web/src/lib/useTheme.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

apps/web/src/pages/CardPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export default function CardPage() {
2424

2525
useEffect(() => {
2626
if (!id) return;
27-
// eslint-disable-next-line react-hooks/set-state-in-effect
2827
setLoading(true);
2928
apiFetch<PublicCard>(`/api/u/card/${id}`)
3029
.then((data) => {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { render, screen, waitFor } from '@testing-library/react';
2+
import { describe, it, expect, vi, beforeEach } from 'vitest';
3+
import { MemoryRouter, Routes, Route } from 'react-router-dom';
4+
import ProfilePage from './ProfilePage';
5+
import { apiFetch } from '../lib/api';
6+
7+
vi.mock('../lib/api', () => ({
8+
apiFetch: vi.fn(),
9+
}));
10+
11+
describe('ProfilePage', () => {
12+
beforeEach(() => {
13+
vi.resetAllMocks();
14+
});
15+
16+
const renderWithRouter = (username: string) => {
17+
return render(
18+
<MemoryRouter initialEntries={[`/u/${username}`]}>
19+
<Routes>
20+
<Route path="/u/:username" element={<ProfilePage />} />
21+
</Routes>
22+
</MemoryRouter>
23+
);
24+
};
25+
26+
it('renders loading state initially', () => {
27+
(apiFetch as any).mockImplementation(() => new Promise(() => {}));
28+
const { container } = renderWithRouter('testuser');
29+
30+
expect(container.querySelector('.loading-card')).toBeInTheDocument();
31+
});
32+
33+
it('renders profile data successfully', async () => {
34+
const mockProfile = {
35+
id: '123',
36+
userId: '456',
37+
username: 'testuser',
38+
displayName: 'Test User',
39+
avatarUrl: 'https://example.com/avatar.jpg',
40+
bio: 'Test Bio',
41+
role: 'Developer',
42+
company: 'Test Corp',
43+
accentColor: '#123456',
44+
links: [
45+
{
46+
id: 'link1',
47+
profileId: '123',
48+
platform: 'github',
49+
username: 'testgithub',
50+
url: '',
51+
order: 0,
52+
}
53+
],
54+
createdAt: new Date().toISOString(),
55+
updatedAt: new Date().toISOString(),
56+
};
57+
58+
(apiFetch as any).mockResolvedValue(mockProfile);
59+
60+
renderWithRouter('testuser');
61+
62+
await waitFor(() => {
63+
expect(screen.getByText('Test User')).toBeInTheDocument();
64+
});
65+
66+
expect(screen.getByText('Developer @ Test Corp')).toBeInTheDocument();
67+
expect(screen.getByText('Test Bio')).toBeInTheDocument();
68+
expect(screen.getByText('@testgithub')).toBeInTheDocument();
69+
expect(screen.getByRole('img', { name: 'Test User' })).toHaveAttribute('src', 'https://example.com/avatar.jpg');
70+
});
71+
72+
it('renders 404 flow when user is not found', async () => {
73+
(apiFetch as any).mockRejectedValue(new Error('User not found'));
74+
75+
renderWithRouter('unknownuser');
76+
77+
await waitFor(() => {
78+
expect(screen.getByText('Profile not found')).toBeInTheDocument();
79+
});
80+
81+
expect(screen.getByText('This DevCard has vanished into the digital void.')).toBeInTheDocument();
82+
expect(screen.getByText('Return Home')).toBeInTheDocument();
83+
});
84+
});

apps/web/src/pages/ProfilePage.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ export default function ProfilePage() {
2323
const [copyStatus, setCopyStatus] = useState<'success' | 'error'>('success');
2424

2525
useEffect(() => {
26-
// eslint-disable-next-line react-hooks/set-state-in-effect
2726
setMounted(true);
2827
}, []);
2928

3029
useEffect(() => {
3130
if (!username) return;
32-
// eslint-disable-next-line react-hooks/set-state-in-effect
3331
setLoading(true);
3432
apiFetch<PublicProfile>(`/api/u/${username}?source=web`)
3533
.then((data) => {

apps/web/src/routes/u/[username]/$types.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

apps/web/src/routes/u/[username]/+page.svelte

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)