Skip to content

Commit

Permalink
Add more Unit Tests for the Main Pages
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtan2000 committed Oct 16, 2024
1 parent 8ed8bf0 commit 9bd0b88
Show file tree
Hide file tree
Showing 10 changed files with 1,506 additions and 18 deletions.
941 changes: 941 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@jest/globals": "^29.7.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@vitejs/plugin-react": "^4.3.2",
"eslint": "8.43.0",
"eslint-config-next": "13.4.6",
Expand Down
58 changes: 58 additions & 0 deletions test/(main)/classes/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import { render, screen, waitFor, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import Page from '../../../app/(main)/classes/page';
import { useRouter } from 'next/navigation';
import { UserService } from '../../../service/UserService';
import { describe, beforeEach, afterEach, it, vi, expect, Mock } from 'vitest';

vi.mock('next/navigation', () => ({
useRouter: vi.fn(),
}));

vi.mock('@/service/UserService', () => ({
UserService: {
getClasses: vi.fn().mockResolvedValue([]),
getTutorProfile: vi.fn().mockResolvedValue(null),
addClass: vi.fn().mockResolvedValue({ success: true }),
updateClass: vi.fn().mockResolvedValue({ success: true }),
},
}));

describe('Page', () => {
beforeEach(() => {
(useRouter as Mock).mockReturnValue({ push: vi.fn() });
(UserService.getClasses as Mock).mockResolvedValue([]);
});
afterEach(() => {
vi.clearAllMocks();
});
it('should load the page from URL and pass if anything is rendered', async () => {
global.fetch = vi.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ data: 'mocked response' }),
})
) as Mock;
await act(async () => {
render(<Page />);
});
const response = await fetch('http://localhost:3000/classes');
await waitFor(() => expect(response.ok).toBe(true));
expect(screen.getByText('Manage Classes')).toBeInTheDocument();
});

it('should render the "Manage Classes" heading', async () => {
await act(async () => {
render(<Page />);
});
expect(screen.getByText('Manage Classes')).toBeInTheDocument();
});

it('should call UserService.getClasses on mount', async () => {
await act(async () => {
render(<Page />);
});
expect(UserService.getClasses).toHaveBeenCalled();
});
});
89 changes: 89 additions & 0 deletions test/(main)/dashboard/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* eslint-disable @next/next/no-img-element */
'use client';
import React from 'react';
import { render, screen, waitFor, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import Page from '../../../app/(main)/dashboard/page';
import { useRouter } from 'next/navigation';
import { describe, beforeEach, afterEach, it, vi, expect, Mock } from 'vitest';
import { StatisticService } from '@/service/StatisticService';
import { LayoutContext } from '../../../layout/context/layoutcontext';

// Mock the next/navigation module
vi.mock('next/navigation', () => ({
useRouter: vi.fn(),
}));

// Mock the StatisticService
vi.mock('@/service/StatisticService', () => ({
StatisticService: {
getTopicSkillStatistics: vi.fn().mockResolvedValue({
data: [
{ topicName: 'Topic 1', skillName: 'Skill 1', cntAttempt: 10, cntCorrectAnswer: 8 },
{ topicName: 'Topic 2', skillName: 'Skill 2', cntAttempt: 15, cntCorrectAnswer: 12 },
]
}),
},
}));

// Mock the Chart component
vi.mock('primereact/chart', () => ({
Chart: vi.fn(() => null),
}));

// Mock the AppMessages component
vi.mock('@/components/AppMessages', () => ({
__esModule: true,
default: vi.fn(() => null),
}));

describe('Dashboard Page', () => {
beforeEach(() => {
(useRouter as Mock).mockReturnValue({ push: vi.fn() });
});

afterEach(() => {
vi.clearAllMocks();
});

it('should load the dashboard and display the top 10 topics/skills for improvement', async () => {
const mockLayoutContext = {
layoutConfig: {
colorScheme: 'light',
ripple: false,
inputStyle: 'outlined',
menuMode: 'static',
theme: 'lara-light-indigo',
scale: 14
},
setLayoutConfig: vi.fn(),
layoutState: {
staticMenuDesktopInactive: false,
overlayMenuActive: false,
profileSidebarVisible: false,
configSidebarVisible: false,
staticMenuMobileActive: false,
menuHoverActive: false,
},
setLayoutState: vi.fn(),
onMenuToggle: vi.fn(),
showProfileSidebar: vi.fn(),
};

await act(async () => {
render(
<LayoutContext.Provider value={mockLayoutContext}>
<Page />
</LayoutContext.Provider>
);
});

await waitFor(() => {
expect(screen.getByText('Top 10 Topics/Skill for Improvement')).toBeInTheDocument();
});

// Add more specific assertions here if needed
expect(screen.getByText('1. Topic 1 - Skill 1')).toBeInTheDocument();
expect(screen.getByText('2. Topic 2 - Skill 2')).toBeInTheDocument();
});
});
144 changes: 144 additions & 0 deletions test/(main)/profile/edit/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import React from 'react';
import { render, screen, waitFor, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import Page from '../../../../app/(main)/profile/edit/page';
import { useRouter } from 'next/navigation';
import { describe, beforeEach, afterEach, it, vi, expect, Mock } from 'vitest';
import { UserService } from '@/service/UserService';

vi.mock('next/navigation', () => ({
useRouter: vi.fn(),
}));

vi.mock('@/service/UserService', () => ({
UserService: {
getTutorProfile: vi.fn().mockResolvedValue({
id: 1,
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
tuitionCentre: 'ABC Center',
educationLevel: 'Masters',
}),
updateTutorProfile: vi.fn().mockResolvedValue({ success: true }),
},
}));

describe('Edit Profile Page', () => {
beforeEach(() => {
(useRouter as Mock).mockReturnValue({ push: vi.fn() });
});

afterEach(() => {
vi.clearAllMocks();
});

it('should load the edit profile page and render profile information', async () => {
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByText('Profile')).toBeInTheDocument();
});
});

it('should load initial profile data', async () => {
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
expect(screen.getByDisplayValue('Doe')).toBeInTheDocument();
expect(screen.getByDisplayValue('ABC Center')).toBeInTheDocument();
expect(screen.getByDisplayValue('Masters')).toBeInTheDocument();
});

expect(UserService.getTutorProfile).toHaveBeenCalledTimes(1);
});

