@tantainnovative/ndpr-toolkit 1.0.3 → 1.0.4
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/next-env.d.ts +5 -0
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -20
- package/.eslintrc.json +0 -10
- package/.github/workflows/ci.yml +0 -36
- package/.github/workflows/nextjs.yml +0 -104
- package/.husky/commit-msg +0 -4
- package/.husky/pre-commit +0 -4
- package/.lintstagedrc.js +0 -4
- package/.nvmrc +0 -1
- package/.versionrc +0 -17
- package/CLAUDE.md +0 -90
- package/commitlint.config.js +0 -36
- package/eslint.config.mjs +0 -16
- package/jest.config.js +0 -31
- package/jest.setup.js +0 -15
- package/next.config.js +0 -15
- package/next.config.ts +0 -62
- package/packages/ndpr-toolkit/README.md +0 -467
- package/packages/ndpr-toolkit/jest.config.js +0 -23
- package/packages/ndpr-toolkit/package-lock.json +0 -8197
- package/packages/ndpr-toolkit/package.json +0 -71
- package/packages/ndpr-toolkit/rollup.config.js +0 -34
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +0 -119
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +0 -122
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +0 -270
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +0 -199
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +0 -224
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +0 -104
- package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +0 -161
- package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +0 -330
- package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +0 -149
- package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +0 -88
- package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +0 -160
- package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +0 -110
- package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +0 -97
- package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +0 -701
- package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +0 -631
- package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +0 -569
- package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +0 -496
- package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +0 -270
- package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +0 -217
- package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +0 -206
- package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +0 -342
- package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +0 -373
- package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +0 -174
- package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +0 -717
- package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +0 -476
- package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +0 -620
- package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +0 -541
- package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +0 -454
- package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +0 -333
- package/packages/ndpr-toolkit/src/hooks/useBreach.ts +0 -409
- package/packages/ndpr-toolkit/src/hooks/useConsent.ts +0 -263
- package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +0 -457
- package/packages/ndpr-toolkit/src/hooks/useDSR.ts +0 -236
- package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +0 -428
- package/packages/ndpr-toolkit/src/index.ts +0 -44
- package/packages/ndpr-toolkit/src/setupTests.ts +0 -5
- package/packages/ndpr-toolkit/src/types/breach.ts +0 -283
- package/packages/ndpr-toolkit/src/types/consent.ts +0 -111
- package/packages/ndpr-toolkit/src/types/dpia.ts +0 -236
- package/packages/ndpr-toolkit/src/types/dsr.ts +0 -192
- package/packages/ndpr-toolkit/src/types/index.ts +0 -42
- package/packages/ndpr-toolkit/src/types/privacy.ts +0 -246
- package/packages/ndpr-toolkit/src/utils/breach.ts +0 -122
- package/packages/ndpr-toolkit/src/utils/consent.ts +0 -51
- package/packages/ndpr-toolkit/src/utils/dpia.ts +0 -104
- package/packages/ndpr-toolkit/src/utils/dsr.ts +0 -77
- package/packages/ndpr-toolkit/src/utils/privacy.ts +0 -100
- package/packages/ndpr-toolkit/tsconfig.json +0 -23
- package/postcss.config.mjs +0 -5
- package/src/__tests__/example.test.ts +0 -13
- package/src/__tests__/requestService.test.ts +0 -57
- package/src/app/accessibility.css +0 -70
- package/src/app/docs/components/DocLayout.tsx +0 -267
- package/src/app/docs/components/breach-notification/page.tsx +0 -797
- package/src/app/docs/components/consent-management/page.tsx +0 -576
- package/src/app/docs/components/data-subject-rights/page.tsx +0 -511
- package/src/app/docs/components/dpia-questionnaire/layout.tsx +0 -15
- package/src/app/docs/components/dpia-questionnaire/metadata.ts +0 -31
- package/src/app/docs/components/dpia-questionnaire/page.tsx +0 -666
- package/src/app/docs/components/hooks/page.tsx +0 -305
- package/src/app/docs/components/page.tsx +0 -84
- package/src/app/docs/components/privacy-policy-generator/page.tsx +0 -634
- package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +0 -123
- package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +0 -328
- package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +0 -28
- package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +0 -91
- package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +0 -118
- package/src/app/docs/guides/breach-notification-process/page.tsx +0 -39
- package/src/app/docs/guides/conducting-dpia/page.tsx +0 -593
- package/src/app/docs/guides/data-subject-requests/page.tsx +0 -666
- package/src/app/docs/guides/managing-consent/page.tsx +0 -738
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +0 -296
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +0 -145
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +0 -33
- package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +0 -99
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +0 -159
- package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +0 -38
- package/src/app/docs/guides/page.tsx +0 -67
- package/src/app/docs/layout.tsx +0 -15
- package/src/app/docs/metadata.ts +0 -31
- package/src/app/docs/page.tsx +0 -572
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +0 -123
- package/src/app/layout.tsx +0 -37
- package/src/app/ndpr-demos/breach/page.tsx +0 -354
- package/src/app/ndpr-demos/consent/page.tsx +0 -366
- package/src/app/ndpr-demos/dpia/page.tsx +0 -495
- package/src/app/ndpr-demos/dsr/page.tsx +0 -280
- package/src/app/ndpr-demos/page.tsx +0 -73
- package/src/app/ndpr-demos/policy/page.tsx +0 -771
- package/src/app/page.tsx +0 -452
- package/src/components/ErrorBoundary.tsx +0 -90
- package/src/components/breach-notification/BreachNotificationForm.tsx +0 -479
- package/src/components/consent/ConsentBanner.tsx +0 -159
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -419
- package/src/components/docs/DocLayout.tsx +0 -289
- package/src/components/docs/index.ts +0 -2
- package/src/components/dpia/DPIAQuestionnaire.tsx +0 -483
- package/src/components/privacy-policy/PolicyGenerator.tsx +0 -1062
- package/src/components/privacy-policy/data.ts +0 -98
- package/src/components/privacy-policy/shared/CheckboxField.tsx +0 -38
- package/src/components/privacy-policy/shared/CheckboxGroup.tsx +0 -85
- package/src/components/privacy-policy/shared/FormField.tsx +0 -79
- package/src/components/privacy-policy/shared/StepIndicator.tsx +0 -86
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +0 -335
- package/src/components/privacy-policy/steps/DataCollectionStep.tsx +0 -231
- package/src/components/privacy-policy/steps/DataSharingStep.tsx +0 -418
- package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +0 -202
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +0 -172
- package/src/components/ui/Badge.tsx +0 -46
- package/src/components/ui/Button.tsx +0 -59
- package/src/components/ui/Card.tsx +0 -92
- package/src/components/ui/Checkbox.tsx +0 -57
- package/src/components/ui/FormField.tsx +0 -50
- package/src/components/ui/Input.tsx +0 -38
- package/src/components/ui/Loading.tsx +0 -201
- package/src/components/ui/Select.tsx +0 -42
- package/src/components/ui/TextArea.tsx +0 -38
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/switch.tsx +0 -31
- package/src/components/ui/tabs.tsx +0 -66
- package/src/hooks/useConsent.ts +0 -64
- package/src/hooks/useLoadingState.ts +0 -85
- package/src/lib/consentService.ts +0 -137
- package/src/lib/dpiaQuestions.ts +0 -148
- package/src/lib/requestService.ts +0 -75
- package/src/lib/sanitize.ts +0 -108
- package/src/lib/storage.ts +0 -222
- package/src/lib/utils.ts +0 -6
- package/src/types/html-to-docx.d.ts +0 -30
- package/src/types/index.ts +0 -72
- package/tailwind.config.ts +0 -65
- package/tsconfig.json +0 -41
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { renderHook, act } from '@testing-library/react';
|
|
2
|
-
import { useDSR } from '../../hooks/useDSR';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { DSRRequest, RequestType } from '../../types/dsr';
|
|
5
|
-
|
|
6
|
-
// Mock localStorage
|
|
7
|
-
const mockLocalStorage = (() => {
|
|
8
|
-
let store: Record<string, string> = {};
|
|
9
|
-
return {
|
|
10
|
-
getItem: jest.fn((key: string) => store[key] || null),
|
|
11
|
-
setItem: jest.fn((key: string, value: string) => {
|
|
12
|
-
store[key] = value.toString();
|
|
13
|
-
}),
|
|
14
|
-
removeItem: jest.fn((key: string) => {
|
|
15
|
-
delete store[key];
|
|
16
|
-
}),
|
|
17
|
-
clear: jest.fn(() => {
|
|
18
|
-
store = {};
|
|
19
|
-
}),
|
|
20
|
-
};
|
|
21
|
-
})();
|
|
22
|
-
|
|
23
|
-
Object.defineProperty(window, 'localStorage', {
|
|
24
|
-
value: mockLocalStorage,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('useDSR', () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
mockLocalStorage.clear();
|
|
30
|
-
jest.clearAllMocks();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const mockRequestTypes: RequestType[] = [
|
|
34
|
-
{
|
|
35
|
-
id: 'access',
|
|
36
|
-
name: 'Access Request',
|
|
37
|
-
description: 'Request to access your personal data',
|
|
38
|
-
estimatedCompletionTime: 30,
|
|
39
|
-
requiresAdditionalInfo: false
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: 'erasure',
|
|
43
|
-
name: 'Erasure Request',
|
|
44
|
-
description: 'Request to delete your personal data',
|
|
45
|
-
estimatedCompletionTime: 45,
|
|
46
|
-
requiresAdditionalInfo: false
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: 'rectification',
|
|
50
|
-
name: 'Rectification Request',
|
|
51
|
-
description: 'Request to correct your personal data',
|
|
52
|
-
estimatedCompletionTime: 15,
|
|
53
|
-
requiresAdditionalInfo: true
|
|
54
|
-
}
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
it('should initialize with empty requests array', () => {
|
|
58
|
-
const { result } = renderHook(() => useDSR({
|
|
59
|
-
requestTypes: mockRequestTypes,
|
|
60
|
-
storageKey: 'test-dsr',
|
|
61
|
-
useLocalStorage: true
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
expect(result.current.requests).toEqual([]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should submit a new DSR request', () => {
|
|
68
|
-
const { result } = renderHook(() => useDSR({
|
|
69
|
-
requestTypes: mockRequestTypes,
|
|
70
|
-
storageKey: 'test-dsr',
|
|
71
|
-
useLocalStorage: true
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
act(() => {
|
|
75
|
-
result.current.submitRequest({
|
|
76
|
-
type: 'access',
|
|
77
|
-
subject: {
|
|
78
|
-
name: 'John Doe',
|
|
79
|
-
email: 'john@example.com',
|
|
80
|
-
},
|
|
81
|
-
createdAt: Date.now(),
|
|
82
|
-
description: 'I want to access my data',
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(result.current.requests.length).toBe(1);
|
|
87
|
-
expect(result.current.requests[0].type).toBe('access');
|
|
88
|
-
expect(result.current.requests[0].status).toBe('pending');
|
|
89
|
-
expect(result.current.requests[0].subject.name).toBe('John Doe');
|
|
90
|
-
expect(result.current.requests[0].id).toBeDefined();
|
|
91
|
-
expect(result.current.requests[0].createdAt).toBeDefined();
|
|
92
|
-
expect(result.current.requests[0].updatedAt).toBeDefined();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should get a request by ID', () => {
|
|
96
|
-
const { result } = renderHook(() => useDSR({
|
|
97
|
-
requestTypes: mockRequestTypes,
|
|
98
|
-
storageKey: 'test-dsr',
|
|
99
|
-
useLocalStorage: true
|
|
100
|
-
}));
|
|
101
|
-
|
|
102
|
-
// Initialize requestId with a default value
|
|
103
|
-
let requestId: string = '';
|
|
104
|
-
|
|
105
|
-
act(() => {
|
|
106
|
-
const request = result.current.submitRequest({
|
|
107
|
-
type: 'access',
|
|
108
|
-
subject: {
|
|
109
|
-
name: 'John Doe',
|
|
110
|
-
email: 'john@example.com',
|
|
111
|
-
},
|
|
112
|
-
createdAt: Date.now(),
|
|
113
|
-
});
|
|
114
|
-
requestId = request.id;
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const retrievedRequest = result.current.getRequest(requestId);
|
|
118
|
-
expect(retrievedRequest).toBeDefined();
|
|
119
|
-
expect(retrievedRequest?.id).toBe(requestId);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should update a request', () => {
|
|
123
|
-
const { result } = renderHook(() => useDSR({
|
|
124
|
-
requestTypes: mockRequestTypes,
|
|
125
|
-
storageKey: 'test-dsr',
|
|
126
|
-
useLocalStorage: true
|
|
127
|
-
}));
|
|
128
|
-
|
|
129
|
-
let requestId = '';
|
|
130
|
-
|
|
131
|
-
act(() => {
|
|
132
|
-
const request = result.current.submitRequest({
|
|
133
|
-
type: 'access',
|
|
134
|
-
subject: {
|
|
135
|
-
name: 'John Doe',
|
|
136
|
-
email: 'john@example.com',
|
|
137
|
-
},
|
|
138
|
-
createdAt: Date.now(),
|
|
139
|
-
});
|
|
140
|
-
requestId = request.id;
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
act(() => {
|
|
144
|
-
result.current.updateRequest(requestId!, {
|
|
145
|
-
status: 'inProgress',
|
|
146
|
-
internalNotes: [
|
|
147
|
-
{
|
|
148
|
-
timestamp: Date.now(),
|
|
149
|
-
author: 'Admin',
|
|
150
|
-
note: 'Working on this request',
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const updatedRequest = result.current.getRequest(requestId!);
|
|
157
|
-
expect(updatedRequest?.status).toBe('inProgress');
|
|
158
|
-
expect(updatedRequest?.internalNotes?.length).toBe(1);
|
|
159
|
-
expect(updatedRequest?.internalNotes?.[0].author).toBe('Admin');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should clear all requests', () => {
|
|
163
|
-
const { result } = renderHook(() => useDSR({
|
|
164
|
-
requestTypes: mockRequestTypes,
|
|
165
|
-
storageKey: 'test-dsr',
|
|
166
|
-
useLocalStorage: true
|
|
167
|
-
}));
|
|
168
|
-
|
|
169
|
-
act(() => {
|
|
170
|
-
result.current.submitRequest({
|
|
171
|
-
type: 'access',
|
|
172
|
-
subject: {
|
|
173
|
-
name: 'John Doe',
|
|
174
|
-
email: 'john@example.com',
|
|
175
|
-
},
|
|
176
|
-
createdAt: Date.now(),
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
expect(result.current.requests.length).toBe(1);
|
|
181
|
-
|
|
182
|
-
act(() => {
|
|
183
|
-
result.current.clearRequests();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
expect(result.current.requests.length).toBe(0);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('should filter requests by type', () => {
|
|
190
|
-
const { result } = renderHook(() => useDSR({
|
|
191
|
-
requestTypes: mockRequestTypes,
|
|
192
|
-
storageKey: 'test-dsr',
|
|
193
|
-
useLocalStorage: true
|
|
194
|
-
}));
|
|
195
|
-
|
|
196
|
-
act(() => {
|
|
197
|
-
result.current.submitRequest({
|
|
198
|
-
type: 'access',
|
|
199
|
-
subject: {
|
|
200
|
-
name: 'John Doe',
|
|
201
|
-
email: 'john@example.com',
|
|
202
|
-
},
|
|
203
|
-
createdAt: Date.now(),
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
result.current.submitRequest({
|
|
207
|
-
type: 'erasure',
|
|
208
|
-
subject: {
|
|
209
|
-
name: 'Jane Smith',
|
|
210
|
-
email: 'jane@example.com',
|
|
211
|
-
},
|
|
212
|
-
createdAt: Date.now(),
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
result.current.submitRequest({
|
|
216
|
-
type: 'access',
|
|
217
|
-
subject: {
|
|
218
|
-
name: 'Bob Johnson',
|
|
219
|
-
email: 'bob@example.com',
|
|
220
|
-
},
|
|
221
|
-
createdAt: Date.now(),
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
const accessRequests = result.current.getRequestsByType('access');
|
|
226
|
-
expect(accessRequests.length).toBe(2);
|
|
227
|
-
expect(accessRequests[0].subject.name).toBe('John Doe');
|
|
228
|
-
expect(accessRequests[1].subject.name).toBe('Bob Johnson');
|
|
229
|
-
|
|
230
|
-
const erasureRequests = result.current.getRequestsByType('erasure');
|
|
231
|
-
expect(erasureRequests.length).toBe(1);
|
|
232
|
-
expect(erasureRequests[0].subject.name).toBe('Jane Smith');
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('should filter requests by status', () => {
|
|
236
|
-
const { result } = renderHook(() => useDSR({
|
|
237
|
-
requestTypes: mockRequestTypes,
|
|
238
|
-
storageKey: 'test-dsr',
|
|
239
|
-
useLocalStorage: true
|
|
240
|
-
}));
|
|
241
|
-
|
|
242
|
-
let requestId: string = '';
|
|
243
|
-
|
|
244
|
-
act(() => {
|
|
245
|
-
result.current.submitRequest({
|
|
246
|
-
type: 'access',
|
|
247
|
-
subject: {
|
|
248
|
-
name: 'John Doe',
|
|
249
|
-
email: 'john@example.com',
|
|
250
|
-
},
|
|
251
|
-
createdAt: Date.now(),
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
const request = result.current.submitRequest({
|
|
255
|
-
type: 'erasure',
|
|
256
|
-
subject: {
|
|
257
|
-
name: 'Jane Smith',
|
|
258
|
-
email: 'jane@example.com',
|
|
259
|
-
},
|
|
260
|
-
createdAt: Date.now(),
|
|
261
|
-
});
|
|
262
|
-
requestId = request.id;
|
|
263
|
-
|
|
264
|
-
result.current.submitRequest({
|
|
265
|
-
type: 'rectification',
|
|
266
|
-
subject: {
|
|
267
|
-
name: 'Bob Johnson',
|
|
268
|
-
email: 'bob@example.com',
|
|
269
|
-
},
|
|
270
|
-
createdAt: Date.now(),
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
act(() => {
|
|
275
|
-
result.current.updateRequest(requestId!, {
|
|
276
|
-
status: 'completed',
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
const pendingRequests = result.current.getRequestsByStatus('pending');
|
|
281
|
-
expect(pendingRequests.length).toBe(2);
|
|
282
|
-
|
|
283
|
-
const completedRequests = result.current.getRequestsByStatus('completed');
|
|
284
|
-
expect(completedRequests.length).toBe(1);
|
|
285
|
-
expect(completedRequests[0].subject.name).toBe('Jane Smith');
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
it('should format a request', () => {
|
|
289
|
-
const { result } = renderHook(() => useDSR({
|
|
290
|
-
requestTypes: mockRequestTypes,
|
|
291
|
-
storageKey: 'test-dsr',
|
|
292
|
-
useLocalStorage: true
|
|
293
|
-
}));
|
|
294
|
-
|
|
295
|
-
let request: DSRRequest | null = null;
|
|
296
|
-
|
|
297
|
-
act(() => {
|
|
298
|
-
request = result.current.submitRequest({
|
|
299
|
-
type: 'access',
|
|
300
|
-
subject: {
|
|
301
|
-
name: 'John Doe',
|
|
302
|
-
email: 'john@example.com',
|
|
303
|
-
},
|
|
304
|
-
createdAt: Date.now(),
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
expect(request).not.toBeNull();
|
|
309
|
-
|
|
310
|
-
if (request) {
|
|
311
|
-
const formattedRequest = result.current.formatRequest(request);
|
|
312
|
-
expect(formattedRequest).toBeDefined();
|
|
313
|
-
expect(formattedRequest.requestType).toBe('access');
|
|
314
|
-
expect(formattedRequest.dataSubject.name).toBe('John Doe');
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('should get request type by ID', () => {
|
|
319
|
-
const { result } = renderHook(() => useDSR({
|
|
320
|
-
requestTypes: mockRequestTypes,
|
|
321
|
-
storageKey: 'test-dsr',
|
|
322
|
-
useLocalStorage: true
|
|
323
|
-
}));
|
|
324
|
-
|
|
325
|
-
const requestType = result.current.getRequestType('access');
|
|
326
|
-
expect(requestType).toBeDefined();
|
|
327
|
-
expect(requestType?.name).toBe('Access Request');
|
|
328
|
-
expect(requestType?.estimatedCompletionTime).toBe(30);
|
|
329
|
-
});
|
|
330
|
-
});
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { calculateBreachSeverity } from '../../utils/breach';
|
|
2
|
-
import { BreachReport, RiskAssessment } from '../../types/breach';
|
|
3
|
-
|
|
4
|
-
describe('calculateBreachSeverity', () => {
|
|
5
|
-
const breachReport: BreachReport = {
|
|
6
|
-
id: 'breach-123',
|
|
7
|
-
title: 'Database Breach',
|
|
8
|
-
description: 'Unauthorized access to customer database',
|
|
9
|
-
category: 'unauthorized_access',
|
|
10
|
-
discoveredAt: 1620000000000,
|
|
11
|
-
occurredAt: 1619900000000,
|
|
12
|
-
reportedAt: 1620010000000,
|
|
13
|
-
reporter: {
|
|
14
|
-
name: 'John Smith',
|
|
15
|
-
email: 'john@example.com',
|
|
16
|
-
department: 'IT Security',
|
|
17
|
-
phone: '1234567890'
|
|
18
|
-
},
|
|
19
|
-
affectedSystems: ['customer-db', 'payment-system'],
|
|
20
|
-
dataTypes: ['personal', 'financial'],
|
|
21
|
-
estimatedAffectedSubjects: 1000,
|
|
22
|
-
status: 'contained'
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
it('should calculate high severity for sensitive data and large number of affected subjects', () => {
|
|
26
|
-
const assessment: RiskAssessment = {
|
|
27
|
-
id: 'risk-123',
|
|
28
|
-
breachId: 'breach-123',
|
|
29
|
-
assessor: {
|
|
30
|
-
name: 'John Doe',
|
|
31
|
-
role: 'DPO',
|
|
32
|
-
email: 'dpo@example.com'
|
|
33
|
-
},
|
|
34
|
-
assessedAt: 1620000000000,
|
|
35
|
-
confidentialityImpact: 4,
|
|
36
|
-
integrityImpact: 3,
|
|
37
|
-
availabilityImpact: 3,
|
|
38
|
-
harmLikelihood: 4,
|
|
39
|
-
harmSeverity: 4,
|
|
40
|
-
overallRiskScore: 16,
|
|
41
|
-
riskLevel: 'high',
|
|
42
|
-
risksToRightsAndFreedoms: true,
|
|
43
|
-
highRisksToRightsAndFreedoms: true,
|
|
44
|
-
justification: 'High risk due to sensitive financial data'
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const result = calculateBreachSeverity(breachReport, assessment);
|
|
48
|
-
|
|
49
|
-
expect(result.severityLevel).toBe('high');
|
|
50
|
-
expect(result.notificationRequired).toBe(true);
|
|
51
|
-
expect(result.urgentNotificationRequired).toBe(true);
|
|
52
|
-
expect(result.timeframeHours).toBe(72);
|
|
53
|
-
expect(result.justification).toBe('High risk due to sensitive financial data');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should calculate medium severity for non-sensitive data with medium impact', () => {
|
|
57
|
-
const assessment: RiskAssessment = {
|
|
58
|
-
id: 'risk-456',
|
|
59
|
-
breachId: 'breach-456',
|
|
60
|
-
assessor: {
|
|
61
|
-
name: 'Jane Smith',
|
|
62
|
-
role: 'Security Officer',
|
|
63
|
-
email: 'security@example.com'
|
|
64
|
-
},
|
|
65
|
-
assessedAt: 1620100000000,
|
|
66
|
-
confidentialityImpact: 3,
|
|
67
|
-
integrityImpact: 2,
|
|
68
|
-
availabilityImpact: 2,
|
|
69
|
-
harmLikelihood: 3,
|
|
70
|
-
harmSeverity: 3,
|
|
71
|
-
overallRiskScore: 9,
|
|
72
|
-
riskLevel: 'medium',
|
|
73
|
-
risksToRightsAndFreedoms: true,
|
|
74
|
-
highRisksToRightsAndFreedoms: false,
|
|
75
|
-
justification: 'Medium risk due to personal data exposure'
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const result = calculateBreachSeverity(breachReport, assessment);
|
|
79
|
-
|
|
80
|
-
expect(result.severityLevel).toBe('medium');
|
|
81
|
-
expect(result.notificationRequired).toBe(true);
|
|
82
|
-
expect(result.urgentNotificationRequired).toBe(false);
|
|
83
|
-
expect(result.timeframeHours).toBe(72);
|
|
84
|
-
expect(result.justification).toBe('Medium risk due to personal data exposure');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should calculate low severity for contained breach with low impact', () => {
|
|
88
|
-
const assessment: RiskAssessment = {
|
|
89
|
-
id: 'risk-789',
|
|
90
|
-
breachId: 'breach-789',
|
|
91
|
-
assessor: {
|
|
92
|
-
name: 'Alex Johnson',
|
|
93
|
-
role: 'Compliance Manager',
|
|
94
|
-
email: 'compliance@example.com'
|
|
95
|
-
},
|
|
96
|
-
assessedAt: 1620200000000,
|
|
97
|
-
confidentialityImpact: 1,
|
|
98
|
-
integrityImpact: 1,
|
|
99
|
-
availabilityImpact: 2,
|
|
100
|
-
harmLikelihood: 2,
|
|
101
|
-
harmSeverity: 1,
|
|
102
|
-
overallRiskScore: 2,
|
|
103
|
-
riskLevel: 'low',
|
|
104
|
-
risksToRightsAndFreedoms: false,
|
|
105
|
-
highRisksToRightsAndFreedoms: false,
|
|
106
|
-
justification: 'Low risk due to minimal data exposure'
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const result = calculateBreachSeverity(breachReport, assessment);
|
|
110
|
-
|
|
111
|
-
expect(result.severityLevel).toBe('low');
|
|
112
|
-
expect(result.notificationRequired).toBe(false);
|
|
113
|
-
expect(result.urgentNotificationRequired).toBe(false);
|
|
114
|
-
expect(result.timeframeHours).toBe(72);
|
|
115
|
-
expect(result.justification).toBe('Low risk due to minimal data exposure');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should calculate severity based on breach report when no assessment is provided', () => {
|
|
119
|
-
// Create a breach report with sensitive data and large scale
|
|
120
|
-
const sensitiveBreachReport: BreachReport = {
|
|
121
|
-
...breachReport,
|
|
122
|
-
dataTypes: ['personal', 'financial', 'health'],
|
|
123
|
-
estimatedAffectedSubjects: 5000,
|
|
124
|
-
status: 'ongoing'
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const result = calculateBreachSeverity(sensitiveBreachReport);
|
|
128
|
-
|
|
129
|
-
// With 3 severity factors (sensitive data, large scale, ongoing), it should be critical
|
|
130
|
-
expect(result.severityLevel).toBe('critical');
|
|
131
|
-
expect(result.notificationRequired).toBe(true);
|
|
132
|
-
expect(result.urgentNotificationRequired).toBe(true);
|
|
133
|
-
expect(result.timeframeHours).toBe(72);
|
|
134
|
-
expect(result.justification).toContain('Critical risk');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should always require notification for ongoing breaches', () => {
|
|
138
|
-
const ongoingBreachReport: BreachReport = {
|
|
139
|
-
...breachReport,
|
|
140
|
-
status: 'ongoing',
|
|
141
|
-
dataTypes: ['personal']
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const result = calculateBreachSeverity(ongoingBreachReport);
|
|
145
|
-
|
|
146
|
-
expect(result.notificationRequired).toBe(true);
|
|
147
|
-
expect(result.justification).toContain('Medium risk');
|
|
148
|
-
});
|
|
149
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { validateConsent } from '../../utils/consent';
|
|
2
|
-
import { ConsentSettings } from '../../types/consent';
|
|
3
|
-
|
|
4
|
-
describe('validateConsent', () => {
|
|
5
|
-
it('should validate valid consent settings', () => {
|
|
6
|
-
const settings: ConsentSettings = {
|
|
7
|
-
consents: {
|
|
8
|
-
necessary: true,
|
|
9
|
-
analytics: false,
|
|
10
|
-
marketing: true
|
|
11
|
-
},
|
|
12
|
-
timestamp: Date.now(),
|
|
13
|
-
version: '1.0',
|
|
14
|
-
method: 'banner',
|
|
15
|
-
hasInteracted: true
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const result = validateConsent(settings);
|
|
19
|
-
expect(result.valid).toBe(true);
|
|
20
|
-
expect(result.errors).toEqual([]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should invalidate settings with missing consents', () => {
|
|
24
|
-
const settings: ConsentSettings = {
|
|
25
|
-
consents: {},
|
|
26
|
-
timestamp: Date.now(),
|
|
27
|
-
version: '1.0',
|
|
28
|
-
method: 'banner',
|
|
29
|
-
hasInteracted: true
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const result = validateConsent(settings);
|
|
33
|
-
expect(result.valid).toBe(false);
|
|
34
|
-
expect(result.errors).toContain('Consent settings must include at least one consent option');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should invalidate settings with missing timestamp', () => {
|
|
38
|
-
const settings = {
|
|
39
|
-
consents: { necessary: true },
|
|
40
|
-
version: '1.0',
|
|
41
|
-
method: 'banner',
|
|
42
|
-
hasInteracted: true
|
|
43
|
-
} as unknown as ConsentSettings;
|
|
44
|
-
|
|
45
|
-
const result = validateConsent(settings);
|
|
46
|
-
expect(result.valid).toBe(false);
|
|
47
|
-
expect(result.errors).toContain('Consent timestamp is required');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should invalidate settings with missing version', () => {
|
|
51
|
-
const settings = {
|
|
52
|
-
consents: { necessary: true },
|
|
53
|
-
timestamp: Date.now(),
|
|
54
|
-
method: 'banner',
|
|
55
|
-
hasInteracted: true
|
|
56
|
-
} as unknown as ConsentSettings;
|
|
57
|
-
|
|
58
|
-
const result = validateConsent(settings);
|
|
59
|
-
expect(result.valid).toBe(false);
|
|
60
|
-
expect(result.errors).toContain('Consent version is required');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should invalidate settings with missing method', () => {
|
|
64
|
-
const settings = {
|
|
65
|
-
consents: { necessary: true },
|
|
66
|
-
timestamp: Date.now(),
|
|
67
|
-
version: '1.0',
|
|
68
|
-
hasInteracted: true
|
|
69
|
-
} as unknown as ConsentSettings;
|
|
70
|
-
|
|
71
|
-
const result = validateConsent(settings);
|
|
72
|
-
expect(result.valid).toBe(false);
|
|
73
|
-
expect(result.errors).toContain('Consent collection method is required');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should invalidate settings with missing hasInteracted', () => {
|
|
77
|
-
const settings = {
|
|
78
|
-
consents: { necessary: true },
|
|
79
|
-
timestamp: Date.now(),
|
|
80
|
-
version: '1.0',
|
|
81
|
-
method: 'banner'
|
|
82
|
-
} as unknown as ConsentSettings;
|
|
83
|
-
|
|
84
|
-
const result = validateConsent(settings);
|
|
85
|
-
expect(result.valid).toBe(false);
|
|
86
|
-
expect(result.errors).toContain('User interaction status is required');
|
|
87
|
-
});
|
|
88
|
-
});
|