@tantainnovative/ndpr-toolkit 1.0.2 → 1.0.3
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/.claude/settings.local.json +20 -0
- package/.eslintrc.json +10 -0
- package/.github/workflows/ci.yml +36 -0
- package/.github/workflows/nextjs.yml +104 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.lintstagedrc.js +4 -0
- package/.nvmrc +1 -0
- package/.versionrc +17 -0
- package/CHANGELOG.md +16 -0
- package/CLAUDE.md +90 -0
- package/CNAME +1 -0
- package/CONTRIBUTING.md +87 -0
- package/README.md +84 -447
- package/RELEASE-NOTES-v1.0.0.md +140 -0
- package/RELEASE-NOTES-v1.0.1.md +69 -0
- package/SECURITY.md +21 -0
- package/commitlint.config.js +36 -0
- package/components.json +21 -0
- package/eslint.config.mjs +16 -0
- package/jest.config.js +31 -0
- package/jest.setup.js +15 -0
- package/next.config.js +15 -0
- package/next.config.ts +62 -0
- package/package.json +70 -52
- package/packages/ndpr-toolkit/README.md +467 -0
- package/packages/ndpr-toolkit/jest.config.js +23 -0
- package/packages/ndpr-toolkit/package-lock.json +8197 -0
- package/packages/ndpr-toolkit/package.json +71 -0
- package/packages/ndpr-toolkit/rollup.config.js +34 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +119 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +122 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +270 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +199 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +224 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +104 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +161 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +330 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +149 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +88 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +160 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +110 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +97 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +701 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +631 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +569 -0
- package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +496 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +270 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +217 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +206 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +342 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +373 -0
- package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +174 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +717 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +476 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +620 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +541 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +454 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +333 -0
- package/packages/ndpr-toolkit/src/hooks/useBreach.ts +409 -0
- package/packages/ndpr-toolkit/src/hooks/useConsent.ts +263 -0
- package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +457 -0
- package/packages/ndpr-toolkit/src/hooks/useDSR.ts +236 -0
- package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +428 -0
- package/{dist/index.d.ts → packages/ndpr-toolkit/src/index.ts} +13 -0
- package/packages/ndpr-toolkit/src/setupTests.ts +5 -0
- package/packages/ndpr-toolkit/src/types/breach.ts +283 -0
- package/packages/ndpr-toolkit/src/types/consent.ts +111 -0
- package/packages/ndpr-toolkit/src/types/dpia.ts +236 -0
- package/packages/ndpr-toolkit/src/types/dsr.ts +192 -0
- package/packages/ndpr-toolkit/src/types/index.ts +42 -0
- package/packages/ndpr-toolkit/src/types/privacy.ts +246 -0
- package/packages/ndpr-toolkit/src/utils/breach.ts +122 -0
- package/packages/ndpr-toolkit/src/utils/consent.ts +51 -0
- package/packages/ndpr-toolkit/src/utils/dpia.ts +104 -0
- package/packages/ndpr-toolkit/src/utils/dsr.ts +77 -0
- package/packages/ndpr-toolkit/src/utils/privacy.ts +100 -0
- package/packages/ndpr-toolkit/tsconfig.json +23 -0
- package/postcss.config.mjs +5 -0
- package/public/NDPR TOOLKIT.svg +1 -0
- package/public/favicon/android-chrome-192x192.png +0 -0
- package/public/favicon/android-chrome-512x512.png +0 -0
- package/public/favicon/apple-touch-icon.png +0 -0
- package/public/favicon/favicon-16x16.png +0 -0
- package/public/favicon/favicon-32x32.png +0 -0
- package/public/favicon/site.webmanifest +1 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/ndpr-toolkit-logo.svg +108 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/__tests__/example.test.ts +13 -0
- package/src/__tests__/requestService.test.ts +57 -0
- package/src/app/accessibility.css +70 -0
- package/src/app/docs/components/DocLayout.tsx +267 -0
- package/src/app/docs/components/breach-notification/page.tsx +797 -0
- package/src/app/docs/components/consent-management/page.tsx +576 -0
- package/src/app/docs/components/data-subject-rights/page.tsx +511 -0
- package/src/app/docs/components/dpia-questionnaire/layout.tsx +15 -0
- package/src/app/docs/components/dpia-questionnaire/metadata.ts +31 -0
- package/src/app/docs/components/dpia-questionnaire/page.tsx +666 -0
- package/src/app/docs/components/hooks/page.tsx +305 -0
- package/src/app/docs/components/page.tsx +84 -0
- package/src/app/docs/components/privacy-policy-generator/page.tsx +634 -0
- package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +123 -0
- package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +328 -0
- package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +28 -0
- package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +91 -0
- package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +118 -0
- package/src/app/docs/guides/breach-notification-process/page.tsx +39 -0
- package/src/app/docs/guides/conducting-dpia/page.tsx +593 -0
- package/src/app/docs/guides/data-subject-requests/page.tsx +666 -0
- package/src/app/docs/guides/managing-consent/page.tsx +738 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +296 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +145 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +33 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +99 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +159 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +38 -0
- package/src/app/docs/guides/page.tsx +67 -0
- package/src/app/docs/layout.tsx +15 -0
- package/src/app/docs/metadata.ts +31 -0
- package/src/app/docs/page.tsx +572 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +123 -0
- package/src/app/layout.tsx +37 -0
- package/src/app/ndpr-demos/breach/page.tsx +354 -0
- package/src/app/ndpr-demos/consent/page.tsx +366 -0
- package/src/app/ndpr-demos/dpia/page.tsx +495 -0
- package/src/app/ndpr-demos/dsr/page.tsx +280 -0
- package/src/app/ndpr-demos/page.tsx +73 -0
- package/src/app/ndpr-demos/policy/page.tsx +771 -0
- package/src/app/page.tsx +452 -0
- package/src/components/ErrorBoundary.tsx +90 -0
- package/src/components/breach-notification/BreachNotificationForm.tsx +479 -0
- package/src/components/consent/ConsentBanner.tsx +159 -0
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +419 -0
- package/src/components/docs/DocLayout.tsx +289 -0
- package/src/components/docs/index.ts +2 -0
- package/src/components/dpia/DPIAQuestionnaire.tsx +483 -0
- package/src/components/privacy-policy/PolicyGenerator.tsx +1062 -0
- package/src/components/privacy-policy/data.ts +98 -0
- package/src/components/privacy-policy/shared/CheckboxField.tsx +38 -0
- package/src/components/privacy-policy/shared/CheckboxGroup.tsx +85 -0
- package/src/components/privacy-policy/shared/FormField.tsx +79 -0
- package/src/components/privacy-policy/shared/StepIndicator.tsx +86 -0
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +335 -0
- package/src/components/privacy-policy/steps/DataCollectionStep.tsx +231 -0
- package/src/components/privacy-policy/steps/DataSharingStep.tsx +418 -0
- package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +202 -0
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +172 -0
- package/src/components/ui/Badge.tsx +46 -0
- package/src/components/ui/Button.tsx +59 -0
- package/src/components/ui/Card.tsx +92 -0
- package/src/components/ui/Checkbox.tsx +57 -0
- package/src/components/ui/FormField.tsx +50 -0
- package/src/components/ui/Input.tsx +38 -0
- package/src/components/ui/Loading.tsx +201 -0
- package/src/components/ui/Select.tsx +42 -0
- package/src/components/ui/TextArea.tsx +38 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/tabs.tsx +66 -0
- package/src/hooks/useConsent.ts +64 -0
- package/src/hooks/useLoadingState.ts +85 -0
- package/src/lib/consentService.ts +137 -0
- package/src/lib/dpiaQuestions.ts +148 -0
- package/src/lib/requestService.ts +75 -0
- package/src/lib/sanitize.ts +108 -0
- package/src/lib/storage.ts +222 -0
- package/src/lib/utils.ts +6 -0
- package/src/types/html-to-docx.d.ts +30 -0
- package/src/types/index.ts +72 -0
- package/tailwind.config.ts +65 -0
- package/tsconfig.json +41 -0
- package/dist/components/breach/BreachNotificationManager.d.ts +0 -62
- package/dist/components/breach/BreachReportForm.d.ts +0 -66
- package/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
- package/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
- package/dist/components/consent/ConsentBanner.d.ts +0 -79
- package/dist/components/consent/ConsentManager.d.ts +0 -73
- package/dist/components/consent/ConsentStorage.d.ts +0 -41
- package/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
- package/dist/components/dpia/DPIAReport.d.ts +0 -40
- package/dist/components/dpia/StepIndicator.d.ts +0 -64
- package/dist/components/dsr/DSRDashboard.d.ts +0 -58
- package/dist/components/dsr/DSRRequestForm.d.ts +0 -74
- package/dist/components/dsr/DSRTracker.d.ts +0 -56
- package/dist/components/policy/PolicyExporter.d.ts +0 -65
- package/dist/components/policy/PolicyGenerator.d.ts +0 -54
- package/dist/components/policy/PolicyPreview.d.ts +0 -71
- package/dist/hooks/useBreach.d.ts +0 -97
- package/dist/hooks/useConsent.d.ts +0 -63
- package/dist/hooks/useDPIA.d.ts +0 -92
- package/dist/hooks/useDSR.d.ts +0 -72
- package/dist/hooks/usePrivacyPolicy.d.ts +0 -87
- package/dist/index.esm.js +0 -2
- package/dist/index.esm.js.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/setupTests.d.ts +0 -2
- package/dist/types/breach.d.ts +0 -239
- package/dist/types/consent.d.ts +0 -95
- package/dist/types/dpia.d.ts +0 -196
- package/dist/types/dsr.d.ts +0 -162
- package/dist/types/privacy.d.ts +0 -204
- package/dist/utils/breach.d.ts +0 -14
- package/dist/utils/consent.d.ts +0 -10
- package/dist/utils/dpia.d.ts +0 -12
- package/dist/utils/dsr.d.ts +0 -11
- package/dist/utils/privacy.d.ts +0 -12
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { assessDPIARisk } from '../../utils/dpia';
|
|
2
|
+
import { DPIAResult, DPIARisk } from '../../types/dpia';
|
|
3
|
+
|
|
4
|
+
describe('assessDPIARisk', () => {
|
|
5
|
+
it('should correctly assess risk based on high risk data', () => {
|
|
6
|
+
// Create a DPIA result with high risks
|
|
7
|
+
const dpiaResult: DPIAResult = {
|
|
8
|
+
id: '123',
|
|
9
|
+
title: 'Test DPIA',
|
|
10
|
+
processingDescription: 'Processing sensitive customer data',
|
|
11
|
+
startedAt: Date.now(),
|
|
12
|
+
assessor: {
|
|
13
|
+
name: 'John Doe',
|
|
14
|
+
role: 'DPO',
|
|
15
|
+
email: 'john@example.com'
|
|
16
|
+
},
|
|
17
|
+
answers: {
|
|
18
|
+
q1: 'yes',
|
|
19
|
+
q2: 'large'
|
|
20
|
+
},
|
|
21
|
+
risks: [
|
|
22
|
+
{
|
|
23
|
+
id: 'risk_1',
|
|
24
|
+
description: 'Processing involves sensitive personal data',
|
|
25
|
+
likelihood: 5,
|
|
26
|
+
impact: 5,
|
|
27
|
+
score: 25,
|
|
28
|
+
level: 'high',
|
|
29
|
+
mitigated: false,
|
|
30
|
+
relatedQuestionIds: ['q1']
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'risk_2',
|
|
34
|
+
description: 'Large volume of data being processed',
|
|
35
|
+
likelihood: 5,
|
|
36
|
+
impact: 5,
|
|
37
|
+
score: 25,
|
|
38
|
+
level: 'high',
|
|
39
|
+
mitigated: false,
|
|
40
|
+
relatedQuestionIds: ['q2']
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'risk_3',
|
|
44
|
+
description: 'Another high risk factor',
|
|
45
|
+
likelihood: 5,
|
|
46
|
+
impact: 5,
|
|
47
|
+
score: 25,
|
|
48
|
+
level: 'high',
|
|
49
|
+
mitigated: false,
|
|
50
|
+
relatedQuestionIds: ['q3']
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
overallRiskLevel: 'low', // Will be updated by the function
|
|
54
|
+
canProceed: true, // Will be updated by the function
|
|
55
|
+
conclusion: 'Initial conclusion',
|
|
56
|
+
version: '1.0'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const result = assessDPIARisk(dpiaResult);
|
|
60
|
+
|
|
61
|
+
expect(result.overallRiskLevel).toBe('high');
|
|
62
|
+
expect(result.requiresConsultation).toBe(true);
|
|
63
|
+
expect(result.canProceed).toBe(false);
|
|
64
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should handle medium risk levels', () => {
|
|
68
|
+
// Create a DPIA result with medium risks
|
|
69
|
+
const dpiaResult: DPIAResult = {
|
|
70
|
+
id: '456',
|
|
71
|
+
title: 'Test DPIA',
|
|
72
|
+
processingDescription: 'Processing customer data',
|
|
73
|
+
startedAt: Date.now(),
|
|
74
|
+
assessor: {
|
|
75
|
+
name: 'Jane Smith',
|
|
76
|
+
role: 'Privacy Officer',
|
|
77
|
+
email: 'jane@example.com'
|
|
78
|
+
},
|
|
79
|
+
answers: {
|
|
80
|
+
q1: 'no',
|
|
81
|
+
q2: 'medium'
|
|
82
|
+
},
|
|
83
|
+
risks: [
|
|
84
|
+
{
|
|
85
|
+
id: 'risk_1',
|
|
86
|
+
description: 'Medium volume of data being processed',
|
|
87
|
+
likelihood: 3,
|
|
88
|
+
impact: 3,
|
|
89
|
+
score: 9,
|
|
90
|
+
level: 'medium',
|
|
91
|
+
mitigated: false,
|
|
92
|
+
relatedQuestionIds: ['q2']
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'risk_2',
|
|
96
|
+
description: 'Another medium risk factor',
|
|
97
|
+
likelihood: 3,
|
|
98
|
+
impact: 3,
|
|
99
|
+
score: 9,
|
|
100
|
+
level: 'medium',
|
|
101
|
+
mitigated: false,
|
|
102
|
+
relatedQuestionIds: ['q3']
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
overallRiskLevel: 'low', // Will be updated by the function
|
|
106
|
+
canProceed: true, // Will be updated by the function
|
|
107
|
+
conclusion: 'Initial conclusion',
|
|
108
|
+
version: '1.0'
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const result = assessDPIARisk(dpiaResult);
|
|
112
|
+
|
|
113
|
+
expect(result.overallRiskLevel).toBe('medium');
|
|
114
|
+
expect(result.requiresConsultation).toBe(false);
|
|
115
|
+
expect(result.canProceed).toBe(true);
|
|
116
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle low risk levels', () => {
|
|
120
|
+
// Create a DPIA result with no significant risks
|
|
121
|
+
const dpiaResult: DPIAResult = {
|
|
122
|
+
id: '789',
|
|
123
|
+
title: 'Test DPIA',
|
|
124
|
+
processingDescription: 'Processing minimal customer data',
|
|
125
|
+
startedAt: Date.now(),
|
|
126
|
+
assessor: {
|
|
127
|
+
name: 'Alex Johnson',
|
|
128
|
+
role: 'Compliance Manager',
|
|
129
|
+
email: 'alex@example.com'
|
|
130
|
+
},
|
|
131
|
+
answers: {
|
|
132
|
+
q1: 'Marketing purposes',
|
|
133
|
+
q2: 'small'
|
|
134
|
+
},
|
|
135
|
+
risks: [
|
|
136
|
+
{
|
|
137
|
+
id: 'risk_1',
|
|
138
|
+
description: 'Small volume of data being processed',
|
|
139
|
+
likelihood: 1,
|
|
140
|
+
impact: 1,
|
|
141
|
+
score: 1,
|
|
142
|
+
level: 'low',
|
|
143
|
+
mitigated: true,
|
|
144
|
+
relatedQuestionIds: ['q2']
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
overallRiskLevel: 'low', // Will be updated by the function
|
|
148
|
+
canProceed: true, // Will be updated by the function
|
|
149
|
+
conclusion: 'Initial conclusion',
|
|
150
|
+
version: '1.0'
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const result = assessDPIARisk(dpiaResult);
|
|
154
|
+
|
|
155
|
+
expect(result.overallRiskLevel).toBe('low');
|
|
156
|
+
expect(result.requiresConsultation).toBe(false);
|
|
157
|
+
expect(result.canProceed).toBe(true);
|
|
158
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { formatDSRRequest } from '../../utils/dsr';
|
|
2
|
+
import { DSRRequest, DSRType, DSRStatus } from '../../types/dsr';
|
|
3
|
+
|
|
4
|
+
describe('formatDSRRequest', () => {
|
|
5
|
+
it('should format a DSR request correctly', () => {
|
|
6
|
+
const request: DSRRequest = {
|
|
7
|
+
id: '123',
|
|
8
|
+
type: 'access',
|
|
9
|
+
status: 'pending',
|
|
10
|
+
createdAt: 1620000000000,
|
|
11
|
+
updatedAt: 1620000000000,
|
|
12
|
+
subject: {
|
|
13
|
+
name: 'John Doe',
|
|
14
|
+
email: 'john@example.com',
|
|
15
|
+
phone: '1234567890'
|
|
16
|
+
},
|
|
17
|
+
description: 'I want to access my data'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const result = formatDSRRequest(request);
|
|
21
|
+
|
|
22
|
+
expect(result.isValid).toBe(true);
|
|
23
|
+
expect(result.formattedRequest.dataSubject.name).toBe('John Doe');
|
|
24
|
+
expect(result.formattedRequest.requestType).toBe('access');
|
|
25
|
+
expect(result.formattedRequest.status).toBe('pending');
|
|
26
|
+
expect(result.formattedRequest.dataSubject.email).toBe('john@example.com');
|
|
27
|
+
expect(result.formattedRequest.additionalInformation).toEqual({});
|
|
28
|
+
expect(result.validationErrors.length).toBe(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should handle missing optional fields', () => {
|
|
32
|
+
const request: DSRRequest = {
|
|
33
|
+
id: '456',
|
|
34
|
+
type: 'erasure',
|
|
35
|
+
status: 'completed',
|
|
36
|
+
createdAt: 1620000000000,
|
|
37
|
+
updatedAt: 1620100000000,
|
|
38
|
+
completedAt: 1620200000000,
|
|
39
|
+
subject: {
|
|
40
|
+
name: 'Jane Smith',
|
|
41
|
+
email: 'jane@example.com'
|
|
42
|
+
// phone is missing
|
|
43
|
+
}
|
|
44
|
+
// description is missing
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const result = formatDSRRequest(request);
|
|
48
|
+
|
|
49
|
+
expect(result.isValid).toBe(true);
|
|
50
|
+
expect(result.formattedRequest.dataSubject.name).toBe('Jane Smith');
|
|
51
|
+
expect(result.formattedRequest.requestType).toBe('erasure');
|
|
52
|
+
expect(result.formattedRequest.status).toBe('completed');
|
|
53
|
+
expect(result.formattedRequest.dataSubject.email).toBe('jane@example.com');
|
|
54
|
+
expect(result.formattedRequest.dataSubject.phone).toBe('Not provided');
|
|
55
|
+
expect(JSON.stringify(result.formattedRequest)).not.toContain('undefined');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should include completion date when available', () => {
|
|
59
|
+
const request: DSRRequest = {
|
|
60
|
+
id: '789',
|
|
61
|
+
type: 'rectification',
|
|
62
|
+
status: 'completed',
|
|
63
|
+
createdAt: 1620000000000,
|
|
64
|
+
updatedAt: 1620100000000,
|
|
65
|
+
completedAt: 1620200000000,
|
|
66
|
+
subject: {
|
|
67
|
+
name: 'Bob Johnson',
|
|
68
|
+
email: 'bob@example.com'
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const result = formatDSRRequest(request);
|
|
73
|
+
|
|
74
|
+
expect(result.isValid).toBe(true);
|
|
75
|
+
// Check that the completedAt date is properly formatted in ISO format
|
|
76
|
+
expect(result.formattedRequest.lastUpdated).toBe(new Date(1620100000000).toISOString());
|
|
77
|
+
expect(result.formattedRequest.dataSubject.name).toBe('Bob Johnson');
|
|
78
|
+
expect(result.formattedRequest.requestType).toBe('rectification');
|
|
79
|
+
expect(result.formattedRequest.status).toBe('completed');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should handle additional info when present', () => {
|
|
83
|
+
const request: DSRRequest = {
|
|
84
|
+
id: '101',
|
|
85
|
+
type: 'portability',
|
|
86
|
+
status: 'inProgress',
|
|
87
|
+
createdAt: 1620000000000,
|
|
88
|
+
updatedAt: 1620100000000,
|
|
89
|
+
subject: {
|
|
90
|
+
name: 'Alice Brown',
|
|
91
|
+
email: 'alice@example.com'
|
|
92
|
+
},
|
|
93
|
+
additionalInfo: {
|
|
94
|
+
format: 'CSV',
|
|
95
|
+
timeRange: 'Last 12 months'
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const result = formatDSRRequest(request);
|
|
100
|
+
|
|
101
|
+
expect(result.isValid).toBe(true);
|
|
102
|
+
expect(result.formattedRequest.dataSubject.name).toBe('Alice Brown');
|
|
103
|
+
expect(result.formattedRequest.requestType).toBe('portability');
|
|
104
|
+
expect(result.formattedRequest.status).toBe('inProgress');
|
|
105
|
+
expect(result.formattedRequest.additionalInformation).toEqual({
|
|
106
|
+
format: 'CSV',
|
|
107
|
+
timeRange: 'Last 12 months'
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { generatePolicyText } from '../../utils/privacy';
|
|
2
|
+
import { PolicySection } from '../../types/privacy';
|
|
3
|
+
|
|
4
|
+
describe('generatePolicyText', () => {
|
|
5
|
+
it('should replace variables in templates', () => {
|
|
6
|
+
const sections: PolicySection[] = [
|
|
7
|
+
{
|
|
8
|
+
id: 'introduction',
|
|
9
|
+
title: 'Introduction',
|
|
10
|
+
template: 'This Privacy Policy explains how {{organizationName}} collects and uses your data.',
|
|
11
|
+
required: true,
|
|
12
|
+
included: true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'contact',
|
|
16
|
+
title: 'Contact Information',
|
|
17
|
+
template: 'For questions about this policy, please contact us at {{contactEmail}}.',
|
|
18
|
+
required: true,
|
|
19
|
+
included: true
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const variables = {
|
|
24
|
+
organizationName: 'Acme Corporation',
|
|
25
|
+
contactEmail: 'privacy@acme.com'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const result = generatePolicyText(sections, variables) as {
|
|
29
|
+
fullText: string;
|
|
30
|
+
sectionTexts: Record<string, string>;
|
|
31
|
+
missingVariables: string[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
expect(result.fullText).toContain('This Privacy Policy explains how Acme Corporation collects and uses your data.');
|
|
35
|
+
expect(result.fullText).toContain('For questions about this policy, please contact us at privacy@acme.com.');
|
|
36
|
+
// Check the number of sections by counting keys in sectionTexts
|
|
37
|
+
expect(Object.keys(result.sectionTexts).length).toBe(2);
|
|
38
|
+
// Check the content of the first section
|
|
39
|
+
expect(Object.values(result.sectionTexts)[0]).toBe('This Privacy Policy explains how Acme Corporation collects and uses your data.');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should skip sections that are not included', () => {
|
|
43
|
+
const sections: PolicySection[] = [
|
|
44
|
+
{
|
|
45
|
+
id: 'introduction',
|
|
46
|
+
title: 'Introduction',
|
|
47
|
+
template: 'This is the introduction.',
|
|
48
|
+
required: true,
|
|
49
|
+
included: true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'optional',
|
|
53
|
+
title: 'Optional Section',
|
|
54
|
+
template: 'This is optional.',
|
|
55
|
+
required: false,
|
|
56
|
+
included: false
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const result = generatePolicyText(sections, {}) as {
|
|
61
|
+
fullText: string;
|
|
62
|
+
sectionTexts: Record<string, string>;
|
|
63
|
+
missingVariables: string[];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
expect(result.fullText).toContain('This is the introduction.');
|
|
67
|
+
expect(result.fullText).not.toContain('This is optional.');
|
|
68
|
+
expect(Object.keys(result.sectionTexts).length).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should handle missing variables gracefully', () => {
|
|
72
|
+
const sections: PolicySection[] = [
|
|
73
|
+
{
|
|
74
|
+
id: 'test',
|
|
75
|
+
title: 'Test',
|
|
76
|
+
template: 'Hello {{name}}, welcome to {{company}}.',
|
|
77
|
+
required: true,
|
|
78
|
+
included: true
|
|
79
|
+
}
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const variables = {
|
|
83
|
+
name: 'John'
|
|
84
|
+
// company is missing
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const result = generatePolicyText(sections, variables) as {
|
|
88
|
+
fullText: string;
|
|
89
|
+
sectionTexts: Record<string, string>;
|
|
90
|
+
missingVariables: string[];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
expect(result.fullText).toContain('Hello John, welcome to .');
|
|
94
|
+
// Verify that 'company' is in the missing variables list
|
|
95
|
+
expect(result.missingVariables).toContain('company');
|
|
96
|
+
});
|
|
97
|
+
});
|