Skip to content

Commit 1d460c2

Browse files
Merge branch 'main' into feat/repo-tracker
2 parents e4421f8 + 7ff0f1d commit 1d460c2

11 files changed

Lines changed: 1288 additions & 209 deletions

File tree

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,20 @@ $ git clone https://github.com/GitMetricsLab/github_tracker.git
5050
```bash
5151
$ cd github-tracker
5252
```
53-
5453
3. Run the frontend
5554
```bash
5655
$ npm i
5756
$ npm run dev
5857
```
5958

59+
This project utilizes [Vitest](https://vitest.dev/) and React Testing Library to ensure UI reliability.
60+
61+
To run the frontend test suite, use the following command:
62+
```bash
63+
npm run test:client
64+
```
65+
66+
6067
4. Run the backend
6168
```bash
6269
$ npm i

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"build": "vite build",
99
"lint": "eslint .",
1010
"test": "vitest",
11+
"test:client": "vitest",
1112
"test:backend": "jasmine spec/**/*.spec.cjs",
1213
"preview": "vite preview",
1314
"docker:dev": "docker compose --profile dev up --build",

src/App.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import ScrollProgressBar from "./components/ScrollProgressBar";
55
import ScrollNavigator from "./components/ScrollNavigator";
66
import { Toaster } from "react-hot-toast";
77
import Router from "./Routes/Router";
8+
import ThemeWrapper from "./context/ThemeContext";
9+
import ChatbotWidget from "./components/Chatbot/ChatbotWidget";
810

911
const FULLSCREEN_ROUTES = ["/signup", "/login"];
1012

@@ -25,6 +27,8 @@ function App() {
2527

2628
{!isFullscreen && <Footer />}
2729

30+
<ChatbotWidget />
31+
2832
<Toaster
2933
position="top-center"
3034
reverseOrder={false}
@@ -46,4 +50,4 @@ function App() {
4650
);
4751
}
4852

49-
export default App;
53+
export default App;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { render, screen, waitFor } from '@testing-library/react';
2+
import { vi } from 'vitest';
3+
import ActivityFeed from './ActivityFeed';
4+
5+
// 1. Capture the original global fetch to prevent side effects
6+
const originalFetch = global.fetch;
7+
8+
const mockEvents = [
9+
{
10+
id: '12345',
11+
type: 'PushEvent',
12+
created_at: new Date().toISOString(),
13+
repo: { name: 'GitMetricsLab/github_tracker' }
14+
}
15+
];
16+
17+
// Helper to generate a full Response-like object to satisfy TypeScript
18+
const createMockResponse = (data: any): Partial<Response> => ({
19+
ok: true,
20+
status: 200,
21+
statusText: 'OK',
22+
json: async () => data,
23+
});
24+
25+
describe('ActivityFeed Component', () => {
26+
beforeAll(() => {
27+
// Mock fetch before the suite runs
28+
global.fetch = vi.fn();
29+
});
30+
31+
afterEach(() => {
32+
// Clear mock history between individual tests
33+
vi.clearAllMocks();
34+
});
35+
36+
afterAll(() => {
37+
// 2. Restore original fetch after the suite finishes to prevent leaks
38+
global.fetch = originalFetch;
39+
});
40+
41+
it('displays the loading state initially', () => {
42+
vi.mocked(global.fetch).mockResolvedValueOnce(createMockResponse([]) as Response);
43+
44+
render(<ActivityFeed username="testuser" />);
45+
46+
expect(screen.getByText('Loading...')).toBeInTheDocument();
47+
});
48+
49+
it('renders activity events after successful fetch', async () => {
50+
vi.mocked(global.fetch).mockResolvedValueOnce(createMockResponse(mockEvents) as Response);
51+
52+
render(<ActivityFeed username="testuser" />);
53+
54+
await waitFor(() => {
55+
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
56+
});
57+
58+
expect(screen.getByText('🚀 Commit pushed')).toBeInTheDocument();
59+
expect(screen.getByText(/GitMetricsLab\/github_tracker/)).toBeInTheDocument();
60+
});
61+
62+
it('displays a fallback message when no activity is found', async () => {
63+
vi.mocked(global.fetch).mockResolvedValueOnce(createMockResponse([]) as Response);
64+
65+
render(<ActivityFeed username="testuser" />);
66+
67+
await waitFor(() => {
68+
expect(screen.getByText('No activity found')).toBeInTheDocument();
69+
});
70+
});
71+
});

0 commit comments

Comments
 (0)