Button.test.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * Tests for the Button component.
  3. */
  4. import { describe, it, expect, vi } from 'vitest';
  5. import { render, screen } from '@testing-library/react';
  6. import userEvent from '@testing-library/user-event';
  7. import { Button } from '../../components/Button';
  8. describe('Button', () => {
  9. it('renders children correctly', () => {
  10. render(<Button>Click me</Button>);
  11. expect(screen.getByRole('button')).toHaveTextContent('Click me');
  12. });
  13. it('handles click events', async () => {
  14. const user = userEvent.setup();
  15. const handleClick = vi.fn();
  16. render(<Button onClick={handleClick}>Click me</Button>);
  17. await user.click(screen.getByRole('button'));
  18. expect(handleClick).toHaveBeenCalledTimes(1);
  19. });
  20. it('can be disabled', async () => {
  21. const user = userEvent.setup();
  22. const handleClick = vi.fn();
  23. render(
  24. <Button onClick={handleClick} disabled>
  25. Click me
  26. </Button>
  27. );
  28. const button = screen.getByRole('button');
  29. expect(button).toBeDisabled();
  30. await user.click(button);
  31. expect(handleClick).not.toHaveBeenCalled();
  32. });
  33. // Variant tests
  34. describe('variants', () => {
  35. it('applies primary variant styles by default', () => {
  36. render(<Button>Primary</Button>);
  37. const button = screen.getByRole('button');
  38. expect(button.className).toContain('bg-bambu-green');
  39. });
  40. it('applies secondary variant styles', () => {
  41. render(<Button variant="secondary">Secondary</Button>);
  42. const button = screen.getByRole('button');
  43. expect(button.className).toContain('bg-bambu-dark-tertiary');
  44. });
  45. it('applies danger variant styles', () => {
  46. render(<Button variant="danger">Danger</Button>);
  47. const button = screen.getByRole('button');
  48. expect(button.className).toContain('bg-red-600');
  49. });
  50. it('applies ghost variant styles', () => {
  51. render(<Button variant="ghost">Ghost</Button>);
  52. const button = screen.getByRole('button');
  53. expect(button.className).toContain('bg-transparent');
  54. });
  55. });
  56. // Size tests
  57. describe('sizes', () => {
  58. it('applies medium size by default', () => {
  59. render(<Button>Medium</Button>);
  60. const button = screen.getByRole('button');
  61. expect(button.className).toContain('px-4');
  62. expect(button.className).toContain('py-2');
  63. });
  64. it('applies small size styles', () => {
  65. render(<Button size="sm">Small</Button>);
  66. const button = screen.getByRole('button');
  67. expect(button.className).toContain('px-3');
  68. expect(button.className).toContain('py-1.5');
  69. });
  70. it('applies large size styles', () => {
  71. render(<Button size="lg">Large</Button>);
  72. const button = screen.getByRole('button');
  73. expect(button.className).toContain('px-6');
  74. expect(button.className).toContain('py-3');
  75. });
  76. });
  77. // Accessibility tests
  78. describe('accessibility', () => {
  79. it('has correct button role', () => {
  80. render(<Button>Accessible</Button>);
  81. expect(screen.getByRole('button')).toBeInTheDocument();
  82. });
  83. it('supports custom aria-label', () => {
  84. render(<Button aria-label="Custom label">Icon</Button>);
  85. expect(screen.getByRole('button')).toHaveAttribute(
  86. 'aria-label',
  87. 'Custom label'
  88. );
  89. });
  90. it('supports type attribute', () => {
  91. render(<Button type="submit">Submit</Button>);
  92. expect(screen.getByRole('button')).toHaveAttribute('type', 'submit');
  93. });
  94. });
  95. // Custom className test
  96. it('merges custom className with default styles', () => {
  97. render(<Button className="custom-class">Custom</Button>);
  98. const button = screen.getByRole('button');
  99. expect(button.className).toContain('custom-class');
  100. expect(button.className).toContain('bg-bambu-green'); // Still has default styles
  101. });
  102. // Disabled styles test
  103. it('applies disabled styles when disabled', () => {
  104. render(<Button disabled>Disabled</Button>);
  105. const button = screen.getByRole('button');
  106. expect(button.className).toContain('disabled:opacity-50');
  107. expect(button.className).toContain('disabled:cursor-not-allowed');
  108. });
  109. });