Files
fast-next-template/frontend/tests/components/admin/organizations/OrganizationMembersContent.test.tsx
Felipe Cardoso 4420756741 Add organization members management components and tests
- Implemented `OrganizationMembersContent`, `OrganizationMembersTable`, and `AddMemberDialog` components for organization members management.
- Added unit tests for `OrganizationMembersContent` and `OrganizationMembersTable`, covering rendering, state handling, and edge cases.
- Enhanced `useOrganizationMembers` and `useGetOrganization` hooks to support members list and pagination data integration.
- Updated E2E tests to include organization members page interactions and improved reliability.
2025-11-06 21:57:57 +01:00

175 lines
5.1 KiB
TypeScript

/**
* Tests for OrganizationMembersContent Component
*/
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { OrganizationMembersContent } from '@/components/admin/organizations/OrganizationMembersContent';
// Mock Next.js navigation
jest.mock('next/navigation', () => ({
useSearchParams: jest.fn(() => new URLSearchParams()),
useRouter: jest.fn(() => ({
push: jest.fn(),
replace: jest.fn(),
})),
}));
// Mock AuthContext
jest.mock('@/lib/auth/AuthContext', () => ({
useAuth: jest.fn(() => ({
user: { id: '1', email: 'admin@test.com', is_superuser: true },
})),
}));
// Mock hooks
jest.mock('@/lib/api/hooks/useAdmin', () => ({
useOrganizationMembers: jest.fn(),
useGetOrganization: jest.fn(),
}));
// Mock child components
jest.mock('@/components/admin/organizations/OrganizationMembersTable', () => ({
OrganizationMembersTable: ({ members, isLoading, onPageChange }: any) => (
<div data-testid="organization-members-table">
{isLoading ? 'Loading...' : `${members.length} members`}
<button onClick={() => onPageChange(2)}>Page 2</button>
</div>
),
}));
jest.mock('@/components/admin/organizations/AddMemberDialog', () => ({
AddMemberDialog: ({ open, onOpenChange }: any) => (
<div data-testid="add-member-dialog">
{open && <button onClick={() => onOpenChange(false)}>Close Dialog</button>}
</div>
),
}));
// Import hooks after mocking
import { useOrganizationMembers, useGetOrganization } from '@/lib/api/hooks/useAdmin';
describe('OrganizationMembersContent', () => {
const mockOrganization = {
id: 'org-1',
name: 'Test Organization',
slug: 'test-organization',
description: 'A test organization',
is_active: true,
created_at: '2025-01-01',
updated_at: '2025-01-01',
member_count: 5,
};
const mockMembers = [
{
user_id: 'user-1',
email: 'member1@test.com',
first_name: 'Member',
last_name: 'One',
role: 'member' as const,
joined_at: '2025-01-01',
},
{
user_id: 'user-2',
email: 'member2@test.com',
first_name: 'Member',
last_name: 'Two',
role: 'admin' as const,
joined_at: '2025-01-02',
},
];
const mockPagination = {
total: 2,
page: 1,
page_size: 20,
total_pages: 1,
has_next: false,
has_prev: false,
};
beforeEach(() => {
jest.clearAllMocks();
(useGetOrganization as jest.Mock).mockReturnValue({
data: mockOrganization,
isLoading: false,
});
(useOrganizationMembers as jest.Mock).mockReturnValue({
data: { data: mockMembers, pagination: mockPagination },
isLoading: false,
});
});
it('renders organization name in header', () => {
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByText('Test Organization Members')).toBeInTheDocument();
});
it('renders description', () => {
render(<OrganizationMembersContent organizationId="org-1" />);
expect(
screen.getByText('Manage members and their roles within the organization')
).toBeInTheDocument();
});
it('renders add member button', () => {
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByRole('button', { name: /add member/i })).toBeInTheDocument();
});
it('opens add member dialog when button clicked', async () => {
const user = userEvent.setup();
render(<OrganizationMembersContent organizationId="org-1" />);
const addButton = screen.getByRole('button', { name: /add member/i });
await user.click(addButton);
await waitFor(() => {
expect(screen.getByTestId('add-member-dialog')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /close dialog/i })).toBeInTheDocument();
});
});
it('renders organization members table', () => {
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByTestId('organization-members-table')).toBeInTheDocument();
});
it('passes members data to table', () => {
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByText('2 members')).toBeInTheDocument();
});
it('shows loading state', () => {
(useOrganizationMembers as jest.Mock).mockReturnValue({
data: undefined,
isLoading: true,
});
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
it('shows "Organization Members" when organization is loading', () => {
(useGetOrganization as jest.Mock).mockReturnValue({
data: undefined,
isLoading: true,
});
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByText('Organization Members')).toBeInTheDocument();
});
it('handles empty members list', () => {
(useOrganizationMembers as jest.Mock).mockReturnValue({
data: { data: [], pagination: { ...mockPagination, total: 0 } },
isLoading: false,
});
render(<OrganizationMembersContent organizationId="org-1" />);
expect(screen.getByText('0 members')).toBeInTheDocument();
});
});