Skip to content
Open
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
12 changes: 10 additions & 2 deletions src/shared/ui/ProgressBar/ProgressBar.skeleton.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { Skeleton } from '@/shared/ui/Skeleton';
import { TextSkeleton } from '@/shared/ui/Text';

import { progressBarTestIds } from './constants';
import { ProgressBarProps } from './ProgressBar';
import styles from './ProgressBar.module.css';

export const ProgressBarSkeleton = ({ label, className, variant = 'small' }: ProgressBarProps) => {
return (
<div className={className}>
<div className={className} data-testid={progressBarTestIds.skeleton}>
<Skeleton className={(styles['progress-bar'], styles[`progress-bar-${variant}`])} />
{label && <TextSkeleton variant="body2-accent" width={180} className={styles.label} />}
{label && (
<TextSkeleton
variant="body2-accent"
width={180}
className={styles.label}
dataTestId={progressBarTestIds.textSkeleton}
/>
)}
</div>
);
};
125 changes: 125 additions & 0 deletions src/shared/ui/ProgressBar/ProgressBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { render, screen } from '@testing-library/react';

import { progressBarTestIds } from './constants';
import { ProgressBar } from './ProgressBar';
import { ProgressBarSkeleton } from './ProgressBar.skeleton';

describe('ProgressBar label', () => {
test('renders label when label prop is passed', () => {
render(<ProgressBar currentCount={1} totalCount={1} label="Label" />);

const label = screen.getByTestId(progressBarTestIds.label);

expect(label).toBeInTheDocument();
expect(label).toHaveTextContent('Label');
});

test('does not render label when label prop is not passed', () => {
render(<ProgressBar currentCount={1} totalCount={1} />);

expect(screen.queryByTestId(progressBarTestIds.label)).toBeNull();
});
});

describe('ProgressBar progress', () => {
test('renders progress element with correct value and max', () => {
render(<ProgressBar currentCount={1} totalCount={10} />);

const progress = screen.getByTestId(progressBarTestIds.progress);

expect(progress).toBeInTheDocument();
expect(progress).toHaveAttribute('value', '1');
expect(progress).toHaveAttribute('max', '10');
});

test('does not apply color class when color prop is not passed', () => {
render(<ProgressBar currentCount={1} totalCount={10} />);

const progress = screen.getByTestId(progressBarTestIds.progress);

expect(progress).toHaveClass('progress-bar-small');
expect(progress.className).not.toMatch(/progress-bar-(green|yellow|red)/);
});

test('applies green color class when color prop is "green"', () => {
render(<ProgressBar currentCount={1} totalCount={10} color="green" />);

const progress = screen.getByTestId(progressBarTestIds.progress);

expect(progress).toBeInTheDocument();
expect(progress).toHaveClass('progress-bar-green');
});
});

describe('ProgressBar variant', () => {
test('renders small variant when variant prop is not passed', () => {
render(<ProgressBar currentCount={1} totalCount={10} label="Label" />);

const progress = screen.getByTestId(progressBarTestIds.progress);
const label = screen.getByTestId(progressBarTestIds.label);

expect(progress).toBeInTheDocument();
expect(label).toBeInTheDocument();

expect(progress).toHaveClass('progress-bar-small');
expect(label).toHaveClass('label-small');
});

test('applies medium variant classes when variant prop is "medium"', () => {
render(<ProgressBar currentCount={1} totalCount={10} label="Label" variant="medium" />);

const progress = screen.getByTestId(progressBarTestIds.progress);

expect(progress).toBeInTheDocument();

expect(progress).toHaveClass('progress-bar-medium');
});

test('applies large variant classes when variant prop is "large"', () => {
render(<ProgressBar currentCount={1} totalCount={10} label="Label" variant="large" />);

const progress = screen.getByTestId(progressBarTestIds.progress);
const label = screen.getByTestId(progressBarTestIds.label);

expect(progress).toBeInTheDocument();
expect(label).toBeInTheDocument();

expect(progress).toHaveClass('progress-bar-large');
expect(label).toHaveClass('label-large');
});
});

describe('ProgressBar', () => {
test('applies custom classname to wrapper', () => {
render(<ProgressBar currentCount={1} totalCount={10} className="custom-class" />);

const wrapper = screen.getByTestId(progressBarTestIds.wrapper);

expect(wrapper).toBeInTheDocument();
expect(wrapper).toHaveClass('custom-class');
});
});

describe('ProgressBarSkeleton', () => {
test('renders progress bar skeleton', () => {
render(<ProgressBarSkeleton currentCount={1} totalCount={10} />);

const skeleton = screen.getByTestId(progressBarTestIds.skeleton);

expect(skeleton).toBeInTheDocument();
});

test('renders text skeleton when label prop is passed', () => {
render(<ProgressBarSkeleton currentCount={1} totalCount={10} label="Label" />);

const textSkeleton = screen.getByTestId(progressBarTestIds.textSkeleton);

expect(textSkeleton).toBeInTheDocument();
});

test('does not render text skeleton when label prop is not passed', () => {
render(<ProgressBarSkeleton currentCount={1} totalCount={10} />);

expect(screen.queryByTestId(progressBarTestIds.textSkeleton)).toBeNull();
});
});
14 changes: 12 additions & 2 deletions src/shared/ui/ProgressBar/ProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import classNames from 'classnames';

import { Text } from '@/shared/ui/Text';

import { progressBarTestIds } from './constants';
import styles from './ProgressBar.module.css';

export type ProgressBarVariant = 'small' | 'large' | 'medium';
Expand All @@ -25,17 +26,26 @@ export const ProgressBar = ({
color,
}: ProgressBarProps) => {
return (
<div className={classNames(styles['progress-bar'], className)}>
<div
className={classNames(styles['progress-bar'], className)}
data-testid={progressBarTestIds.wrapper}
>
<progress
className={classNames(
styles[`progress-bar-${variant}`],
color && styles[`progress-bar-${color}`],
)}
value={currentCount}
max={totalCount}
data-testid={progressBarTestIds.progress}
/>
{label && (
<Text variant="body2-accent" color="black-500" className={styles[`label-${variant}`]}>
<Text
variant="body2-accent"
color="black-500"
className={styles[`label-${variant}`]}
dataTestId={progressBarTestIds.label}
>
{label}
</Text>
)}
Expand Down
7 changes: 7 additions & 0 deletions src/shared/ui/ProgressBar/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const progressBarTestIds = {
wrapper: 'ProgressBarWrapper',
progress: 'ProgressBarProgress',
label: 'ProgressBarLabel',
skeleton: 'ProgressBarSkeleton',
textSkeleton: 'ProgressBarTextSkeleton',
};