Skip to content

Commit

Permalink
feat!: add switch atomic component (#13)
Browse files Browse the repository at this point in the history
- Added Switch.tsx and Switch.types.d.ts.
 - Wrapped MuiSwitch in new Switch component
- Added test suite for switch, Switch.test.tsx

Co-authored-by: ishaan bhalla <[email protected]>
  • Loading branch information
ishaan000 and ishaan bhalla authored Oct 21, 2024
1 parent 51f535f commit 4202138
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/components/atoms/Switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use client';

import { Switch as MuiSwitch } from '@mui/material';
import React from 'react';
import { SwitchProps } from '@components/atoms/Switch';

const Switch: React.FC<SwitchProps> = ({
checked = false,
onChange,
color = 'primary',
size = 'medium',
disabled = false,
sx = {},
ariaLabel = '',
tabIndex = 0,
inputProps = {},
...props
}) => {
return (
<MuiSwitch
checked={checked}
color={color}
disabled={disabled}
inputProps={{ 'aria-label': ariaLabel, ...inputProps }}
onChange={onChange}
size={size}
sx={sx}
tabIndex={tabIndex}
{...props}
/>
);
};

export default Switch;
28 changes: 28 additions & 0 deletions src/types/Switch.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
declare module '@components/atoms/Switch' {
import { SxProps, Theme } from '@mui/system';
import { FC } from 'react';
import { SwitchProps as MuiSwitchProps } from '@mui/material/Switch';

export interface SwitchProps extends Omit<MuiSwitchProps, 'color'> {
checked?: boolean;
color?:
| 'primary'
| 'secondary'
| 'error'
| 'info'
| 'success'
| 'warning'
| 'default';
disabled?: boolean;
onChange?: MuiSwitchProps['onChange'];
size?: 'small' | 'medium';
sx?: SxProps<Theme>;
value?: unknown;
ariaLabel?: string;
tabIndex?: number;
inputProps?: MuiSwitchProps['inputProps'];
}

const Switch: FC<SwitchProps>;
export default Switch;
}
114 changes: 114 additions & 0 deletions tests/components/atoms/Switch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { Switch as MuiSwitch } from '@mui/material';
import React from 'react';
import Switch from '../../../src/components/atoms/Switch';

jest.mock('@mui/material', () => ({
Switch: jest
.fn()
.mockImplementation(({ inputProps, ...props }) => (
<input type="checkbox" {...inputProps} {...props} />
)),
}));

describe('Switch component', () => {
const defaultProps = {
checked: false,
onChange: jest.fn(),
color: 'primary' as const,
size: 'medium' as const,
disabled: false,
ariaLabel: 'Test Switch',
};

beforeEach(() => {
(MuiSwitch as jest.Mock).mockClear();
});

afterEach(() => {
jest.clearAllMocks();
});

it('should render the switch', () => {
render(<Switch {...defaultProps} />);
expect(screen.getByRole('checkbox')).toBeInTheDocument();
});

it('should have the correct checked state', () => {
render(<Switch {...defaultProps} checked={true} />);
expect(screen.getByRole('checkbox')).toBeChecked();
});

it('should call onChange when toggled', () => {
render(<Switch {...defaultProps} />);
fireEvent.click(screen.getByRole('checkbox'));
expect(defaultProps.onChange).toHaveBeenCalledTimes(1);
});

it('should pass the correct color prop to MuiSwitch', () => {
render(<Switch {...defaultProps} color="secondary" />);
expect(MuiSwitch).toHaveBeenCalledWith(
expect.objectContaining({ color: 'secondary' }),
expect.anything()
);
});

it('should pass the correct size prop to MuiSwitch', () => {
render(<Switch {...defaultProps} size="small" />);
expect(MuiSwitch).toHaveBeenCalledWith(
expect.objectContaining({ size: 'small' }),
expect.anything()
);
});

it('should be disabled when the disabled prop is true', () => {
render(<Switch {...defaultProps} disabled={true} />);
expect(screen.getByRole('checkbox')).toBeDisabled();
});

it('should apply the correct aria-label', () => {
render(<Switch {...defaultProps} ariaLabel="Custom Aria Label" />);
expect(screen.getByRole('checkbox')).toHaveAttribute(
'aria-label',
'Custom Aria Label'
);
});

it('should set the correct tabIndex on the input', () => {
render(<Switch {...defaultProps} tabIndex={-1} />);
expect(screen.getByRole('checkbox')).toHaveAttribute('tabindex', '-1');
});

it('should apply sx prop to MuiSwitch', () => {
const sx = { margin: 2 };
render(<Switch {...defaultProps} sx={sx} />);
expect(MuiSwitch).toHaveBeenCalledWith(
expect.objectContaining({
sx: expect.objectContaining({
margin: 2,
}),
}),
expect.anything()
);
});

it('should pass additional inputProps to the input element', () => {
const inputProps = { 'data-testid': 'custom-switch' };
render(<Switch {...defaultProps} inputProps={inputProps} />);
expect(screen.getByTestId('custom-switch')).toBeInTheDocument();
});

it('should use default values when no props are provided', () => {
render(<Switch onChange={jest.fn()} />);
expect(MuiSwitch).toHaveBeenCalledWith(
expect.objectContaining({
checked: false,
color: 'primary',
size: 'medium',
disabled: false,
}),
expect.anything()
);
});
});

0 comments on commit 4202138

Please sign in to comment.