Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/components/Badge/Badge.test.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
/**
* Validate the Badge component: rendering children, the class applied for each variant (success,
* warning, danger, info, neutral, default), and the default variant.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render, screen } from '@testing-library/react';
import { Badge } from './Badge';

describe('Badge', () => {
// Render the given children inside the badge.
it('renders children', () => {
render(<Badge>hello</Badge>);
expect(screen.getByText('hello')).toBeInTheDocument();
});
// Apply the omni-badge--success class for the success variant.
it('applies success variant class', () => {
const { container } = render(<Badge variant="success">ok</Badge>);
expect(container.firstChild).toHaveClass('omni-badge--success');
});
// Apply the omni-badge--warning class for the warning variant.
it('applies warning variant class', () => {
const { container } = render(<Badge variant="warning">warn</Badge>);
expect(container.firstChild).toHaveClass('omni-badge--warning');
});
// Apply the omni-badge--danger class for the danger variant.
it('applies danger variant class', () => {
const { container } = render(<Badge variant="danger">fail</Badge>);
expect(container.firstChild).toHaveClass('omni-badge--danger');
});
// Apply the omni-badge--info class for the info variant.
it('applies info variant class', () => {
const { container } = render(<Badge variant="info">info</Badge>);
expect(container.firstChild).toHaveClass('omni-badge--info');
});
// Render without error for both the neutral and default variants.
it('neutral and default both render without error', () => {
const { container: a } = render(<Badge variant="neutral">n</Badge>);
const { container: b } = render(<Badge variant="default">d</Badge>);
expect(a.firstChild).toBeTruthy();
expect(b.firstChild).toBeTruthy();
});
// Apply the base omni-badge class when no variant is given.
it('defaults to neutral when no variant given', () => {
const { container } = render(<Badge>default</Badge>);
expect(container.firstChild).toHaveClass('omni-badge');
Expand Down
13 changes: 13 additions & 0 deletions src/components/Button/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
/**
* Validate the Button component: rendering children, click handling, the disabled and loading
* states, and the variant and size class names.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
// Render the given children inside the button.
it('renders children', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
// Call onClick exactly once when the button is clicked.
it('calls onClick when clicked', () => {
const fn = vi.fn();
render(<Button onClick={fn}>Click</Button>);
fireEvent.click(screen.getByText('Click'));
expect(fn).toHaveBeenCalledTimes(1);
});
// Disable the button when the disabled prop is true.
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Click</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
// Disable the button and show a spinner while loading.
it('is disabled and shows spinner when loading', () => {
const { container } = render(<Button loading>Save</Button>);
expect(screen.getByRole('button')).toBeDisabled();
expect(container.querySelector('.omni-spinner')).toBeInTheDocument();
});
// Never call onClick when the button is disabled.
it('does not call onClick when disabled', () => {
const fn = vi.fn();
render(<Button disabled onClick={fn}>Click</Button>);
fireEvent.click(screen.getByRole('button'));
expect(fn).not.toHaveBeenCalled();
});
// Apply the variant class, e.g. omni-btn--danger.
it('applies variant classes', () => {
const { container } = render(<Button variant="danger">x</Button>);
expect(container.firstChild).toHaveClass('omni-btn--danger');
});
// Apply the size class, e.g. omni-btn--lg.
it('applies size classes', () => {
const { container } = render(<Button size="lg">x</Button>);
expect(container.firstChild).toHaveClass('omni-btn--lg');
Expand Down
11 changes: 11 additions & 0 deletions src/components/Card/Card.test.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
/**
* Validate the Card component: rendering children and an optional title, omitting the header when
* there is nothing to show in it, and the elevated and clickable class/click-handler behavior.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render, screen, fireEvent } from '@testing-library/react';
import { Card } from './Card';

describe('Card', () => {
// Render the given children inside the card.
it('renders children', () => {
render(<Card>content</Card>);
expect(screen.getByText('content')).toBeInTheDocument();
});
// Render the title when one is provided.
it('renders title when provided', () => {
render(<Card title="My Card">body</Card>);
expect(screen.getByText('My Card')).toBeInTheDocument();
});
// Omit the header element when there is no title or actions to show.
it('does not render header when no title or actions', () => {
const { container } = render(<Card>body</Card>);
expect(container.querySelector('.omni-card__header')).toBeNull();
});
// Apply the omni-card--elevated class when elevated is set.
it('applies elevated class', () => {
const { container } = render(<Card elevated>body</Card>);
expect(container.firstChild).toHaveClass('omni-card--elevated');
});
// Apply the omni-card--clickable class and call onClick when the card is clicked.
it('applies clickable class and calls onClick', () => {
const fn = vi.fn();
const { container } = render(<Card onClick={fn}>body</Card>);
Expand Down
11 changes: 11 additions & 0 deletions src/components/Input/Input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
/**
* Validate the Input component: label and placeholder rendering, change handling, the error
* message and error class, and the disabled state.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render, screen, fireEvent } from '@testing-library/react';
import { Input } from './Input';

describe('Input', () => {
// Render the field's label text when one is provided.
it('renders label when provided', () => {
render(<Input label="Sample ID" value="" onChange={() => {}} />);
expect(screen.getByText('Sample ID')).toBeInTheDocument();
});
// Render the placeholder text on the input.
it('renders placeholder', () => {
render(<Input placeholder="Enter value" value="" onChange={() => {}} />);
expect(screen.getByPlaceholderText('Enter value')).toBeInTheDocument();
});
// Call onChange once when the input value changes.
it('calls onChange when typed', () => {
const fn = vi.fn();
render(<Input value="" onChange={fn} />);
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'abc' } });
expect(fn).toHaveBeenCalledTimes(1);
});
// Show the error message and apply the omni-input--error class.
it('shows error message and error class', () => {
const { container } = render(
<Input value="" onChange={() => {}} error="File not found" />
);
expect(screen.getByText('File not found')).toBeInTheDocument();
expect(container.querySelector('.omni-input--error')).toBeInTheDocument();
});
// Disable the input when the disabled prop is true.
it('is disabled when disabled prop is true', () => {
render(<Input value="" onChange={() => {}} disabled />);
expect(screen.getByRole('textbox')).toBeDisabled();
Expand Down
13 changes: 13 additions & 0 deletions src/components/ProgressBar/ProgressBar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
/**
* Validate the ProgressBar component: default rendering, clamping out-of-range values, the
* variant and size classes, and the percentage label's default, custom, and hidden states.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render } from '@testing-library/react';
import { ProgressBar } from './ProgressBar';

describe('ProgressBar', () => {
// Render the progress fill element with default props.
it('renders with default props', () => {
const { container } = render(<ProgressBar value={50} />);
expect(container.querySelector('.omni-progress-fill')).toBeInTheDocument();
});
// Clamp a value above 100 to a 100% fill width.
it('clamps value to 0–100', () => {
const { container } = render(<ProgressBar value={150} />);
const fill = container.querySelector('.omni-progress-fill') as HTMLElement;
expect(fill.style.width).toBe('100%');
});
// Apply the variant class, e.g. omni-progress-fill--success.
it('applies correct variant class', () => {
const { container } = render(<ProgressBar value={80} variant="success" />);
expect(container.querySelector('.omni-progress-fill--success')).toBeInTheDocument();
});
// Show the numeric percentage as the label by default.
it('shows percentage label by default', () => {
const { getByText } = render(<ProgressBar value={75} />);
expect(getByText('75%')).toBeInTheDocument();
});
// Show a custom label string when one is provided.
it('shows custom label when provided', () => {
const { getByText } = render(<ProgressBar value={75} label="98.7%" />);
expect(getByText('98.7%')).toBeInTheDocument();
});
// Omit the label element when showLabel is false.
it('hides label when showLabel is false', () => {
const { container } = render(<ProgressBar value={75} showLabel={false} />);
expect(container.querySelector('.omni-progress-label')).toBeNull();
});
// Apply the size class, e.g. omni-progress-track--lg.
it('applies size class', () => {
const { container } = render(<ProgressBar value={50} size="lg" />);
expect(container.querySelector('.omni-progress-track--lg')).toBeInTheDocument();
Expand Down
11 changes: 11 additions & 0 deletions src/components/Select/Select.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Validate the Select component: rendering its options and label, change handling, the disabled
* state, and the placeholder option.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render, screen, fireEvent } from '@testing-library/react';
import { Select } from './Select';

Expand All @@ -8,25 +14,30 @@ const options = [
];

describe('Select', () => {
// Render every option's label.
it('renders all options', () => {
render(<Select options={options} value="a" onChange={() => {}} />);
expect(screen.getByText('Option A')).toBeInTheDocument();
expect(screen.getByText('Option B')).toBeInTheDocument();
});
// Render the field label when one is provided.
it('renders label when provided', () => {
render(<Select options={options} value="a" onChange={() => {}} label="Category" />);
expect(screen.getByText('Category')).toBeInTheDocument();
});
// Call onChange with the newly selected value.
it('calls onChange with selected value', () => {
const fn = vi.fn();
render(<Select options={options} value="a" onChange={fn} />);
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'b' } });
expect(fn).toHaveBeenCalledWith('b');
});
// Disable the select when the disabled prop is true.
it('is disabled when disabled prop is true', () => {
render(<Select options={options} value="a" onChange={() => {}} disabled />);
expect(screen.getByRole('combobox')).toBeDisabled();
});
// Render the placeholder option when the value is empty.
it('renders placeholder option', () => {
render(
<Select options={options} value="" onChange={() => {}}
Expand Down
10 changes: 10 additions & 0 deletions src/components/Spinner/Spinner.test.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
/**
* Validate the Spinner component: the default and explicit size classes and the custom border
* color applied via inline style.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render } from '@testing-library/react';
import { Spinner } from './Spinner';

describe('Spinner', () => {
// Apply the medium size class by default.
it('renders with default size', () => {
const { container } = render(<Spinner />);
expect(container.querySelector('.omni-spinner--md')).toBeInTheDocument();
});
// Apply the small size class when size is sm.
it('applies sm size class', () => {
const { container } = render(<Spinner size="sm" />);
expect(container.querySelector('.omni-spinner--sm')).toBeInTheDocument();
});
// Apply the large size class when size is lg.
it('applies lg size class', () => {
const { container } = render(<Spinner size="lg" />);
expect(container.querySelector('.omni-spinner--lg')).toBeInTheDocument();
});
// Apply a custom border-top color via inline style.
it('applies custom color via style', () => {
const { container } = render(<Spinner color="#ff0000" />);
const el = container.querySelector('.omni-spinner') as HTMLElement;
Expand Down
13 changes: 13 additions & 0 deletions src/components/StatusDot/StatusDot.test.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
/**
* Validate the StatusDot component: rendering with and without a label, and the class applied for
* each status value.
*
* Developer: Manish Kumar <manish@omnibioai.org>
*/
import { render } from '@testing-library/react';
import { StatusDot } from './StatusDot';

