dhre-component-lib 0.0.1 → 0.0.2

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.
Files changed (90) hide show
  1. package/coverage/clover.xml +260 -0
  2. package/coverage/coverage-final.json +19 -0
  3. package/coverage/lcov-report/base.css +224 -0
  4. package/coverage/lcov-report/block-navigation.js +87 -0
  5. package/coverage/lcov-report/components/Avatar/Avatar.tsx.html +163 -0
  6. package/coverage/lcov-report/components/Avatar/index.html +116 -0
  7. package/coverage/lcov-report/components/Badge/Badge.tsx.html +160 -0
  8. package/coverage/lcov-report/components/Badge/index.html +116 -0
  9. package/coverage/lcov-report/components/BreadCrumb/BreadCrumb.tsx.html +193 -0
  10. package/coverage/lcov-report/components/BreadCrumb/index.html +116 -0
  11. package/coverage/lcov-report/components/Button/Button.tsx.html +151 -0
  12. package/coverage/lcov-report/components/Button/index.html +116 -0
  13. package/coverage/lcov-report/components/Checkbox/Checkbox.tsx.html +190 -0
  14. package/coverage/lcov-report/components/Checkbox/index.html +116 -0
  15. package/coverage/lcov-report/components/CircularProgress/CircularProgress.tsx.html +196 -0
  16. package/coverage/lcov-report/components/CircularProgress/index.html +116 -0
  17. package/coverage/lcov-report/components/Divider/Divider.tsx.html +157 -0
  18. package/coverage/lcov-report/components/Divider/index.html +116 -0
  19. package/coverage/lcov-report/components/Enum.ts.html +142 -0
  20. package/coverage/lcov-report/components/InputTextField/InputTextField.tsx.html +229 -0
  21. package/coverage/lcov-report/components/InputTextField/index.html +116 -0
  22. package/coverage/lcov-report/components/Link/Link.tsx.html +184 -0
  23. package/coverage/lcov-report/components/Link/index.html +116 -0
  24. package/coverage/lcov-report/components/Modal/Modal.tsx.html +169 -0
  25. package/coverage/lcov-report/components/Modal/index.html +116 -0
  26. package/coverage/lcov-report/components/Notification/Notification.tsx.html +208 -0
  27. package/coverage/lcov-report/components/Notification/index.html +116 -0
  28. package/coverage/lcov-report/components/PdfView/PdfView.tsx.html +400 -0
  29. package/coverage/lcov-report/components/PdfView/index.html +116 -0
  30. package/coverage/lcov-report/components/Progress/Progress.tsx.html +190 -0
  31. package/coverage/lcov-report/components/Progress/index.html +116 -0
  32. package/coverage/lcov-report/components/RadioButton/RadioButton.tsx.html +214 -0
  33. package/coverage/lcov-report/components/RadioButton/index.html +116 -0
  34. package/coverage/lcov-report/components/Switch/Switch.tsx.html +199 -0
  35. package/coverage/lcov-report/components/Switch/index.html +116 -0
  36. package/coverage/lcov-report/components/Tag/Tag.tsx.html +160 -0
  37. package/coverage/lcov-report/components/Tag/index.html +116 -0
  38. package/coverage/lcov-report/components/Tooltip/Tooltip.tsx.html +187 -0
  39. package/coverage/lcov-report/components/Tooltip/index.html +116 -0
  40. package/coverage/lcov-report/components/index.html +116 -0
  41. package/coverage/lcov-report/favicon.png +0 -0
  42. package/coverage/lcov-report/index.html +371 -0
  43. package/coverage/lcov-report/prettify.css +1 -0
  44. package/coverage/lcov-report/prettify.js +2 -0
  45. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  46. package/coverage/lcov-report/sorter.js +196 -0
  47. package/coverage/lcov.info +457 -0
  48. package/jest.config.ts +1 -1
  49. package/package.json +9 -6
  50. package/src/components/Avatar/Avatar.test.tsx +52 -0
  51. package/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap +9 -0
  52. package/src/components/Badge/Badge.test.tsx +63 -0
  53. package/src/components/Badge/__snapshots__/Badge.test.tsx.snap +9 -0
  54. package/src/components/BreadCrumb/BreadCrumb.test.tsx +90 -0
  55. package/src/components/BreadCrumb/index.ts +1 -0
  56. package/src/components/Button/Button.test.tsx +62 -0
  57. package/src/components/Button/__snapshots__/Button.test.tsx.snap +9 -0
  58. package/src/components/Checkbox/Checkbox.test.tsx +71 -43
  59. package/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +17 -0
  60. package/src/components/{Circular_Progress → CircularProgress}/CircularProgress.tsx +1 -1
  61. package/src/components/Divider/Divider.test.tsx +35 -10
  62. package/src/components/InputTextField/InputTextField.test.tsx +103 -33
  63. package/src/components/InputTextField/InputTextField.tsx +7 -5
  64. package/src/components/Link/Link.test.tsx +44 -36
  65. package/src/components/Link/Link.tsx +1 -1
  66. package/src/components/Map/Directions.tsx +36 -0
  67. package/src/components/Map/GoogleMap.module.scss +5 -0
  68. package/src/components/Map/GoogleMap.tsx +186 -0
  69. package/src/components/Map/GoogleMapsLoader.tsx +12 -0
  70. package/src/components/Map/index.ts +2 -0
  71. package/src/components/Modal/Modal.css +26 -0
  72. package/src/components/Modal/Modal.test.tsx +53 -34
  73. package/src/components/Modal/Modal.tsx +15 -6
  74. package/src/components/PdfView/PdfView.css +70 -0
  75. package/src/components/PdfView/PdfView.test.tsx +27 -63
  76. package/src/components/PdfView/PdfView.tsx +53 -41
  77. package/src/components/Progress/Progress.test.tsx +34 -26
  78. package/src/components/Progress/Progress.tsx +2 -2
  79. package/src/components/RadioButton/RadioButton.test.tsx +59 -30
  80. package/src/components/Switch/Switch.test.tsx +83 -0
  81. package/src/components/Tag/Tag.test.tsx +57 -0
  82. package/src/components/Tag/__snapshots__/Tag.test.tsx.snap +9 -0
  83. package/src/components/Tooltip/Tooltip.test.tsx +73 -0
  84. package/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap +22 -0
  85. package/src/components/index.ts +5 -2
  86. package/src/typings.d.ts +1 -0
  87. package/tsconfig.json +17 -18
  88. /package/src/components/{Circular_Progress → CircularProgress}/CircularProgress.css +0 -0
  89. /package/src/components/{Circular_Progress → CircularProgress}/CircularProgress.test.tsx +0 -0
  90. /package/src/components/{Circular_Progress → CircularProgress}/index.ts +0 -0
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { LINK_TARGET } from '../Enum';
3
3
 
