dhre-component-lib 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/components/Avatar/Avatar.test.tsx +5 -4
- package/src/components/Avatar/Avatar.tsx +8 -6
- package/src/components/Badge/Badge.module.scss +14 -0
- package/src/components/Badge/Badge.test.tsx +8 -4
- package/src/components/Badge/Badge.tsx +5 -5
- package/src/components/BreadCrumb/BreadCrumb.tsx +16 -7
- package/src/components/BreadCrumb/Breadcrumb.module.scss +20 -0
- package/src/components/Button/Button.module.scss +66 -0
- package/src/components/Button/Button.test.tsx +10 -6
- package/src/components/Button/Button.tsx +11 -4
- package/src/components/Checkbox/Checkbox.test.tsx +7 -3
- package/src/components/CircularProgress/CircularProgress.module.scss +19 -0
- package/src/components/CircularProgress/CircularProgress.tsx +2 -2
- package/src/components/Modal/{Modal.css → Modal.module.scss} +1 -1
- package/src/components/Modal/Modal.test.tsx +9 -5
- package/src/components/Modal/Modal.tsx +17 -6
- package/src/components/Notification/Notification.tsx +1 -1
- package/src/components/OtpInput/OtpInput.module.scss +49 -0
- package/src/components/OtpInput/OtpInput.test.tsx +53 -0
- package/src/components/OtpInput/OtpInput.tsx +137 -0
- package/src/components/OtpInput/index.ts +1 -0
- package/src/components/PdfView/PdfView.module.scss +69 -0
- package/src/components/PdfView/PdfView.test.tsx +20 -11
- package/src/components/PdfView/PdfView.tsx +20 -9
- package/src/components/Tag/Tag.css +12 -13
- package/src/components/Tag/Tag.test.tsx +7 -3
- package/src/components/Tag/Tag.tsx +8 -14
- package/src/components/Tooltip/Tooltip.module.scss +37 -0
- package/src/components/Tooltip/Tooltip.test.tsx +35 -40
- package/src/components/Tooltip/Tooltip.tsx +9 -5
- package/src/components/index.ts +1 -0
- package/src/theme/Typography/typography.scss +117 -0
- package/src/theme/colors/colors.scss +22 -0
- package/src/theme/colors.ts +3 -0
- package/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap +0 -9
- package/src/components/Badge/Badge.css +0 -15
- package/src/components/Badge/__snapshots__/Badge.test.tsx.snap +0 -9
- package/src/components/BreadCrumb/Breadcrumb.css +0 -21
- package/src/components/Button/Button.css +0 -92
- package/src/components/Button/__snapshots__/Button.test.tsx.snap +0 -9
- package/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +0 -17
- package/src/components/CircularProgress/CircularProgress.css +0 -19
- package/src/components/PdfView/PdfView.css +0 -70
- package/src/components/Tag/__snapshots__/Tag.test.tsx.snap +0 -9
- package/src/components/Tooltip/Tooltip.css +0 -38
- package/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap +0 -22
- /package/src/components/Notification/{Notification.css → Notification.module.scss} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dhre-component-lib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "jest",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@emotion/styled": "^11.13.0",
|
|
39
39
|
"@mui/icons-material": "^5.16.7",
|
|
40
40
|
"@mui/material": "^5.16.7",
|
|
41
|
+
"sass": "^1.77.8",
|
|
41
42
|
"tslib": "^2.6.3"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom';
|
|
4
4
|
import Avatar, { AvatarProps } from './Avatar';
|
|
5
5
|
|
|
@@ -44,9 +44,10 @@ describe('Avatar Component', () => {
|
|
|
44
44
|
expect(() => fireEvent.click(imgElement)).not.toThrow();
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it('
|
|
48
|
-
|
|
47
|
+
it('renders correctly without crashing', () => {
|
|
48
|
+
render(<Avatar {...defaultProps} />);
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
const imgElement = screen.getByAltText(defaultProps.alt);
|
|
51
|
+
expect(imgElement).toBeInTheDocument();
|
|
51
52
|
});
|
|
52
53
|
});
|
|
@@ -14,12 +14,14 @@ const Avatar: React.FC<AvatarProps> = ({
|
|
|
14
14
|
handleClick,
|
|
15
15
|
}) => {
|
|
16
16
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
<button onClick={handleClick}>
|
|
18
|
+
<img
|
|
19
|
+
src={src}
|
|
20
|
+
alt={alt}
|
|
21
|
+
|
|
22
|
+
className={imgClassName}
|
|
23
|
+
/>
|
|
24
|
+
</button>
|
|
23
25
|
);
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom';
|
|
4
4
|
import Badge, { BadgeProps } from './Badge';
|
|
5
5
|
|
|
@@ -55,9 +55,13 @@ describe('Badge Component', () => {
|
|
|
55
55
|
expect(badgeElement).toHaveTextContent('99');
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it('
|
|
59
|
-
const
|
|
58
|
+
it('renders correctly with different content', () => {
|
|
59
|
+
const newContent = 'Updated Badge';
|
|
60
|
+
render(<Badge {...defaultProps} content={newContent} />);
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
const badgeElement = screen.getByText(newContent);
|
|
63
|
+
|
|
64
|
+
expect(badgeElement).toBeInTheDocument();
|
|
65
|
+
expect(badgeElement).toHaveTextContent(newContent);
|
|
62
66
|
});
|
|
63
67
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import './Badge.
|
|
2
|
+
import styles from './Badge.module.scss';
|
|
3
3
|
|
|
4
4
|
export interface BadgeProps {
|
|
5
5
|
content: string | number;
|
|
6
|
-
badgeClassName
|
|
6
|
+
badgeClassName?: string;
|
|
7
7
|
handleClick?: () => void;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -13,12 +13,12 @@ const Badge: React.FC<BadgeProps> = ({
|
|
|
13
13
|
handleClick,
|
|
14
14
|
}) => {
|
|
15
15
|
return (
|
|
16
|
-
<
|
|
16
|
+
<button
|
|
17
17
|
onClick={handleClick}
|
|
18
|
-
className={badgeClassName}
|
|
18
|
+
className={`${styles.badge} ${badgeClassName}`}
|
|
19
19
|
>
|
|
20
20
|
{content}
|
|
21
|
-
</
|
|
21
|
+
</button>
|
|
22
22
|
);
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import './Breadcrumb.
|
|
2
|
+
import styles from './Breadcrumb.module.scss';
|
|
3
3
|
|
|
4
4
|
export interface BreadcrumbItem {
|
|
5
5
|
label: string;
|
|
@@ -11,7 +11,7 @@ export interface BreadcrumbProps {
|
|
|
11
11
|
breadcrumbClassName: string;
|
|
12
12
|
itemClassName?: string;
|
|
13
13
|
separator?: string;
|
|
14
|
-
separatorClassName?: string
|
|
14
|
+
separatorClassName?: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const Breadcrumb: React.FC<BreadcrumbProps> = ({
|
|
@@ -22,12 +22,21 @@ const Breadcrumb: React.FC<BreadcrumbProps> = ({
|
|
|
22
22
|
separatorClassName,
|
|
23
23
|
}) => {
|
|
24
24
|
return (
|
|
25
|
-
<nav className={breadcrumbClassName}>
|
|
25
|
+
<nav className={`${styles.breadcrumb} ${breadcrumbClassName}`}>
|
|
26
26
|
{items.map((item, index) => (
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
<React.Fragment key={index}>
|
|
28
|
+
<button
|
|
29
|
+
className={`${styles.breadcrumbItem} ${itemClassName}`}
|
|
30
|
+
onClick={item.handleClick}
|
|
31
|
+
>
|
|
32
|
+
{item.label}
|
|
33
|
+
</button>
|
|
34
|
+
{index < items.length - 1 && (
|
|
35
|
+
<span className={`${styles.separator} ${separatorClassName}`}>
|
|
36
|
+
{separator}
|
|
37
|
+
</span>
|
|
38
|
+
)}
|
|
39
|
+
</React.Fragment>
|
|
31
40
|
))}
|
|
32
41
|
</nav>
|
|
33
42
|
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.breadcrumb {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
font-size: 16px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.breadcrumbItem {
|
|
8
|
+
color: blue;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
margin-right: 8px;
|
|
11
|
+
|
|
12
|
+
&:hover {
|
|
13
|
+
text-decoration: underline;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.separator {
|
|
18
|
+
margin: 0 8px;
|
|
19
|
+
color: grey;
|
|
20
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* Base button styling */
|
|
2
|
+
.button {
|
|
3
|
+
padding: 8px 16px;
|
|
4
|
+
font-size: 14px;
|
|
5
|
+
border-radius: 4px;
|
|
6
|
+
border: none;
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
transition: background-color 0.3s ease;
|
|
9
|
+
|
|
10
|
+
&.text {
|
|
11
|
+
background-color: transparent;
|
|
12
|
+
color: inherit;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&.outlined {
|
|
16
|
+
background-color: transparent;
|
|
17
|
+
border: 2px solid currentColor;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.contained {
|
|
21
|
+
background-color: currentColor;
|
|
22
|
+
color: #fff;
|
|
23
|
+
|
|
24
|
+
&.primary:hover {
|
|
25
|
+
background-color: #1565c0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&.secondary:hover {
|
|
29
|
+
background-color: #7b1fa2;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&.success:hover {
|
|
33
|
+
background-color: #388e3c;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&.error:hover {
|
|
37
|
+
background-color: #d32f2f;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&.warning:hover {
|
|
41
|
+
background-color: #f57c00;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.info:hover {
|
|
45
|
+
background-color: #1976d2;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.primary {
|
|
50
|
+
color: #1976d2;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&.secondary {
|
|
54
|
+
color: #9c27b0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&.success {
|
|
58
|
+
color: #4caf50;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.error {
|
|
62
|
+
color: #f44336;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&.warning {
|
|
66
|
+
color:
|
|
@@ -48,15 +48,19 @@ describe('Button Component', () => {
|
|
|
48
48
|
expect(handleClick).toHaveBeenCalledTimes(1); // Ensure the mock function is called once
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
it('renders correctly without crashing', () => {
|
|
52
|
-
const { container } = renderButton();
|
|
53
|
-
|
|
54
|
-
expect(container.firstChild).toMatchSnapshot();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
51
|
it('does not call handleClick when the button is not clicked', () => {
|
|
58
52
|
renderButton();
|
|
59
53
|
|
|
60
54
|
expect(handleClick).not.toHaveBeenCalled();
|
|
61
55
|
});
|
|
56
|
+
|
|
57
|
+
it('renders correctly with a different label', () => {
|
|
58
|
+
const newLabel = 'Submit';
|
|
59
|
+
renderButton({ label: newLabel });
|
|
60
|
+
|
|
61
|
+
const buttonElement = screen.getByText(newLabel);
|
|
62
|
+
|
|
63
|
+
expect(buttonElement).toBeInTheDocument();
|
|
64
|
+
expect(buttonElement.tagName).toBe('BUTTON');
|
|
65
|
+
});
|
|
62
66
|
});
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import './Button.
|
|
2
|
+
import styles from './Button.module.scss';
|
|
3
3
|
|
|
4
4
|
export interface ButtonProps {
|
|
5
5
|
label: string;
|
|
6
|
-
|
|
6
|
+
variant: 'text' | 'outlined' | 'contained';
|
|
7
|
+
color: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info';
|
|
8
|
+
size: 'small' | 'medium' | 'large';
|
|
7
9
|
handleClick: () => void;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
const Button: React.FC<ButtonProps> = ({
|
|
11
13
|
label,
|
|
12
|
-
|
|
14
|
+
variant,
|
|
15
|
+
color,
|
|
16
|
+
size,
|
|
13
17
|
handleClick,
|
|
14
18
|
}) => {
|
|
15
19
|
return (
|
|
16
|
-
<button
|
|
20
|
+
<button
|
|
21
|
+
onClick={handleClick}
|
|
22
|
+
className={`${styles.button} ${styles[variant]} ${styles[color]} ${styles[size]}`}
|
|
23
|
+
>
|
|
17
24
|
{label}
|
|
18
25
|
</button>
|
|
19
26
|
);
|
|
@@ -81,9 +81,13 @@ describe('CustomCheckbox Component', () => {
|
|
|
81
81
|
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
it('renders correctly
|
|
85
|
-
const
|
|
84
|
+
it('renders correctly with different label', () => {
|
|
85
|
+
const newLabel = 'Agree to Privacy Policy';
|
|
86
|
+
render(<CustomCheckbox {...getDefaultProps()} label={newLabel} />);
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
const labelElement = screen.getByText(newLabel);
|
|
89
|
+
|
|
90
|
+
expect(labelElement).toBeInTheDocument();
|
|
91
|
+
expect(labelElement).toHaveTextContent(newLabel);
|
|
88
92
|
});
|
|
89
93
|
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.spinner {
|
|
2
|
+
border-style: solid;
|
|
3
|
+
border-radius: 50%;
|
|
4
|
+
border-color: transparent;
|
|
5
|
+
border-top-color: currentColor;
|
|
6
|
+
animation: spin 1s linear infinite;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.spinner.primary { color: #007bff; }
|
|
10
|
+
.spinner.secondary { color: #6c757d; }
|
|
11
|
+
.spinner.error { color: #dc3545; }
|
|
12
|
+
.spinner.success { color: #28a745; }
|
|
13
|
+
.spinner.info { color: #17a2b8; }
|
|
14
|
+
.spinner.warning { color: #ffc107; }
|
|
15
|
+
|
|
16
|
+
@keyframes spin {
|
|
17
|
+
0% { transform: rotate(0deg); }
|
|
18
|
+
100% { transform: rotate(360deg); }
|
|
19
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import './CircularProgress.
|
|
2
|
+
import styles from './CircularProgress.module.scss';
|
|
3
3
|
|
|
4
4
|
export interface CircularProgressProps {
|
|
5
5
|
value?: number;
|
|
@@ -23,7 +23,7 @@ const CircularProgress: React.FC<CircularProgressProps> = ({
|
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<div
|
|
26
|
-
className={
|
|
26
|
+
className={`${styles.spinner} ${styles[color]}`}
|
|
27
27
|
style={{
|
|
28
28
|
width: typeof size === 'number' ? `${size}px` : size,
|
|
29
29
|
height: typeof size === 'number' ? `${size}px` : size,
|
|
@@ -6,7 +6,11 @@ describe('Modal Component', () => {
|
|
|
6
6
|
const onCloseMock = jest.fn();
|
|
7
7
|
const modalContentText = 'This is the modal content';
|
|
8
8
|
|
|
9
|
-
const renderModal = (
|
|
9
|
+
const renderModal = (
|
|
10
|
+
isOpen: boolean,
|
|
11
|
+
modalOverlayClassname?: string,
|
|
12
|
+
modalContentClassname?: string
|
|
13
|
+
) => {
|
|
10
14
|
render(
|
|
11
15
|
<Modal
|
|
12
16
|
isOpen={isOpen}
|
|
@@ -35,7 +39,7 @@ describe('Modal Component', () => {
|
|
|
35
39
|
|
|
36
40
|
it('calls onClose when clicking on the overlay', () => {
|
|
37
41
|
renderModal(true);
|
|
38
|
-
const overlay = screen.getByText(modalContentText).closest('
|
|
42
|
+
const overlay = screen.getByText(modalContentText).closest('button');
|
|
39
43
|
fireEvent.click(overlay!);
|
|
40
44
|
expect(onCloseMock).toHaveBeenCalled();
|
|
41
45
|
});
|
|
@@ -50,15 +54,15 @@ describe('Modal Component', () => {
|
|
|
50
54
|
it('applies the provided modalOverlayClassname', () => {
|
|
51
55
|
const overlayClass = 'customOverlayClass';
|
|
52
56
|
renderModal(true, overlayClass);
|
|
53
|
-
const overlay = screen.getByText(modalContentText).closest('
|
|
57
|
+
const overlay = screen.getByText(modalContentText).closest('button');
|
|
54
58
|
expect(overlay).toHaveClass(overlayClass);
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
it('applies the provided modalContentClassname', () => {
|
|
58
62
|
const contentClass = 'customContentClass';
|
|
59
63
|
renderModal(true, undefined, contentClass);
|
|
60
|
-
const modalContent = screen.getByText(modalContentText)
|
|
61
|
-
expect(modalContent).toHaveClass(contentClass);
|
|
64
|
+
const modalContent = screen.getByText(modalContentText);
|
|
65
|
+
expect(modalContent.parentElement).toHaveClass(contentClass);
|
|
62
66
|
});
|
|
63
67
|
|
|
64
68
|
it('does not render modal when isOpen is false, even if modalOverlayClassname and modalContentClassname are provided', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
2
|
+
import styles from './Modal.module.scss';
|
|
3
3
|
|
|
4
4
|
interface ModalProps {
|
|
5
5
|
isOpen: boolean;
|
|
@@ -9,19 +9,30 @@ interface ModalProps {
|
|
|
9
9
|
modalContentClassname?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
const Modal: React.FC<ModalProps> = ({
|
|
12
|
+
const Modal: React.FC<ModalProps> = ({
|
|
13
|
+
isOpen,
|
|
14
|
+
onClose,
|
|
15
|
+
children,
|
|
16
|
+
modalOverlayClassname = '',
|
|
17
|
+
modalContentClassname = ''
|
|
18
|
+
}) => {
|
|
13
19
|
if (!isOpen) return null;
|
|
14
20
|
|
|
15
|
-
const handleOverlayClick = (event: React.MouseEvent<
|
|
21
|
+
const handleOverlayClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
16
22
|
if (event.target === event.currentTarget) {
|
|
17
23
|
onClose();
|
|
18
24
|
}
|
|
19
25
|
};
|
|
20
26
|
|
|
21
27
|
return (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
<button
|
|
29
|
+
className={`${styles.modalOverlay} ${modalOverlayClassname}`}
|
|
30
|
+
onClick={handleOverlayClick}
|
|
31
|
+
>
|
|
32
|
+
<div className={`${styles.modalContent} ${modalContentClassname}`}>
|
|
33
|
+
{children}
|
|
34
|
+
</div>
|
|
35
|
+
</button>
|
|
25
36
|
);
|
|
26
37
|
};
|
|
27
38
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
@import '../../theme/colors/colors.scss';
|
|
2
|
+
|
|
3
|
+
.otpMainContainer {
|
|
4
|
+
display: flex;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
margin: 10px;
|
|
8
|
+
width: 343px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.otpInputDiv {
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
gap: 12px;
|
|
14
|
+
display: flex
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.otpInput {
|
|
18
|
+
width: 76px;
|
|
19
|
+
height: 48px;
|
|
20
|
+
text-align: center;
|
|
21
|
+
font-size: 18px;
|
|
22
|
+
font-weight: 400;
|
|
23
|
+
border-radius: 8px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.resendContainer {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: row;
|
|
29
|
+
margin-top: 10px;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.errorText {
|
|
34
|
+
color: $border-brand-danger;
|
|
35
|
+
font-weight: 400;
|
|
36
|
+
font-size: 14px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.timerText {
|
|
40
|
+
color: $content-disabled;
|
|
41
|
+
font-weight: 400;
|
|
42
|
+
font-size: 14px;
|
|
43
|
+
}
|
|
44
|
+
.resendText {
|
|
45
|
+
color: $content-disabled;
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
font-size: 14px;
|
|
48
|
+
}
|
|
49
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent, screen } from '@testing-library/react';
|
|
3
|
+
import OTPInput from './OtpInput';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
|
+
|
|
6
|
+
describe('OTPInput Component', () => {
|
|
7
|
+
it('renders the correct number of input fields based on the length prop', () => {
|
|
8
|
+
render(
|
|
9
|
+
<OTPInput
|
|
10
|
+
length={4}
|
|
11
|
+
onChange={() => {}}
|
|
12
|
+
onResend={() => {}}
|
|
13
|
+
resendText="Resend OTP"
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
const inputs = screen.getAllByRole('textbox');
|
|
17
|
+
expect(inputs).toHaveLength(4);
|
|
18
|
+
});
|
|
19
|
+
it('calls onChange prop when input changes', () => {
|
|
20
|
+
const handleChange = jest.fn();
|
|
21
|
+
render(<OTPInput length={4} onChange={handleChange} onResend={() => {}} resendText="Resend OTP" />);
|
|
22
|
+
const inputs = screen.getAllByRole('textbox');
|
|
23
|
+
fireEvent.change(inputs[0], { target: { value: '1' } });
|
|
24
|
+
expect(handleChange).toHaveBeenCalledWith('1');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('calls onResend prop when the resend button is clicked', async () => {
|
|
28
|
+
const handleResend = jest.fn();
|
|
29
|
+
render(<OTPInput length={4} onChange={() => {}} onResend={handleResend} resendText="Resend OTP" resendDelay={0} />);
|
|
30
|
+
const resendButton = screen.getByRole('button', { name: /resend otp/i });
|
|
31
|
+
fireEvent.click(resendButton);
|
|
32
|
+
expect(handleResend).toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
it('displays error text when the error prop is true', () => {
|
|
35
|
+
const errorMessage = 'Invalid OTP';
|
|
36
|
+
render(<OTPInput length={4} onChange={() => {}} onResend={() => {}} resendText="Resend OTP" error={true} errorText={errorMessage} />);
|
|
37
|
+
const errorElement = screen.getByText(errorMessage);
|
|
38
|
+
expect(errorElement).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
it('changes border color to red when the error prop is true', () => {
|
|
41
|
+
render(
|
|
42
|
+
<OTPInput
|
|
43
|
+
length={4}
|
|
44
|
+
onChange={() => {}}
|
|
45
|
+
onResend={() => {}}
|
|
46
|
+
resendText="Resend OTP"
|
|
47
|
+
error={true}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
const firstInput = screen.getByTestId('otp-input-0');
|
|
51
|
+
expect(firstInput).toHaveStyle('border: 1px solid #EB0542');
|
|
52
|
+
});
|
|
53
|
+
});
|