- Registration form: added 5 new role options to dropdown - Sidebar: new roles get proper nav access via ALL_ROLES/LEADER_ROLES - Dashboard: isLeader check expanded to include new leadership roles - Shared/Pages: role badge colors added for all new roles - Invite modal: expanded role dropdown
109 lines
4.9 KiB
TypeScript
109 lines
4.9 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { render, screen } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { TaskDrawer } from '../TaskDrawer';
|
|
import type { Task, User } from '../data';
|
|
|
|
// Mock Shared components to avoid testing their specific implementation here
|
|
vi.mock('../Shared', () => ({
|
|
Avatar: ({ userId }: any) => <div data-testid="avatar">{userId}</div>,
|
|
Tag: ({ label }: any) => <div>{label}</div>,
|
|
ProgressBar: () => <div>Progress</div>
|
|
}));
|
|
|
|
describe('TaskDrawer Component', () => {
|
|
const mockUser: User = { id: 'u1', name: 'Test User', email: 'test@example.com', role: 'emp', dept: 'dev', avatar: 'TU', color: '#000' };
|
|
const mockUsers = [mockUser, { id: 'u2', name: 'Other User', email: 'other@example.com', role: 'emp', dept: 'dev', avatar: 'OU', color: '#fff' }];
|
|
|
|
const mockTask: Task = {
|
|
id: 't1',
|
|
title: 'Test Task',
|
|
description: 'Test Description',
|
|
status: 'todo',
|
|
priority: 'medium',
|
|
assignee: 'u1',
|
|
reporter: 'u1',
|
|
dueDate: '2023-12-31',
|
|
tags: ['bug'],
|
|
subtasks: [],
|
|
comments: [],
|
|
activity: [],
|
|
dependencies: []
|
|
};
|
|
|
|
const mockOnUpdate = vi.fn();
|
|
const mockOnClose = vi.fn();
|
|
const mockOnAddDep = vi.fn();
|
|
const mockOnToggleDep = vi.fn();
|
|
const mockOnRemoveDep = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('renders task details correctly', () => {
|
|
render(<TaskDrawer task={mockTask} currentUser={mockUser} onClose={mockOnClose} onUpdate={mockOnUpdate} onAddDependency={mockOnAddDep} onToggleDependency={mockOnToggleDep} onRemoveDependency={mockOnRemoveDep} users={mockUsers} />);
|
|
|
|
// screen.debug();
|
|
|
|
expect(screen.getByText('Test Task')).toBeInTheDocument();
|
|
expect(screen.getByText('Test Description')).toBeInTheDocument();
|
|
// Check for mocked avatar with userId
|
|
const avatars = screen.getAllByTestId('avatar');
|
|
expect(avatars.length).toBeGreaterThan(0);
|
|
expect(avatars[0]).toHaveTextContent('u1');
|
|
// expect(screen.getByText(/Test User/i)).toBeInTheDocument(); // Assignee name might be tricky in Select/Div
|
|
expect(screen.getByText('bug')).toBeInTheDocument();
|
|
});
|
|
|
|
it('updates title/description calling onUpdate', async () => {
|
|
// Title isn't editable in the drawer based on code, only via modal or just display?
|
|
// Checking code: <h2 className="drawer-title">{task.title}</h2>. It's not an input.
|
|
// But status, priority, assignee are selects.
|
|
|
|
render(<TaskDrawer task={mockTask} currentUser={mockUser} onClose={mockOnClose} onUpdate={mockOnUpdate} onAddDependency={mockOnAddDep} onToggleDependency={mockOnToggleDep} onRemoveDependency={mockOnRemoveDep} users={mockUsers} />);
|
|
|
|
// Update status
|
|
const statusSelect = screen.getByRole('combobox', { name: /status/i });
|
|
await userEvent.selectOptions(statusSelect, 'done');
|
|
|
|
expect(mockOnUpdate).toHaveBeenCalledWith(expect.objectContaining({
|
|
id: 't1',
|
|
status: 'done'
|
|
}));
|
|
});
|
|
|
|
it('adds a subtask', async () => {
|
|
render(<TaskDrawer task={mockTask} currentUser={mockUser} onClose={mockOnClose} onUpdate={mockOnUpdate} onAddDependency={mockOnAddDep} onToggleDependency={mockOnToggleDep} onRemoveDependency={mockOnRemoveDep} users={mockUsers} />);
|
|
|
|
const input = screen.getByPlaceholderText(/add a subtask/i);
|
|
await userEvent.type(input, 'New Subtask{enter}');
|
|
|
|
expect(mockOnUpdate).toHaveBeenCalledWith(expect.objectContaining({
|
|
subtasks: expect.arrayContaining([expect.objectContaining({ title: 'New Subtask', done: false })])
|
|
}));
|
|
});
|
|
|
|
it('adds a comment', async () => {
|
|
render(<TaskDrawer task={mockTask} currentUser={mockUser} onClose={mockOnClose} onUpdate={mockOnUpdate} onAddDependency={mockOnAddDep} onToggleDependency={mockOnToggleDep} onRemoveDependency={mockOnRemoveDep} users={mockUsers} />);
|
|
|
|
const input = screen.getByPlaceholderText(/add a comment/i);
|
|
await userEvent.type(input, 'This is a comment{enter}');
|
|
|
|
expect(mockOnUpdate).toHaveBeenCalledWith(expect.objectContaining({
|
|
comments: expect.arrayContaining([expect.objectContaining({ text: 'This is a comment', userId: 'u1' })])
|
|
}));
|
|
});
|
|
|
|
it('adds a dependency', async () => {
|
|
render(<TaskDrawer task={mockTask} currentUser={mockUser} onClose={mockOnClose} onUpdate={mockOnUpdate} onAddDependency={mockOnAddDep} onToggleDependency={mockOnToggleDep} onRemoveDependency={mockOnRemoveDep} users={mockUsers} />);
|
|
|
|
const descInput = screen.getByPlaceholderText(/describe the dependency/i);
|
|
await userEvent.type(descInput, 'Blocked by API{enter}');
|
|
|
|
// Default select is "Anyone" (empty string).
|
|
expect(mockOnAddDep).toHaveBeenCalledWith('t1', { dependsOnUserId: '', description: 'Blocked by API' });
|
|
});
|
|
});
|