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.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Tests for AddMemberDialog Component
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { AddMemberDialog } from '@/components/admin/organizations/AddMemberDialog';
|
||||
|
||||
// Mock hooks
|
||||
const mockAddMember = jest.fn();
|
||||
jest.mock('@/lib/api/hooks/useAdmin', () => ({
|
||||
useAddOrganizationMember: () => ({
|
||||
mutateAsync: mockAddMember,
|
||||
}),
|
||||
useAdminUsers: () => ({
|
||||
data: {
|
||||
data: [
|
||||
{ id: 'user-1', email: 'user1@test.com', first_name: 'User', last_name: 'One' },
|
||||
{ id: 'user-2', email: 'user2@test.com', first_name: 'User', last_name: 'Two' },
|
||||
],
|
||||
},
|
||||
isLoading: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock toast
|
||||
jest.mock('sonner', () => ({
|
||||
toast: {
|
||||
success: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('AddMemberDialog', () => {
|
||||
it('exports AddMemberDialog component', () => {
|
||||
expect(AddMemberDialog).toBeDefined();
|
||||
expect(typeof AddMemberDialog).toBe('function');
|
||||
});
|
||||
|
||||
it('has correct component name', () => {
|
||||
expect(AddMemberDialog.name).toBe('AddMemberDialog');
|
||||
});
|
||||
|
||||
describe('Component Implementation', () => {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const componentPath = path.join(
|
||||
__dirname,
|
||||
'../../../../src/components/admin/organizations/AddMemberDialog.tsx'
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, 'utf8');
|
||||
|
||||
it('component file contains expected functionality markers', () => {
|
||||
expect(source).toContain('AddMemberDialog');
|
||||
expect(source).toContain('useAddOrganizationMember');
|
||||
expect(source).toContain('useAdminUsers');
|
||||
expect(source).toContain('useForm');
|
||||
expect(source).toContain('zodResolver');
|
||||
expect(source).toContain('Dialog');
|
||||
expect(source).toContain('Select');
|
||||
});
|
||||
|
||||
it('component has user email select field', () => {
|
||||
expect(source).toContain('userEmail');
|
||||
expect(source).toContain('User Email');
|
||||
expect(source).toContain('Select a user');
|
||||
});
|
||||
|
||||
it('component has role select field', () => {
|
||||
expect(source).toContain('role');
|
||||
expect(source).toContain('Role');
|
||||
expect(source).toContain('member');
|
||||
expect(source).toContain('admin');
|
||||
expect(source).toContain('owner');
|
||||
expect(source).toContain('guest');
|
||||
});
|
||||
|
||||
it('component has form validation schema', () => {
|
||||
expect(source).toContain('addMemberSchema');
|
||||
expect(source).toContain('z.object');
|
||||
expect(source).toContain('email');
|
||||
expect(source).toContain('z.enum');
|
||||
});
|
||||
|
||||
it('component handles form submission', () => {
|
||||
expect(source).toContain('onSubmit');
|
||||
expect(source).toContain('mutateAsync');
|
||||
expect(source).toContain('user_id');
|
||||
expect(source).toContain('role');
|
||||
});
|
||||
|
||||
it('component handles loading state', () => {
|
||||
expect(source).toContain('isSubmitting');
|
||||
expect(source).toContain('setIsSubmitting');
|
||||
expect(source).toContain('disabled={isSubmitting}');
|
||||
});
|
||||
|
||||
it('component displays success toast on success', () => {
|
||||
expect(source).toContain('toast.success');
|
||||
expect(source).toContain('Member added successfully');
|
||||
});
|
||||
|
||||
it('component displays error toast on failure', () => {
|
||||
expect(source).toContain('toast.error');
|
||||
expect(source).toContain('Failed to add member');
|
||||
});
|
||||
|
||||
it('component has cancel button', () => {
|
||||
expect(source).toContain('Cancel');
|
||||
expect(source).toContain('onOpenChange(false)');
|
||||
});
|
||||
|
||||
it('component has submit button', () => {
|
||||
expect(source).toContain('Add Member');
|
||||
expect(source).toContain('Adding...');
|
||||
});
|
||||
|
||||
it('component uses DialogFooter for actions', () => {
|
||||
expect(source).toContain('DialogFooter');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Tests for MemberActionMenu Component
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MemberActionMenu } from '@/components/admin/organizations/MemberActionMenu';
|
||||
import type { OrganizationMember } from '@/lib/api/hooks/useAdmin';
|
||||
|
||||
// Mock hooks
|
||||
const mockRemoveMember = jest.fn();
|
||||
jest.mock('@/lib/api/hooks/useAdmin', () => ({
|
||||
useRemoveOrganizationMember: () => ({
|
||||
mutateAsync: mockRemoveMember,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock toast
|
||||
jest.mock('sonner', () => ({
|
||||
toast: {
|
||||
success: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('MemberActionMenu', () => {
|
||||
const mockMember: OrganizationMember = {
|
||||
user_id: 'user-1',
|
||||
email: 'john@test.com',
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
role: 'member',
|
||||
joined_at: '2025-01-01T00:00:00Z',
|
||||
};
|
||||
|
||||
const props = {
|
||||
member: mockMember,
|
||||
organizationId: 'org-1',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockRemoveMember.mockResolvedValue({});
|
||||
});
|
||||
|
||||
it('renders action menu button', () => {
|
||||
render(<MemberActionMenu {...props} />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /Actions for John Doe/i });
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens menu when button clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<MemberActionMenu {...props} />);
|
||||
|
||||
const menuButton = screen.getByRole('button', { name: /Actions for/i });
|
||||
await user.click(menuButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Remove Member')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows remove member option in menu', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<MemberActionMenu {...props} />);
|
||||
|
||||
const menuButton = screen.getByRole('button', { name: /Actions for/i });
|
||||
await user.click(menuButton);
|
||||
|
||||
await waitFor(() => {
|
||||
const removeOption = screen.getByText('Remove Member');
|
||||
expect(removeOption).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
it('opens confirmation dialog when remove clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<MemberActionMenu {...props} />);
|
||||
|
||||
const menuButton = screen.getByRole('button', { name: /Actions for/i });
|
||||
await user.click(menuButton);
|
||||
|
||||
const removeOption = await screen.findByText('Remove Member');
|
||||
await user.click(removeOption);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Are you sure you want to remove.*John Doe.*from this organization/)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
it('closes dialog when cancel clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<MemberActionMenu {...props} />);
|
||||
|
||||
// Open menu
|
||||
const menuButton = screen.getByRole('button', { name: /Actions for/i });
|
||||
await user.click(menuButton);
|
||||
|
||||
// Click remove
|
||||
const removeOption = await screen.findByText('Remove Member');
|
||||
await user.click(removeOption);
|
||||
|
||||
// Wait for dialog
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button', { name: 'Cancel' })).toBeVisible();
|
||||
});
|
||||
|
||||
// Click cancel
|
||||
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
|
||||
await user.click(cancelButton);
|
||||
|
||||
// Dialog should close
|
||||
await waitFor(() => {
|
||||
const confirmText = screen.queryByText(/Are you sure you want to remove/);
|
||||
expect(confirmText).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('uses email as fallback when name is missing', () => {
|
||||
const memberWithoutName = {
|
||||
...mockMember,
|
||||
first_name: '',
|
||||
last_name: null,
|
||||
};
|
||||
|
||||
render(<MemberActionMenu member={memberWithoutName} organizationId="org-1" />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /Actions for john@test.com/i });
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Tests for OrganizationMembersTable Component
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { OrganizationMembersTable } from '@/components/admin/organizations/OrganizationMembersTable';
|
||||
import type { OrganizationMember, PaginationMeta } from '@/lib/api/hooks/useAdmin';
|
||||
|
||||
// Mock child components
|
||||
jest.mock('@/components/admin/organizations/MemberActionMenu', () => ({
|
||||
MemberActionMenu: ({ member }: any) => (
|
||||
<div data-testid={`action-menu-${member.user_id}`}>Actions for {member.email}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
describe('OrganizationMembersTable', () => {
|
||||
const mockMembers: OrganizationMember[] = [
|
||||
{
|
||||
user_id: 'user-1',
|
||||
email: 'john@test.com',
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
role: 'owner',
|
||||
joined_at: '2025-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
user_id: 'user-2',
|
||||
email: 'jane@test.com',
|
||||
first_name: 'Jane',
|
||||
last_name: null,
|
||||
role: 'admin',
|
||||
joined_at: '2025-01-15T00:00:00Z',
|
||||
},
|
||||
{
|
||||
user_id: 'user-3',
|
||||
email: 'guest@test.com',
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
role: 'guest',
|
||||
joined_at: '2025-02-01T00:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
const mockPagination: PaginationMeta = {
|
||||
total: 3,
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
total_pages: 1,
|
||||
has_next: false,
|
||||
has_prev: false,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
members: mockMembers,
|
||||
organizationId: 'org-1',
|
||||
pagination: mockPagination,
|
||||
isLoading: false,
|
||||
onPageChange: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders table with column headers', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('Email')).toBeInTheDocument();
|
||||
expect(screen.getByText('Name')).toBeInTheDocument();
|
||||
expect(screen.getByText('Role')).toBeInTheDocument();
|
||||
expect(screen.getByText('Joined')).toBeInTheDocument();
|
||||
|
||||
const actionsHeaders = screen.getAllByText('Actions');
|
||||
expect(actionsHeaders.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('renders member rows with email', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('john@test.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('jane@test.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('guest@test.com')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders member full names', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
||||
expect(screen.getByText('Jane')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows "No name" for members without names', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('No name')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders role badges', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('Owner')).toBeInTheDocument();
|
||||
expect(screen.getByText('Admin')).toBeInTheDocument();
|
||||
expect(screen.getByText('Guest')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders formatted joined dates', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('Jan 1, 2025')).toBeInTheDocument();
|
||||
expect(screen.getByText('Jan 15, 2025')).toBeInTheDocument();
|
||||
expect(screen.getByText('Feb 1, 2025')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders action menu for each member', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('action-menu-user-1')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('action-menu-user-2')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('action-menu-user-3')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows loading skeleton when isLoading is true', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} isLoading={true} />);
|
||||
|
||||
const skeletons = screen.getAllByRole('row');
|
||||
expect(skeletons.length).toBeGreaterThan(1); // Header + skeleton rows
|
||||
});
|
||||
|
||||
it('shows empty state when no members', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} members={[]} />);
|
||||
|
||||
expect(screen.getByText('No members found.')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders pagination info', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText(/Showing 1 to 3 of 3 members/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onPageChange when page button clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onPageChange = jest.fn();
|
||||
const paginationWithNext = { ...mockPagination, has_next: true, total_pages: 2 };
|
||||
|
||||
render(
|
||||
<OrganizationMembersTable
|
||||
{...defaultProps}
|
||||
onPageChange={onPageChange}
|
||||
pagination={paginationWithNext}
|
||||
/>
|
||||
);
|
||||
|
||||
const nextButton = screen.getByRole('button', { name: 'Next' });
|
||||
await user.click(nextButton);
|
||||
|
||||
expect(onPageChange).toHaveBeenCalledWith(2);
|
||||
});
|
||||
|
||||
it('disables previous button on first page', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
const prevButton = screen.getByRole('button', { name: 'Previous' });
|
||||
expect(prevButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('disables next button on last page', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} />);
|
||||
|
||||
const nextButton = screen.getByRole('button', { name: 'Next' });
|
||||
expect(nextButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('does not show pagination when loading', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} isLoading={true} />);
|
||||
|
||||
expect(screen.queryByText(/Showing/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show pagination when no members', () => {
|
||||
render(<OrganizationMembersTable {...defaultProps} members={[]} />);
|
||||
|
||||
expect(screen.queryByText(/Showing/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user