it('should submit form with valid data', async () => {
const user = userEvent.setup();
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
});

const firstNameInput = screen.getByPlaceholderText('First Name');
await user.clear(firstNameInput);
await user.type(firstNameInput, 'Jane');

const saveButton = screen.getByRole('button', { name: /save/i });
await user.click(saveButton);

await waitFor(() => {
expect(UserService.updateTutorProfile).toHaveBeenCalledWith(expect.objectContaining({
firstName: 'Jane',
lastName: 'Doe',
tuitionCentre: 'ABC Center',
educationLevel: 'Masters',
}));
});
});

it('should show validation errors for empty required fields', async () => {
const user = userEvent.setup();
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
});

const firstNameInput = screen.getByPlaceholderText('First Name');
await user.clear(firstNameInput);

const saveButton = screen.getByRole('button', { name: /save/i });
await user.click(saveButton);

await waitFor(() => {
expect(screen.getByText('First name is required')).toBeInTheDocument();
});
});

it('should disable submit button when form is pristine', async () => {
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
});

const saveButton = screen.getByRole('button', { name: /save/i });
expect(saveButton).toBeDisabled();
});

it('should show success message after successful submission', async () => {
const user = userEvent.setup();
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
});

const firstNameInput = screen.getByPlaceholderText('First Name');
await user.clear(firstNameInput);
await user.type(firstNameInput, 'Jane');

const saveButton = screen.getByRole('button', { name: /save/i });
await user.click(saveButton);

await waitFor(() => {
expect(screen.getByText('Profile updated successfully')).toBeInTheDocument();
});
});
});
82 changes: 82 additions & 0 deletions test/(main)/questions/searchlist/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react';
import { render, screen, waitFor, act, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import Page from '../../../../app/(main)/questions/searchlist/page';
import { useRouter } from 'next/navigation';
import { describe, it, vi, expect, Mock, beforeEach } from 'vitest';
import { QuestionsService } from '@/service/QuestionsService';
import { DataScroller } from 'primereact/datascroller';
import { TreeSelect } from 'primereact/treeselect';
import { Editor } from 'primereact/editor';
import { Button } from 'primereact/button';
import { Tag } from 'primereact/tag';
import { Toolbar } from 'primereact/toolbar';
import userEvent from '@testing-library/user-event';

vi.mock('next/navigation', () => ({
useRouter: vi.fn(),
}));

vi.mock('@/service/QuestionsService', () => ({
QuestionsService: {
getTopics: vi.fn().mockResolvedValue([
{ id: 1, name: 'Topic 1', skills: [{ id: 1, name: 'Skill 1' }] },
{ id: 2, name: 'Topic 2', skills: [{ id: 2, name: 'Skill 2' }] }
]),
retrieveMCQ: vi.fn().mockResolvedValue({
mcqs: [{
id: 1,
stem: 'Test Question',
topics: [{ id: 1, name: 'Topic 1' }],
skills: [{ id: 1, name: 'Skill 1' }],
status: 'Active',
createdOn: '2023-01-01',
createdBy: 'Test User'
}],
pageNumber: 1,
pageSize: 5,
totalPages: 1,
totalRecords: 1,
keywords: null
}),
},
}));

vi.mock('primereact/datascroller', () => ({
DataScroller: vi.fn().mockImplementation(({ children }) => children)
}));

vi.mock('primereact/treeselect', () => ({
TreeSelect: vi.fn().mockImplementation(() => null)
}));

vi.mock('primereact/editor', () => ({
Editor: vi.fn().mockImplementation(() => null)
}));

describe('Questions Search List Page', () => {
beforeEach(() => {
vi.clearAllMocks();
(useRouter as Mock).mockReturnValue({ push: vi.fn() });
});

it('should load the page and display questions', async () => {
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(screen.getByText('Questions (1 records)')).toBeInTheDocument();
});
});

it('should load topics and skills for TreeSelect', async () => {
await act(async () => {
render(<Page />);
});

await waitFor(() => {
expect(TreeSelect).toHaveBeenCalled();
});
});
});
Loading

0 comments on commit 9bd0b88

Please sign in to comment.