describe('StatusDot', () => {
// Render the dot element without a label.
it('renders without label', () => {
const { container } = render(<StatusDot status="success" />);
expect(container.querySelector('.omni-status-dot')).toBeInTheDocument();
});
// Render the status label text when one is provided.
it('renders label when provided', () => {
const { getByText } = render(<StatusDot status="success" label="UP" />);
expect(getByText('UP')).toBeInTheDocument();
});
// Apply the up class for the success status.
it('applies up class for success', () => {
const { container } = render(<StatusDot status="success" />);
expect(container.querySelector('.omni-status-dot--up')).toBeInTheDocument();
});
// Apply the down class for the failed status.
it('applies down class for failed', () => {
const { container } = render(<StatusDot status="failed" />);
expect(container.querySelector('.omni-status-dot--down')).toBeInTheDocument();
});
// Apply the pulse class for the running status.
it('applies pulse class for running', () => {
const { container } = render(<StatusDot status="running" />);
expect(container.querySelector('.omni-status-dot--pulse')).toBeInTheDocument();
});
// Apply the warn class for the queued status.
it('applies warn class for queued', () => {
const { container } = render(<StatusDot status="queued" />);
expect(container.querySelector('.omni-status-dot--warn')).toBeInTheDocument();
});
// Apply the init class for the idle status.
it('applies init class for idle', () => {
const { container } = render(<StatusDot status="idle" />);
expect(container.querySelector('.omni-status-dot--init')).toBeInTheDocument();
Expand Down
Loading
Loading