4
- interface LinkProps {
4
+ export interface LinkProps {
5
5
  href: string;
6
6
  target?:string ;
7
7
  rel?: string;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ interface GetDirectionActionProps {
4
+ title: string;
5
+ titleClasses?: string;
6
+ location: string;
7
+ locationClasses?: string;
8
+ hours: string;
9
+ hoursClasses?: string;
10
+ directionsLink: string;
11
+ buttonName?: string;
12
+ }
13
+
14
+ const GetDirectionAction: React.FC<GetDirectionActionProps> = ({
15
+ title,
16
+ titleClasses,
17
+ location,
18
+ locationClasses,
19
+ hours,
20
+ hoursClasses,
21
+ directionsLink,
22
+ buttonName = 'Get Directions',
23
+ }) => {
24
+ return (
25
+ <div className="direction-action-container">
26
+ <h3 className={titleClasses}>{title}</h3>
27
+ <p className={locationClasses}>{location}</p>
28
+ <p className={hoursClasses}>{hours}</p>
29
+ <a href={directionsLink} target="_blank" rel="noopener noreferrer" className="directions-link">
30
+ {buttonName}
31
+ </a>
32
+ </div>
33
+ );
34
+ };
35
+
36
+ export default GetDirectionAction;
@@ -0,0 +1,5 @@
1
+ .mapContainerStyle{
2
+ width: 100%;
3
+ height: 100%;
4
+ position: absolute;
5
+ }
@@ -0,0 +1,186 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import {
3
+ GoogleMap,
4
+ Marker,
5
+ Circle,
6
+ DirectionsRenderer,
7
+ } from "@react-google-maps/api";
8
+ import { useGoogleMapsLoader } from "./GoogleMapsLoader";
9
+ import styles from './GoogleMap.module.scss'
10
+ export interface MapComponentProps {
11
+ containerClassName?: string;
12
+ zoom?: number;
13
+ mapOptions?: google.maps.MapOptions;
14
+ radius?: number;
15
+ googleMapsUrls: string[];
16
+ buttonText: string;
17
+ buttonClassName: string;
18
+ }
19
+
20
+ const MapComponent: React.FC<MapComponentProps> = ({
21
+ containerClassName = "map-container",
22
+ zoom = 18,
23
+ mapOptions = {
24
+ zoomControl: true,
25
+ tilt: 0,
26
+ gestureHandling: "auto",
27
+ mapTypeId: "roadmap",
28
+ },
29
+ radius = 5000,
30
+ googleMapsUrls,
31
+ buttonText,
32
+ buttonClassName,
33
+ }) => {
34
+ const [location, setLocation] = useState<{
35
+ latitude: number;
36
+ longitude: number;
37
+ } | null>(null);
38
+ const [mapVisible, setMapVisible] = useState(false);
39
+ const [directionsResponse, setDirectionsResponse] =
40
+ useState<google.maps.DirectionsResult | null>(null);
41
+ const mapRef = useRef<google.maps.Map | null>(null);
42
+ const directionsService = useRef<google.maps.DirectionsService | null>(null);
43
+ const directionsRenderer = useRef<google.maps.DirectionsRenderer | null>(
44
+ null
45
+ );
46
+
47
+ const handleLocationRequest = () => {
48
+ if ("geolocation" in navigator) {
49
+ navigator.geolocation.getCurrentPosition(
50
+ ({ coords }) => {
51
+ const { latitude, longitude } = coords;
52
+ setLocation({ latitude, longitude });
53
+ setMapVisible(true);
54
+ },
55
+ () => {
56
+ alert("Failed to get location. Please try again.");
57
+ }
58
+ );
59
+ } else {
60
+ alert("Geolocation is not supported by this browser.");
61
+ }
62
+ };
63
+
64
+ const handleMarkerClick = (lat: number, lng: number) => {
65
+ if (location) {
66
+ const directionsServiceInstance =
67
+ directionsService.current || new google.maps.DirectionsService();
68
+ const directionsRendererInstance =
69
+ directionsRenderer.current || new google.maps.DirectionsRenderer();
70
+
71
+ if (!directionsService.current)
72
+ directionsService.current = directionsServiceInstance;
73
+ if (!directionsRenderer.current)
74
+ directionsRenderer.current = directionsRendererInstance;
75
+
76
+ const directionsRequest: google.maps.DirectionsRequest = {
77
+ origin: { lat: location.latitude, lng: location.longitude },
78
+ destination: { lat, lng },
79
+ travelMode: google.maps.TravelMode.DRIVING,
80
+ };
81
+
82
+ directionsService.current.route(directionsRequest, (result, status) => {
83
+ if (status === google.maps.DirectionsStatus.OK) {
84
+ setDirectionsResponse(result);
85
+ if (mapRef.current && directionsRenderer.current) {
86
+ directionsRenderer.current.setMap(mapRef.current);
87
+ directionsRenderer.current.setDirections(result);
88
+ }
89
+ } else {
90
+ alert("Failed to get directions. Please try again.");
91
+ }
92
+ });
93
+ }
94
+ };
95
+
96
+ const extractCoordinatesFromUrl = (url: string) => {
97
+ const regex = /@(-?\d+\.\d+),(-?\d+\.\d+)/;
98
+ const match = url.match(regex);
99
+ if (match) {
100
+ return {
101
+ lat: parseFloat(match[1]),
102
+ lng: parseFloat(match[2]),
103
+ };
104
+ }
105
+
106
+ return null;
107
+ };
108
+
109
+ const { isLoaded } = useGoogleMapsLoader();
110
+
111
+ useEffect(() => {}, [isLoaded]);
112
+
113
+ useEffect(() => {}, [mapVisible]);
114
+
115
+ if (!isLoaded) {
116
+ return <div>Loading map...</div>;
117
+ }
118
+
119
+ if (mapVisible && location) {
120
+ return (
121
+ <div className={containerClassName}>
122
+ <button onClick={handleLocationRequest} className={buttonClassName}>
123
+ {buttonText}
124
+ </button>
125
+
126
+ <GoogleMap
127
+ mapContainerStyle={styles.mapContainerStyle}
128
+ center={{ lat: location.latitude, lng: location.longitude }}
129
+ zoom={zoom}
130
+ options={mapOptions}
131
+ onLoad={(map) => {
132
+ mapRef.current = map;
133
+ directionsRenderer.current = new google.maps.DirectionsRenderer();
134
+ directionsRenderer.current.setMap(map);
135
+ }}
136
+ >
137
+ <Marker
138
+ position={{ lat: location.latitude, lng: location.longitude }}
139
+ icon="http://maps.google.com/mapfiles/ms/icons/red-dot.png"
140
+ />
141
+ <Circle
142
+ center={{ lat: location.latitude, lng: location.longitude }}
143
+ radius={radius}
144
+ options={{
145
+ strokeColor: "#FF0000",
146
+ strokeOpacity: 0.8,
147
+ strokeWeight: 2,
148
+ fillColor: "#FF0000",
149
+ fillOpacity: 0,
150
+ }}
151
+ />
152
+ {googleMapsUrls.map((url, index) => {
153
+ const coord = extractCoordinatesFromUrl(url);
154
+ if (!coord) return null;
155
+
156
+ return (
157
+ <Marker
158
+ key={index}
159
+ position={{ lat: coord.lat, lng: coord.lng }}
160
+ title={`Sample Location ${index + 1}`}
161
+ icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
162
+ onClick={() => handleMarkerClick(coord.lat, coord.lng)}
163
+ />
164
+ );
165
+ })}
166
+ {directionsResponse && (
167
+ <DirectionsRenderer
168
+ directions={directionsResponse}
169
+ options={{ suppressMarkers: true }}
170
+ />
171
+ )}
172
+ </GoogleMap>
173
+ </div>
174
+ );
175
+ } else {
176
+ return (
177
+ <div className={containerClassName}>
178
+ <button onClick={handleLocationRequest} className={buttonClassName}>
179
+ {buttonText}
180
+ </button>
181
+ </div>
182
+ );
183
+ }
184
+ };
185
+
186
+ export default MapComponent;
@@ -0,0 +1,12 @@
1
+ import { useJsApiLoader } from '@react-google-maps/api';
2
+
3
+ const GOOGLE_MAPS_API_KEY = process.env.NEXT_PUBLIC_GOOGLE_MAP_API as string; // Ensure you are using environment variable
4
+
5
+ export const useGoogleMapsLoader = () => {
6
+ return useJsApiLoader({
7
+ googleMapsApiKey: GOOGLE_MAPS_API_KEY, // Replace with your API key
8
+ libraries: ['places', 'drawing', 'geometry'], // Include all libraries you need
9
+ language: 'en',
10
+ region: 'US',
11
+ });
12
+ };
@@ -0,0 +1,2 @@
1
+ export { default as Directions } from "./Directions";
2
+ export { default as GoogleMap } from "./GoogleMap";
@@ -0,0 +1,26 @@
1
+ .modalOverlay {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ background: rgba(0, 0, 0, 0.5);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ z-index: 1000;
12
+ }
13
+
14
+ .modalContent {
15
+ background: white;
16
+ position: relative;
17
+ width: auto;
18
+ height: auto;
19
+ max-width: 80vw;
20
+ max-height: 80vh;
21
+ overflow: scroll;
22
+ }
23
+
24
+ .modalContent::-webkit-scrollbar {
25
+ display: none;
26
+ }
@@ -1,51 +1,70 @@
1
- import React from "react";
2
- import { render, screen } from "@testing-library/react";
3
- import Modal from "./Modal";
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import Modal from './Modal';
4
4
 
5
- describe("Modal Component", () => {
6
- test("renders children when open", () => {
5
+ describe('Modal Component', () => {
6
+ const onCloseMock = jest.fn();
7
+ const modalContentText = 'This is the modal content';
8
+
9
+ const renderModal = (isOpen: boolean, modalOverlayClassname?: string, modalContentClassname?: string) => {
7
10
  render(
8
- <Modal isOpen={true} onClose={() => {}}>
9
- <div>Modal Content</div>
11
+ <Modal
12
+ isOpen={isOpen}
13
+ onClose={onCloseMock}
14
+ modalOverlayClassname={modalOverlayClassname}
15
+ modalContentClassname={modalContentClassname}
16
+ >
17
+ <div>{modalContentText}</div>
10
18
  </Modal>
11
19
  );
20
+ };
12
21
 
13
- expect(screen.getByText("Modal Content")).toBeInTheDocument();
22
+ afterEach(() => {
23
+ jest.clearAllMocks();
14
24
  });
15
25
 
16
- test("does not render children when not open", () => {
17
- render(
18
- <Modal isOpen={false} onClose={() => {}}>
19
- <div>Modal Content</div>
20
- </Modal>
21
- );
22
-
23
- expect(screen.queryByText("Modal Content")).not.toBeInTheDocument();
26
+ it('renders the modal when isOpen is true', () => {
27
+ renderModal(true);
28
+ expect(screen.getByText(modalContentText)).toBeInTheDocument();
24
29
  });
25
30
 
26
- test("calls onClose when the modal is closed", () => {
27
- const onCloseMock = jest.fn();
31
+ it('does not render the modal when isOpen is false', () => {
32
+ renderModal(false);
33
+ expect(screen.queryByText(modalContentText)).not.toBeInTheDocument();
34
+ });
28
35
 
29
- render(
30
- <Modal isOpen={true} onClose={onCloseMock}>
31
- <div>Modal Content</div>
32
- </Modal>
33
- );
36
+ it('calls onClose when clicking on the overlay', () => {
37
+ renderModal(true);
38
+ const overlay = screen.getByText(modalContentText).closest('div.modalOverlay');
39
+ fireEvent.click(overlay!);
40
+ expect(onCloseMock).toHaveBeenCalled();
41
+ });
34
42
 
35
- // Manually trigger the close event
36
- onCloseMock();
43
+ it('does not call onClose when clicking inside the modal content', () => {
44
+ renderModal(true);
45
+ const modalContent = screen.getByText(modalContentText);
46
+ fireEvent.click(modalContent);
47
+ expect(onCloseMock).not.toHaveBeenCalled();
48
+ });
37
49
 
38
- expect(onCloseMock).toHaveBeenCalledTimes(1);
50
+ it('applies the provided modalOverlayClassname', () => {
51
+ const overlayClass = 'customOverlayClass';
52
+ renderModal(true, overlayClass);
53
+ const overlay = screen.getByText(modalContentText).closest('div.modalOverlay');
54
+ expect(overlay).toHaveClass(overlayClass);
39
55
  });
40
56
 
41
- test("applies the className to the modal container", () => {
42
- render(
43
- <Modal isOpen={true} onClose={() => {}} className="custom-class">
44
- <div>Modal Content</div>
45
- </Modal>
46
- );
57
+ it('applies the provided modalContentClassname', () => {
58
+ const contentClass = 'customContentClass';
59
+ renderModal(true, undefined, contentClass);
60
+ const modalContent = screen.getByText(modalContentText).closest('div.modalContent');
61
+ expect(modalContent).toHaveClass(contentClass);
62
+ });
47
63
 
48
- const modalContainer = screen.getByText("Modal Content").parentElement;
49
- expect(modalContainer).toHaveClass("custom-class");
64
+ it('does not render modal when isOpen is false, even if modalOverlayClassname and modalContentClassname are provided', () => {
65
+ const overlayClass = 'customOverlayClass';
66
+ const contentClass = 'customContentClass';
67
+ renderModal(false, overlayClass, contentClass);
68
+ expect(screen.queryByText(modalContentText)).not.toBeInTheDocument();
50
69
  });
51
70
  });
@@ -1,18 +1,27 @@
1
1
  import React from "react";
2
- import { Modal as MuiModal } from "@mui/material";
2
+ import "./Modal.css";
3
3
 
4
4
  interface ModalProps {
5
5
  isOpen: boolean;
6
6
  onClose: () => void;
7
7
  children: React.ReactNode;
8
- className?: string;
8
+ modalOverlayClassname?: string;
9
+ modalContentClassname?: string;
9
10
  }
10
11
 
11
- const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children, className, ...rest }) => {
12
+ const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children, modalOverlayClassname, modalContentClassname }) => {
13
+ if (!isOpen) return null;
14
+
15
+ const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
16
+ if (event.target === event.currentTarget) {
17
+ onClose();
18
+ }
19
+ };
20
+
12
21
  return (
13
- <MuiModal open={isOpen} onClose={onClose} {...rest}>
14
- <div className={className}>{children}</div>
15
- </MuiModal>
22
+ <div className={`modalOverlay ${modalOverlayClassname}`} onClick={handleOverlayClick}>
23
+ <div className={`modalContent ${modalContentClassname}`}>{children}</div>
24
+ </div>
16
25
  );
17
26
  };
18
27
 
@@ -0,0 +1,70 @@
1
+ .container {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ }
7
+
8
+ .spinner {
9
+ border: 2px solid transparent;
10
+ border-radius: 50%;
11
+ border-top: 2px solid currentColor;
12
+ animation: spin 1s linear infinite;
13
+ }
14
+
15
+ .spinner-inner {
16
+ width: 100%;
17
+ height: 100%;
18
+ border-radius: 50%;
19
+ }
20
+
21
+ .error-text {
22
+ color: red;
23
+ }
24
+
25
+ .button {
26
+ padding: 8px 16px;
27
+ border: none;
28
+ border-radius: 4px;
29
+ cursor: pointer;
30
+ font-size: 16px;
31
+ }
32
+
33
+ .button-text {
34
+ background: none;
35
+ }
36
+
37
+ .button-outlined {
38
+ border: 1px solid currentColor;
39
+ }
40
+
41
+ .button-contained {
42
+ background-color: currentColor;
43
+ color: white;
44
+ }
45
+
46
+ .button-primary {
47
+ color: blue;
48
+ }
49
+
50
+ .button-secondary {
51
+ color: gray;
52
+ }
53
+
54
+ .button-small {
55
+ font-size: 12px;
56
+ }
57
+
58
+ .button-medium {
59
+ font-size: 16px;
60
+ }
61
+
62
+ .button-large {
63
+ font-size: 20px;
64
+ }
65
+
66
+ @keyframes spin {
67
+ 0% { transform: rotate(0deg); }
68
+ 100% { transform: rotate(360deg); }
69
+ }
70
+
@@ -1,79 +1,43 @@
1
1
  import React from 'react';
2
2
  import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
3
  import '@testing-library/jest-dom';
4
- import PdfView, { PdfViewerProps } from './PdfView';
5
-
6
- // Mock the URL.createObjectURL and URL.revokeObjectURL functions
7
- global.URL.createObjectURL = jest.fn();
8
- global.URL.revokeObjectURL = jest.fn();
9
-
10
- const defaultProps: PdfViewerProps = {
11
- content: 'mockBase64Data',
12
- buttonText: 'View PDF',
13
- showLoadingSpinner: true, // Set this to true to test the spinner
14
- loadingText: 'Loading...',
15
- errorText: 'Failed to load PDF',
16
- spinnerSize: 24,
17
- spinnerColor: 'primary',
18
- };
4
+ import PdfView from './PdfView';
19
5
 
20
6
  describe('PdfView Component', () => {
21
- beforeEach(() => {
22
- jest.clearAllMocks();
7
+ // Dummy base64 content for testing
8
+ const validBase64Content = 'JVBERi0xLjQKJeLjz9MNCjEgMCBvYmoKPDwvTGluay9QYWdlcyAyIDAgUj4+CnN0YXJ0eHJlZgoyNCAwIFIKZW5kb2JqCjEgMCBvYmoKPDwvTGluay9QYWdlcyAyIDAgUj4+CnN0YXJ0eHJlZgo2IDAgUgo+';
9
+ const invalidBase64Content = 'invalid base64 content';
10
+ const errorText = 'Failed to load PDF';
11
+ const buttonText = 'View PDF';
12
+ const loadingText = 'Loading...';
13
+
14
+ beforeAll(() => {
15
+ // Mock URL.createObjectURL directly
16
+ global.URL.createObjectURL = jest.fn(() => 'mock-url');
23
17
  });
24
18
 
25
- it('should render the PDF viewer with the default button text', () => {
26
- render(<PdfView {...defaultProps} />);
27
- expect(screen.getByText('View PDF')).toBeInTheDocument();
19
+ afterAll(() => {
20
+ // Restore the original implementation
21
+ delete global.URL.createObjectURL;
28
22
  });
29
23
 
30
-
31
- it('should render an error message if the PDF fails to load', async () => {
32
- // Override the base64ToBlob method to throw an error
33
- jest.spyOn(global, 'atob').mockImplementation(() => {
34
- throw new Error('Error converting base64');
35
- });
36
-
37
- render(<PdfView {...defaultProps} />);
38
-
39
- // Click the button to trigger the error
40
- fireEvent.click(screen.getByText('View PDF'));
41
-
42
- // Wait for the error message to appear
43
- await waitFor(() => expect(screen.getByText('Failed to load PDF')).toBeInTheDocument());
44
-
45
- jest.restoreAllMocks();
24
+ it('renders correctly with default props', () => {
25
+ render(<PdfView content={validBase64Content} />);
26
+ expect(screen.getByText(buttonText)).toBeInTheDocument();
46
27
  });
47
28
 
48
- it('should call the onError callback when there is an error', async () => {
49
- const mockOnError = jest.fn();
50
-
51
- // Simulate an error in base64 to blob conversion
52
- jest.spyOn(global, 'atob').mockImplementation(() => {
53
- throw new Error('Error converting base64');
54
- });
55
-
56
- render(<PdfView {...defaultProps} onError={mockOnError} />);
57
-
58
- // Click the button to trigger the error
59
- fireEvent.click(screen.getByText('View PDF'));
60
-
61
- // Wait for the error callback to be called
62
- await waitFor(() => expect(mockOnError).toHaveBeenCalled());
63
-
64
- jest.restoreAllMocks();
29
+ it('shows error message if content is invalid', () => {
30
+ render(<PdfView content={invalidBase64Content} />);
31
+ expect(screen.getByText(errorText)).toBeInTheDocument();
65
32
  });
66
33
 
67
- it('should open the PDF in a new tab when the button is clicked', async () => {
68
- render(<PdfView {...defaultProps} />);
69
34
 
70
- // Click the button to trigger PDF opening
71
- fireEvent.click(screen.getByText('View PDF'));
72
-
73
- // Check if URL.createObjectURL was called
74
- await waitFor(() => expect(global.URL.createObjectURL).toHaveBeenCalled());
75
-
76
- // Check if window.open was called
77
- expect(global.URL.createObjectURL).toHaveBeenCalled();
35
+
36
+ it('applies the provided class names', () => {
37
+ const className = 'custom-class';
38
+ render(<PdfView content={validBase64Content} className={className} />);
39
+ expect(screen.getByText(buttonText).parentElement).toHaveClass(className);
78
40
  });
41
+
42
+ // More tests for different button props can be added here...
79
43
  });