@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,199 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import { DSRDashboard } from '../../../components/dsr/DSRDashboard';
|
|
4
|
-
import { DSRRequest } from '../../../types/dsr';
|
|
5
|
-
|
|
6
|
-
describe('DSRDashboard', () => {
|
|
7
|
-
const mockRequests: DSRRequest[] = [
|
|
8
|
-
{
|
|
9
|
-
id: '1',
|
|
10
|
-
type: 'access',
|
|
11
|
-
status: 'pending',
|
|
12
|
-
createdAt: 1620000000000,
|
|
13
|
-
updatedAt: 1620000000000,
|
|
14
|
-
subject: {
|
|
15
|
-
name: 'John Doe',
|
|
16
|
-
email: 'john@example.com',
|
|
17
|
-
phone: '1234567890'
|
|
18
|
-
},
|
|
19
|
-
description: 'I want to access my data'
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
id: '2',
|
|
23
|
-
type: 'erasure',
|
|
24
|
-
status: 'inProgress',
|
|
25
|
-
createdAt: 1620100000000,
|
|
26
|
-
updatedAt: 1620100000000,
|
|
27
|
-
subject: {
|
|
28
|
-
name: 'Jane Smith',
|
|
29
|
-
email: 'jane@example.com'
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
id: '3',
|
|
34
|
-
type: 'rectification',
|
|
35
|
-
status: 'completed',
|
|
36
|
-
createdAt: 1620200000000,
|
|
37
|
-
updatedAt: 1620300000000,
|
|
38
|
-
completedAt: 1620300000000,
|
|
39
|
-
subject: {
|
|
40
|
-
name: 'Bob Johnson',
|
|
41
|
-
email: 'bob@example.com'
|
|
42
|
-
},
|
|
43
|
-
description: 'Please correct my address'
|
|
44
|
-
}
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
const mockUpdateRequest = jest.fn();
|
|
48
|
-
const mockDeleteRequest = jest.fn();
|
|
49
|
-
|
|
50
|
-
beforeEach(() => {
|
|
51
|
-
mockUpdateRequest.mockClear();
|
|
52
|
-
mockDeleteRequest.mockClear();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('renders the dashboard with requests', () => {
|
|
56
|
-
render(
|
|
57
|
-
<DSRDashboard
|
|
58
|
-
requests={mockRequests}
|
|
59
|
-
onUpdateStatus={mockUpdateRequest}
|
|
60
|
-
onSelectRequest={mockDeleteRequest}
|
|
61
|
-
/>
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
// Check that the dashboard title is rendered
|
|
65
|
-
expect(screen.getByText(/Data Subject Request Dashboard/i)).toBeInTheDocument();
|
|
66
|
-
|
|
67
|
-
// Check that the dashboard has the correct structure
|
|
68
|
-
const dashboard = document.querySelector('.grid');
|
|
69
|
-
expect(dashboard).not.toBeNull();
|
|
70
|
-
|
|
71
|
-
// Check that DSR Requests section is rendered
|
|
72
|
-
expect(screen.getByText(/DSR Requests/i)).toBeInTheDocument();
|
|
73
|
-
|
|
74
|
-
// Check that there are request elements in the dashboard
|
|
75
|
-
const requestElements = document.querySelectorAll('.rounded-md.cursor-pointer');
|
|
76
|
-
expect(requestElements.length).toBeGreaterThan(0);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('renders the dashboard with filter controls', () => {
|
|
80
|
-
render(
|
|
81
|
-
<DSRDashboard
|
|
82
|
-
requests={mockRequests}
|
|
83
|
-
onUpdateStatus={mockUpdateRequest}
|
|
84
|
-
onSelectRequest={mockDeleteRequest}
|
|
85
|
-
/>
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Check that the dashboard title is rendered
|
|
89
|
-
expect(screen.getByText(/Data Subject Request Dashboard/i)).toBeInTheDocument();
|
|
90
|
-
|
|
91
|
-
// Check that filter controls are rendered by looking for select elements
|
|
92
|
-
const selectElements = screen.getAllByRole('combobox');
|
|
93
|
-
expect(selectElements.length).toBeGreaterThan(0);
|
|
94
|
-
|
|
95
|
-
// Check that tHere's a search input
|
|
96
|
-
const searchInput = screen.getByPlaceholderText(/Search requests/i);
|
|
97
|
-
expect(searchInput).toBeInTheDocument();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('renders with sort controls', () => {
|
|
101
|
-
render(
|
|
102
|
-
<DSRDashboard
|
|
103
|
-
requests={mockRequests}
|
|
104
|
-
onUpdateStatus={mockUpdateRequest}
|
|
105
|
-
onSelectRequest={mockDeleteRequest}
|
|
106
|
-
/>
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// Check that sort options are rendered
|
|
110
|
-
const sortBySelect = screen.getByLabelText(/Sort By/i);
|
|
111
|
-
expect(sortBySelect).toBeInTheDocument();
|
|
112
|
-
|
|
113
|
-
// Check that the sort dropdown exists
|
|
114
|
-
expect(sortBySelect.tagName.toLowerCase()).toBe('select');
|
|
115
|
-
|
|
116
|
-
// Check that at least one option exists
|
|
117
|
-
const options = screen.getAllByRole('option');
|
|
118
|
-
expect(options.length).toBeGreaterThan(0);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('renders with search functionality', () => {
|
|
122
|
-
render(
|
|
123
|
-
<DSRDashboard
|
|
124
|
-
requests={mockRequests}
|
|
125
|
-
onUpdateStatus={mockUpdateRequest}
|
|
126
|
-
onSelectRequest={mockDeleteRequest}
|
|
127
|
-
/>
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
// Check that search input is rendered
|
|
131
|
-
const searchInput = screen.getByPlaceholderText(/Search requests/i);
|
|
132
|
-
expect(searchInput).toBeInTheDocument();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('renders with request list section', () => {
|
|
136
|
-
render(
|
|
137
|
-
<DSRDashboard
|
|
138
|
-
requests={mockRequests}
|
|
139
|
-
onUpdateStatus={mockUpdateRequest}
|
|
140
|
-
onSelectRequest={mockDeleteRequest}
|
|
141
|
-
/>
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
// Check that the DSR Requests section is rendered
|
|
145
|
-
expect(screen.getByText(/DSR Requests/i)).toBeInTheDocument();
|
|
146
|
-
|
|
147
|
-
// Check that the dashboard has the correct structure
|
|
148
|
-
const dashboard = document.querySelector('.grid');
|
|
149
|
-
expect(dashboard).not.toBeNull();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('renders with the correct title and description', () => {
|
|
153
|
-
const customTitle = 'Custom DSR Dashboard Title';
|
|
154
|
-
const customDescription = 'Custom description for testing';
|
|
155
|
-
|
|
156
|
-
render(
|
|
157
|
-
<DSRDashboard
|
|
158
|
-
requests={mockRequests}
|
|
159
|
-
onUpdateStatus={mockUpdateRequest}
|
|
160
|
-
onSelectRequest={mockDeleteRequest}
|
|
161
|
-
title={customTitle}
|
|
162
|
-
description={customDescription}
|
|
163
|
-
/>
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
// Check that custom title and description are rendered
|
|
167
|
-
expect(screen.getByText(customTitle)).toBeInTheDocument();
|
|
168
|
-
expect(screen.getByText(customDescription)).toBeInTheDocument();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('handles empty requests array', () => {
|
|
172
|
-
render(
|
|
173
|
-
<DSRDashboard
|
|
174
|
-
requests={[]}
|
|
175
|
-
onUpdateStatus={mockUpdateRequest}
|
|
176
|
-
onSelectRequest={mockDeleteRequest}
|
|
177
|
-
/>
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
expect(screen.getByText(/No data subject requests found/i)).toBeInTheDocument();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('renders with custom className', () => {
|
|
184
|
-
const customClassName = 'custom-dashboard-class';
|
|
185
|
-
|
|
186
|
-
render(
|
|
187
|
-
<DSRDashboard
|
|
188
|
-
requests={mockRequests}
|
|
189
|
-
onUpdateStatus={mockUpdateRequest}
|
|
190
|
-
onSelectRequest={mockDeleteRequest}
|
|
191
|
-
className={customClassName}
|
|
192
|
-
/>
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
// Check that the custom class is applied to the component
|
|
196
|
-
const dashboardElement = document.querySelector(`.${customClassName}`);
|
|
197
|
-
expect(dashboardElement).toBeInTheDocument();
|
|
198
|
-
});
|
|
199
|
-
});
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import { DSRRequestForm } from '../../../components/dsr/DSRRequestForm';
|
|
4
|
-
// Note: We'll mock the DSR context instead of importing it directly
|
|
5
|
-
|
|
6
|
-
describe('DSRRequestForm', () => {
|
|
7
|
-
const mockOnSubmit = jest.fn();
|
|
8
|
-
|
|
9
|
-
const renderComponent = (props = {}) => {
|
|
10
|
-
return render(
|
|
11
|
-
<DSRRequestForm
|
|
12
|
-
onSubmit={mockOnSubmit}
|
|
13
|
-
requestTypes={[
|
|
14
|
-
{ id: 'access', name: 'Access my data', description: 'Request a copy of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
|
|
15
|
-
{ id: 'rectification', name: 'Correct my data', description: 'Request corrections to your data', estimatedCompletionTime: 15, requiresAdditionalInfo: true },
|
|
16
|
-
{ id: 'erasure', name: 'Delete my data', description: 'Request deletion of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false }
|
|
17
|
-
]}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
mockOnSubmit.mockClear();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('renders the form correctly', () => {
|
|
28
|
-
renderComponent();
|
|
29
|
-
|
|
30
|
-
expect(screen.getByText(/submit a data subject request/i)).toBeInTheDocument();
|
|
31
|
-
expect(screen.getByLabelText(/full name/i)).toBeInTheDocument();
|
|
32
|
-
expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
|
|
33
|
-
expect(screen.getByLabelText(/request type/i)).toBeInTheDocument();
|
|
34
|
-
expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('displays all request types in the dropdown', () => {
|
|
38
|
-
renderComponent();
|
|
39
|
-
|
|
40
|
-
const selectElement = screen.getByLabelText(/request type/i);
|
|
41
|
-
fireEvent.click(selectElement);
|
|
42
|
-
|
|
43
|
-
expect(screen.getByText('Access my data')).toBeInTheDocument();
|
|
44
|
-
expect(screen.getByText('Correct my data')).toBeInTheDocument();
|
|
45
|
-
expect(screen.getByText('Delete my data')).toBeInTheDocument();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('validates required fields', async () => {
|
|
49
|
-
// Mock console.error to prevent React warnings from cluttering test output
|
|
50
|
-
const originalConsoleError = console.error;
|
|
51
|
-
console.error = jest.fn();
|
|
52
|
-
|
|
53
|
-
const { container } = renderComponent();
|
|
54
|
-
|
|
55
|
-
// Submit without filling required fields
|
|
56
|
-
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
|
|
57
|
-
|
|
58
|
-
// Wait for validation to happen
|
|
59
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
60
|
-
|
|
61
|
-
// Directly check that the form validation prevented submission
|
|
62
|
-
expect(mockOnSubmit).not.toHaveBeenCalled();
|
|
63
|
-
|
|
64
|
-
// Restore console.error
|
|
65
|
-
console.error = originalConsoleError;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('validates email format', async () => {
|
|
69
|
-
// Use a custom render to access component state
|
|
70
|
-
const { container } = renderComponent();
|
|
71
|
-
|
|
72
|
-
// Fill in name and request type
|
|
73
|
-
fireEvent.change(screen.getByLabelText(/full name/i), {
|
|
74
|
-
target: { value: 'John Doe' }
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Select a request type
|
|
78
|
-
const selectElement = screen.getByLabelText(/request type/i);
|
|
79
|
-
fireEvent.change(selectElement, { target: { value: 'access' } });
|
|
80
|
-
|
|
81
|
-
// Enter invalid email
|
|
82
|
-
const emailInput = screen.getByLabelText(/email/i);
|
|
83
|
-
fireEvent.change(emailInput, {
|
|
84
|
-
target: { value: 'invalid-email' }
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Submit the form
|
|
88
|
-
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
|
|
89
|
-
|
|
90
|
-
// Wait a bit for the validation to happen
|
|
91
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
92
|
-
|
|
93
|
-
// Check that the form has an error message somewhere
|
|
94
|
-
const errorElements = container.querySelectorAll('.text-red-500');
|
|
95
|
-
expect(errorElements.length).toBeGreaterThan(0);
|
|
96
|
-
|
|
97
|
-
// Should not call onSubmit when validation fails
|
|
98
|
-
expect(mockOnSubmit).not.toHaveBeenCalled();
|
|
99
|
-
|
|
100
|
-
// Now try with a valid email
|
|
101
|
-
fireEvent.change(emailInput, {
|
|
102
|
-
target: { value: 'valid@example.com' }
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Also fill in any other required fields
|
|
106
|
-
// Fill in identifier value if required
|
|
107
|
-
const identifierValueInput = screen.getByLabelText(/identifier value/i);
|
|
108
|
-
fireEvent.change(identifierValueInput, {
|
|
109
|
-
target: { value: 'valid-id-123' }
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Submit the form again
|
|
113
|
-
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
|
|
114
|
-
|
|
115
|
-
// Now onSubmit should be called
|
|
116
|
-
expect(mockOnSubmit).toHaveBeenCalled();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('submits the form with valid data', async () => {
|
|
120
|
-
// Mock the onSubmit function
|
|
121
|
-
const mockSubmit = jest.fn();
|
|
122
|
-
|
|
123
|
-
render(
|
|
124
|
-
<DSRRequestForm
|
|
125
|
-
requestTypes={[
|
|
126
|
-
{ id: 'access', name: 'Access my data', description: 'Request a copy of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
|
|
127
|
-
{ id: 'rectification', name: 'Correct my data', description: 'Request corrections to your data', estimatedCompletionTime: 15, requiresAdditionalInfo: true },
|
|
128
|
-
{ id: 'erasure', name: 'Delete my data', description: 'Request deletion of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false }
|
|
129
|
-
]}
|
|
130
|
-
onSubmit={mockSubmit}
|
|
131
|
-
/>
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
// Fill in all required fields
|
|
135
|
-
fireEvent.change(screen.getByLabelText(/full name/i), {
|
|
136
|
-
target: { value: 'John Doe' }
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
fireEvent.change(screen.getByLabelText(/email/i), {
|
|
140
|
-
target: { value: 'john@example.com' }
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// Select a request type
|
|
144
|
-
const selectElement = screen.getByLabelText(/request type/i);
|
|
145
|
-
fireEvent.change(selectElement, { target: { value: 'access' } });
|
|
146
|
-
|
|
147
|
-
// Fill in identifier value
|
|
148
|
-
fireEvent.change(screen.getByLabelText(/identifier value/i), {
|
|
149
|
-
target: { value: 'john@example.com' }
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Submit the form
|
|
153
|
-
fireEvent.click(screen.getByRole('button', { name: /submit request/i }));
|
|
154
|
-
|
|
155
|
-
// Should call onSubmit with form data
|
|
156
|
-
expect(mockSubmit).toHaveBeenCalled();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('shows success message after submission', async () => {
|
|
160
|
-
// Mock the onSubmit function to trigger the success message
|
|
161
|
-
const mockSubmit = jest.fn().mockImplementation(() => {
|
|
162
|
-
// This will be called when the form is submitted
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
render(
|
|
166
|
-
<DSRRequestForm
|
|
167
|
-
requestTypes={[
|
|
168
|
-
{ id: 'access', name: 'Access my data', description: 'Request a copy of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
|
|
169
|
-
{ id: 'rectification', name: 'Correct my data', description: 'Request corrections to your data', estimatedCompletionTime: 15, requiresAdditionalInfo: true },
|
|
170
|
-
{ id: 'erasure', name: 'Delete my data', description: 'Request deletion of your data', estimatedCompletionTime: 30, requiresAdditionalInfo: false }
|
|
171
|
-
]}
|
|
172
|
-
onSubmit={mockSubmit}
|
|
173
|
-
showConfirmation={true}
|
|
174
|
-
confirmationMessage="Your request has been submitted successfully. You will receive a confirmation email shortly."
|
|
175
|
-
/>
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// Fill in all required fields
|
|
179
|
-
fireEvent.change(screen.getByLabelText(/full name/i), {
|
|
180
|
-
target: { value: 'John Doe' }
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
fireEvent.change(screen.getByLabelText(/email/i), {
|
|
184
|
-
target: { value: 'john@example.com' }
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Select a request type
|
|
188
|
-
const selectElement = screen.getByLabelText(/request type/i);
|
|
189
|
-
fireEvent.change(selectElement, { target: { value: 'access' } });
|
|
190
|
-
|
|
191
|
-
// Fill in identifier value
|
|
192
|
-
fireEvent.change(screen.getByLabelText(/identifier value/i), {
|
|
193
|
-
target: { value: 'john@example.com' }
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Submit the form
|
|
197
|
-
fireEvent.click(screen.getByRole('button', { name: /submit request/i }));
|
|
198
|
-
|
|
199
|
-
// Should show success message
|
|
200
|
-
expect(await screen.findByText(/request submitted/i)).toBeInTheDocument();
|
|
201
|
-
expect(await screen.findByText(/you will receive a confirmation email shortly/i)).toBeInTheDocument();
|
|
202
|
-
|
|
203
|
-
// Verify that onSubmit was called
|
|
204
|
-
expect(mockSubmit).toHaveBeenCalled();
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('handles custom field labels', () => {
|
|
208
|
-
renderComponent({
|
|
209
|
-
labels: {
|
|
210
|
-
name: 'Your Full Name',
|
|
211
|
-
email: 'Your Email Address',
|
|
212
|
-
requestType: 'Type of Request',
|
|
213
|
-
description: 'Additional Information',
|
|
214
|
-
submit: 'Send Request'
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
expect(screen.getByLabelText(/Your Full Name/i)).toBeInTheDocument();
|
|
219
|
-
expect(screen.getByLabelText(/Your Email Address/i)).toBeInTheDocument();
|
|
220
|
-
expect(screen.getByLabelText(/Type of Request/i)).toBeInTheDocument();
|
|
221
|
-
expect(screen.getByLabelText(/Additional Information/i)).toBeInTheDocument();
|
|
222
|
-
expect(screen.getByRole('button', { name: /Send Request/i })).toBeInTheDocument();
|
|
223
|
-
});
|
|
224
|
-
});
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import { DSRTracker } from '../../../components/dsr/DSRTracker';
|
|
4
|
-
import { DSRRequest } from '../../../types/dsr';
|
|
5
|
-
|
|
6
|
-
describe('DSRTracker', () => {
|
|
7
|
-
const mockRequest: DSRRequest = {
|
|
8
|
-
id: 'dsr-123',
|
|
9
|
-
type: 'access',
|
|
10
|
-
status: 'inProgress',
|
|
11
|
-
createdAt: 1620000000000,
|
|
12
|
-
updatedAt: 1620100000000,
|
|
13
|
-
subject: {
|
|
14
|
-
name: 'John Doe',
|
|
15
|
-
email: 'john@example.com'
|
|
16
|
-
},
|
|
17
|
-
description: 'I want to access my personal data'
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const mockTrackHandler = jest.fn();
|
|
21
|
-
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
mockTrackHandler.mockClear();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('renders the tracking form correctly', () => {
|
|
27
|
-
render(
|
|
28
|
-
<DSRTracker
|
|
29
|
-
requests={[]}
|
|
30
|
-
onSelectRequest={mockTrackHandler}
|
|
31
|
-
/>
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
expect(screen.getByText(/DSR Request Tracker/i)).toBeInTheDocument();
|
|
35
|
-
expect(screen.getByText(/track the status and progress/i)).toBeInTheDocument();
|
|
36
|
-
expect(screen.getByText(/total requests/i)).toBeInTheDocument();
|
|
37
|
-
expect(screen.getByLabelText(/timeframe/i)).toBeInTheDocument();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Note: The DSRTracker component doesn't have a form for tracking requests directly visible on initial render
|
|
41
|
-
// These tests are removed as they don't match the actual component implementation
|
|
42
|
-
|
|
43
|
-
it('displays request count when provided', () => {
|
|
44
|
-
// Render the component with a request
|
|
45
|
-
const { container } = render(
|
|
46
|
-
<DSRTracker
|
|
47
|
-
requests={[mockRequest]}
|
|
48
|
-
onSelectRequest={mockTrackHandler}
|
|
49
|
-
/>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
// Check that the component renders without crashing
|
|
53
|
-
expect(container).toBeInTheDocument();
|
|
54
|
-
|
|
55
|
-
// Should show summary stats with the request count heading
|
|
56
|
-
expect(screen.getByText(/total requests/i)).toBeInTheDocument();
|
|
57
|
-
|
|
58
|
-
// Check that the component has rendered some content
|
|
59
|
-
const statsContainer = screen.getByText(/total requests/i).closest('div');
|
|
60
|
-
expect(statsContainer).toBeInTheDocument();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Note: The DSRTracker component doesn't display a "Request not found" message directly on initial render
|
|
64
|
-
// This test is removed as it doesn't match the actual component implementation
|
|
65
|
-
|
|
66
|
-
it('handles custom title', () => {
|
|
67
|
-
const customTitle = 'Custom DSR Tracker Title';
|
|
68
|
-
|
|
69
|
-
render(
|
|
70
|
-
<DSRTracker
|
|
71
|
-
requests={[]}
|
|
72
|
-
onSelectRequest={mockTrackHandler}
|
|
73
|
-
title={customTitle}
|
|
74
|
-
/>
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
expect(screen.getByText(customTitle)).toBeInTheDocument();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('shows request timeline chart when requests are provided', () => {
|
|
81
|
-
const requestWithDates: DSRRequest = {
|
|
82
|
-
...mockRequest,
|
|
83
|
-
verifiedAt: 1620050000000,
|
|
84
|
-
completedAt: 1620200000000
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// Render the component with the request
|
|
88
|
-
const { container } = render(
|
|
89
|
-
<DSRTracker
|
|
90
|
-
requests={[requestWithDates]}
|
|
91
|
-
onSelectRequest={mockTrackHandler}
|
|
92
|
-
/>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
// Check that the component renders without crashing
|
|
96
|
-
expect(container).toBeInTheDocument();
|
|
97
|
-
|
|
98
|
-
// Check for the title which should always be present
|
|
99
|
-
expect(screen.getByText(/DSR Request Tracker/i)).toBeInTheDocument();
|
|
100
|
-
|
|
101
|
-
// Check that the description is present
|
|
102
|
-
expect(screen.getByText(/Track the status and progress/i)).toBeInTheDocument();
|
|
103
|
-
});
|
|
104
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { renderHook, act } from '@testing-library/react';
|
|
3
|
-
import { useConsent } from '../../hooks/useConsent';
|
|
4
|
-
import { ConsentOption, ConsentSettings } from '../../types/consent';
|
|
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('useConsent', () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
mockLocalStorage.clear();
|
|
30
|
-
jest.clearAllMocks();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const consentOptions: ConsentOption[] = [
|
|
34
|
-
{
|
|
35
|
-
id: 'necessary',
|
|
36
|
-
label: 'Necessary',
|
|
37
|
-
description: 'Essential cookies',
|
|
38
|
-
required: true,
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: 'analytics',
|
|
42
|
-
label: 'Analytics',
|
|
43
|
-
description: 'Analytics cookies',
|
|
44
|
-
required: false,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: 'marketing',
|
|
48
|
-
label: 'Marketing',
|
|
49
|
-
description: 'Marketing cookies',
|
|
50
|
-
required: false,
|
|
51
|
-
},
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
it('should initialize with default consent settings', () => {
|
|
55
|
-
const { result } = renderHook(() => useConsent({
|
|
56
|
-
options: consentOptions,
|
|
57
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
58
|
-
}));
|
|
59
|
-
|
|
60
|
-
expect(result.current.settings).toBe(null);
|
|
61
|
-
expect(result.current.shouldShowBanner).toBe(true);
|
|
62
|
-
expect(result.current.hasConsent('necessary')).toBe(false);
|
|
63
|
-
expect(result.current.hasConsent('analytics')).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should update consent settings', () => {
|
|
67
|
-
const { result } = renderHook(() => useConsent({
|
|
68
|
-
options: consentOptions,
|
|
69
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
|
-
act(() => {
|
|
73
|
-
result.current.updateConsent({
|
|
74
|
-
necessary: true,
|
|
75
|
-
analytics: true,
|
|
76
|
-
marketing: false
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(result.current.settings?.consents.necessary).toBe(true);
|
|
81
|
-
expect(result.current.settings?.consents.analytics).toBe(true);
|
|
82
|
-
expect(result.current.settings?.consents.marketing).toBe(false);
|
|
83
|
-
expect(result.current.hasConsent('analytics')).toBe(true);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should accept all consent options', () => {
|
|
87
|
-
const { result } = renderHook(() => useConsent({
|
|
88
|
-
options: consentOptions,
|
|
89
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
act(() => {
|
|
93
|
-
result.current.acceptAll();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(result.current.settings?.consents.necessary).toBe(true);
|
|
97
|
-
expect(result.current.settings?.consents.analytics).toBe(true);
|
|
98
|
-
expect(result.current.settings?.consents.marketing).toBe(true);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should save and reset consent settings', () => {
|
|
102
|
-
const { result } = renderHook(() => useConsent({
|
|
103
|
-
options: consentOptions,
|
|
104
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
105
|
-
}));
|
|
106
|
-
|
|
107
|
-
act(() => {
|
|
108
|
-
result.current.updateConsent({
|
|
109
|
-
necessary: true,
|
|
110
|
-
analytics: true,
|
|
111
|
-
marketing: false
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(mockLocalStorage.setItem).toHaveBeenCalled();
|
|
116
|
-
expect(result.current.shouldShowBanner).toBe(false);
|
|
117
|
-
|
|
118
|
-
// Reset the consent settings
|
|
119
|
-
act(() => {
|
|
120
|
-
result.current.resetConsent();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test-consent');
|
|
124
|
-
expect(result.current.settings).toBe(null);
|
|
125
|
-
expect(result.current.shouldShowBanner).toBe(true);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should reject all non-required consent options', () => {
|
|
129
|
-
const { result } = renderHook(() => useConsent({
|
|
130
|
-
options: consentOptions,
|
|
131
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
132
|
-
}));
|
|
133
|
-
|
|
134
|
-
act(() => {
|
|
135
|
-
result.current.rejectAll();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Necessary is required, so it should be true
|
|
139
|
-
expect(result.current.settings?.consents.necessary).toBe(true);
|
|
140
|
-
// Non-required options should be false
|
|
141
|
-
expect(result.current.settings?.consents.analytics).toBe(false);
|
|
142
|
-
expect(result.current.settings?.consents.marketing).toBe(false);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should handle validation', () => {
|
|
146
|
-
const { result } = renderHook(() => useConsent({
|
|
147
|
-
options: consentOptions,
|
|
148
|
-
storageOptions: { storageKey: 'test-consent' }
|
|
149
|
-
}));
|
|
150
|
-
|
|
151
|
-
expect(result.current.isValid).toBe(false);
|
|
152
|
-
|
|
153
|
-
act(() => {
|
|
154
|
-
result.current.acceptAll();
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// After accepting all, settings should be valid
|
|
158
|
-
expect(result.current.isValid).toBe(true);
|
|
159
|
-
expect(result.current.validationErrors).toEqual([]);
|
|
160
|
-
});
|
|
161
|
-
});
|