@semiont/react-ui 0.2.33-build.79 → 0.2.33-build.81
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/dist/EventBusContext-CJjL_cCf.d.mts +462 -0
- package/dist/{PdfAnnotationCanvas.client-ADC4FFSE.mjs → PdfAnnotationCanvas.client-RAJRPQLU.mjs} +42 -27
- package/dist/PdfAnnotationCanvas.client-RAJRPQLU.mjs.map +1 -0
- package/dist/{ar-EMHEHPCJ.mjs → ar-4ZEORRW2.mjs} +7 -4
- package/dist/ar-4ZEORRW2.mjs.map +1 -0
- package/dist/{bn-OVCI4F6X.mjs → bn-SEDE5BQJ.mjs} +7 -4
- package/dist/bn-SEDE5BQJ.mjs.map +1 -0
- package/dist/{chunk-LIHZTECW.mjs → chunk-D7NBW4RV.mjs} +7 -4
- package/dist/chunk-D7NBW4RV.mjs.map +1 -0
- package/dist/{chunk-JZIO2A3B.mjs → chunk-QB52Q7EQ.mjs} +206 -146
- package/dist/chunk-QB52Q7EQ.mjs.map +1 -0
- package/dist/{cs-FAN66Q2F.mjs → cs-7W4WF5WD.mjs} +7 -4
- package/dist/cs-7W4WF5WD.mjs.map +1 -0
- package/dist/{da-YBBIHI2O.mjs → da-75XGBCBK.mjs} +7 -4
- package/dist/da-75XGBCBK.mjs.map +1 -0
- package/dist/{de-MAYU33LB.mjs → de-ODJVFLHM.mjs} +7 -4
- package/dist/de-ODJVFLHM.mjs.map +1 -0
- package/dist/{el-MKGSWN4O.mjs → el-C4PM4WB3.mjs} +7 -4
- package/dist/el-C4PM4WB3.mjs.map +1 -0
- package/dist/{en-DDLIXJCU.mjs → en-KJCJQ4OO.mjs} +2 -2
- package/dist/{es-52LHUWJD.mjs → es-WD33R7QL.mjs} +7 -4
- package/dist/es-WD33R7QL.mjs.map +1 -0
- package/dist/{fa-FJICRANB.mjs → fa-2BP6V56P.mjs} +7 -4
- package/dist/fa-2BP6V56P.mjs.map +1 -0
- package/dist/{fi-O455XFCR.mjs → fi-USRRW24J.mjs} +7 -4
- package/dist/fi-USRRW24J.mjs.map +1 -0
- package/dist/{fr-TXIXHOOE.mjs → fr-EC5S6WVF.mjs} +7 -4
- package/dist/fr-EC5S6WVF.mjs.map +1 -0
- package/dist/{he-JBSOX5IN.mjs → he-7TBVIKAA.mjs} +7 -4
- package/dist/he-7TBVIKAA.mjs.map +1 -0
- package/dist/{hi-KGHI3XVT.mjs → hi-FO4VIZLA.mjs} +7 -4
- package/dist/hi-FO4VIZLA.mjs.map +1 -0
- package/dist/{id-5OCPPZLO.mjs → id-7U7GGVWY.mjs} +7 -4
- package/dist/id-7U7GGVWY.mjs.map +1 -0
- package/dist/index.css +123 -85
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +715 -574
- package/dist/index.mjs +3898 -3575
- package/dist/index.mjs.map +1 -1
- package/dist/{it-PNBBZSM2.mjs → it-Y4OPL6I2.mjs} +7 -4
- package/dist/it-Y4OPL6I2.mjs.map +1 -0
- package/dist/{ja-LDD7R3TJ.mjs → ja-PK7SQL55.mjs} +7 -4
- package/dist/ja-PK7SQL55.mjs.map +1 -0
- package/dist/{ko-F47ZDEY3.mjs → ko-L25PXMYD.mjs} +7 -4
- package/dist/ko-L25PXMYD.mjs.map +1 -0
- package/dist/{ms-Z7LMXJWL.mjs → ms-STH777QM.mjs} +7 -4
- package/dist/ms-STH777QM.mjs.map +1 -0
- package/dist/{nl-6SJFBPJ3.mjs → nl-Y7LECDDR.mjs} +7 -4
- package/dist/nl-Y7LECDDR.mjs.map +1 -0
- package/dist/{no-YXPBPSGF.mjs → no-KEKCEWU6.mjs} +7 -4
- package/dist/no-KEKCEWU6.mjs.map +1 -0
- package/dist/{pl-P4AZ2QME.mjs → pl-7A7OC75O.mjs} +7 -4
- package/dist/pl-7A7OC75O.mjs.map +1 -0
- package/dist/{pt-LHWUS6U6.mjs → pt-35HTM7RA.mjs} +7 -4
- package/dist/pt-35HTM7RA.mjs.map +1 -0
- package/dist/{ro-EA5J2ZON.mjs → ro-VAWL5KQA.mjs} +7 -4
- package/dist/ro-VAWL5KQA.mjs.map +1 -0
- package/dist/{sv-DATBS3UQ.mjs → sv-7ZK5EQEB.mjs} +7 -4
- package/dist/sv-7ZK5EQEB.mjs.map +1 -0
- package/dist/test-utils.d.mts +18 -8
- package/dist/test-utils.mjs +36 -14
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-WTFJRWPT.mjs → th-UDWZ4X34.mjs} +7 -4
- package/dist/th-UDWZ4X34.mjs.map +1 -0
- package/dist/{tr-IKO3RXOX.mjs → tr-4WMPK3UX.mjs} +7 -4
- package/dist/tr-4WMPK3UX.mjs.map +1 -0
- package/dist/{uk-CF6CTTRK.mjs → uk-SSLASQYJ.mjs} +7 -4
- package/dist/uk-SSLASQYJ.mjs.map +1 -0
- package/dist/{vi-AJLTXPZQ.mjs → vi-IF42Z5PU.mjs} +7 -4
- package/dist/vi-IF42Z5PU.mjs.map +1 -0
- package/dist/{zh-U3ORHHYH.mjs → zh-HRQTNTAI.mjs} +7 -4
- package/dist/zh-HRQTNTAI.mjs.map +1 -0
- package/package.json +3 -1
- package/src/components/CodeMirrorRenderer.tsx +66 -93
- package/src/components/DetectionProgressWidget.tsx +16 -5
- package/src/components/ResizeHandle.tsx +10 -4
- package/src/components/SessionExpiryBanner.tsx +2 -3
- package/src/components/SessionTimer.tsx +3 -3
- package/src/components/Toolbar.tsx +18 -9
- package/src/components/__tests__/SessionTimer.test.tsx +33 -33
- package/src/components/annotation/AnnotateToolbar.tsx +17 -15
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +165 -63
- package/src/components/annotation/annotation-entries.css +10 -0
- package/src/components/annotation-popups/JsonLdView.tsx +8 -2
- package/src/components/image-annotation/AnnotationOverlay.tsx +42 -22
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +27 -30
- package/src/components/layout/__tests__/LeftSidebar.test.tsx +12 -33
- package/src/components/layout/__tests__/PageLayout.test.tsx +37 -32
- package/src/components/layout/__tests__/UnifiedHeader.test.tsx +21 -40
- package/src/components/modals/ResourceSearchModal.tsx +2 -2
- package/src/components/modals/SearchModal.tsx +1 -1
- package/src/components/navigation/CollapsibleResourceNavigation.tsx +14 -9
- package/src/components/navigation/NavigationTabs.css +36 -24
- package/src/components/navigation/ObservableLink.tsx +91 -0
- package/src/components/navigation/SimpleNavigation.tsx +20 -16
- package/src/components/navigation/SortableResourceTab.tsx +11 -5
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +51 -26
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +28 -22
- package/src/components/resource/AnnotateView.tsx +64 -134
- package/src/components/resource/BrowseView.tsx +86 -166
- package/src/components/resource/HistoryEvent.tsx +13 -7
- package/src/components/resource/ResourceViewer.tsx +122 -264
- package/src/components/resource/__tests__/BrowseView.test.tsx +631 -0
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +231 -0
- package/src/components/resource/panels/AssessmentEntry.tsx +25 -33
- package/src/components/resource/panels/AssessmentPanel.tsx +106 -28
- package/src/components/resource/panels/CommentEntry.tsx +38 -32
- package/src/components/resource/panels/CommentsPanel.tsx +121 -28
- package/src/components/resource/panels/DetectSection.css +36 -1
- package/src/components/resource/panels/DetectSection.tsx +49 -15
- package/src/components/resource/panels/HighlightEntry.tsx +25 -33
- package/src/components/resource/panels/HighlightPanel.tsx +100 -25
- package/src/components/resource/panels/ReferenceEntry.tsx +61 -75
- package/src/components/resource/panels/ReferencesPanel.tsx +134 -42
- package/src/components/resource/panels/ResourceInfoPanel.tsx +47 -48
- package/src/components/resource/panels/TagEntry.tsx +25 -33
- package/src/components/resource/panels/TaggingPanel.tsx +118 -30
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +30 -92
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +129 -110
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +86 -78
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +144 -149
- package/src/components/resource/panels/__tests__/DetectSection.test.tsx +480 -0
- package/src/components/resource/panels/__tests__/HighlightPanel.detectionProgress.test.tsx +362 -0
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +226 -111
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +117 -61
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +128 -106
- package/src/components/settings/SettingsPanel.tsx +15 -12
- package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +1 -46
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +0 -9
- package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +0 -3
- package/src/features/admin-security/components/AdminSecurityPage.tsx +0 -9
- package/src/features/admin-users/__tests__/AdminUsersPage.test.tsx +0 -3
- package/src/features/admin-users/components/AdminUsersPage.tsx +0 -9
- package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +0 -3
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -9
- package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +0 -32
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -9
- package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +0 -32
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -9
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +51 -54
- package/src/features/resource-compose/components/ResourceComposePage.tsx +3 -13
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +39 -45
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +9 -13
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +234 -0
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +234 -0
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +388 -0
- package/src/features/resource-viewer/__tests__/DetectionProgressDismissal.test.tsx +318 -0
- package/src/features/resource-viewer/__tests__/GenerationFlowIntegration.test.tsx +503 -0
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +139 -93
- package/src/features/resource-viewer/__tests__/detection-progress-flow.test.tsx +322 -0
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +341 -524
- package/translations/ar.json +6 -3
- package/translations/bn.json +6 -3
- package/translations/cs.json +6 -3
- package/translations/da.json +6 -3
- package/translations/de.json +6 -3
- package/translations/el.json +6 -3
- package/translations/en.json +6 -3
- package/translations/es.json +6 -3
- package/translations/fa.json +6 -3
- package/translations/fi.json +6 -3
- package/translations/fr.json +6 -3
- package/translations/he.json +6 -3
- package/translations/hi.json +6 -3
- package/translations/id.json +6 -3
- package/translations/it.json +6 -3
- package/translations/ja.json +6 -3
- package/translations/ko.json +6 -3
- package/translations/ms.json +6 -3
- package/translations/nl.json +6 -3
- package/translations/no.json +6 -3
- package/translations/pl.json +6 -3
- package/translations/pt.json +6 -3
- package/translations/ro.json +6 -3
- package/translations/sv.json +6 -3
- package/translations/th.json +6 -3
- package/translations/tr.json +6 -3
- package/translations/uk.json +6 -3
- package/translations/vi.json +6 -3
- package/translations/zh.json +6 -3
- package/dist/PdfAnnotationCanvas.client-ADC4FFSE.mjs.map +0 -1
- package/dist/TranslationManager-Co_5fSxl.d.mts +0 -118
- package/dist/ar-EMHEHPCJ.mjs.map +0 -1
- package/dist/bn-OVCI4F6X.mjs.map +0 -1
- package/dist/chunk-JZIO2A3B.mjs.map +0 -1
- package/dist/chunk-LIHZTECW.mjs.map +0 -1
- package/dist/cs-FAN66Q2F.mjs.map +0 -1
- package/dist/da-YBBIHI2O.mjs.map +0 -1
- package/dist/de-MAYU33LB.mjs.map +0 -1
- package/dist/el-MKGSWN4O.mjs.map +0 -1
- package/dist/es-52LHUWJD.mjs.map +0 -1
- package/dist/fa-FJICRANB.mjs.map +0 -1
- package/dist/fi-O455XFCR.mjs.map +0 -1
- package/dist/fr-TXIXHOOE.mjs.map +0 -1
- package/dist/he-JBSOX5IN.mjs.map +0 -1
- package/dist/hi-KGHI3XVT.mjs.map +0 -1
- package/dist/id-5OCPPZLO.mjs.map +0 -1
- package/dist/it-PNBBZSM2.mjs.map +0 -1
- package/dist/ja-LDD7R3TJ.mjs.map +0 -1
- package/dist/ko-F47ZDEY3.mjs.map +0 -1
- package/dist/ms-Z7LMXJWL.mjs.map +0 -1
- package/dist/nl-6SJFBPJ3.mjs.map +0 -1
- package/dist/no-YXPBPSGF.mjs.map +0 -1
- package/dist/pl-P4AZ2QME.mjs.map +0 -1
- package/dist/pt-LHWUS6U6.mjs.map +0 -1
- package/dist/ro-EA5J2ZON.mjs.map +0 -1
- package/dist/sv-DATBS3UQ.mjs.map +0 -1
- package/dist/th-WTFJRWPT.mjs.map +0 -1
- package/dist/tr-IKO3RXOX.mjs.map +0 -1
- package/dist/uk-CF6CTTRK.mjs.map +0 -1
- package/dist/vi-AJLTXPZQ.mjs.map +0 -1
- package/dist/zh-U3ORHHYH.mjs.map +0 -1
- /package/dist/{en-DDLIXJCU.mjs.map → en-KJCJQ4OO.mjs.map} +0 -0
|
@@ -1,22 +1,77 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import type { MockedFunction } from 'vitest';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { AssessmentPanel } from '../AssessmentPanel';
|
|
8
|
+
import { EventBusProvider, resetEventBusForTesting, useEventBus } from '../../../../contexts/EventBusContext';
|
|
8
9
|
import type { components } from '@semiont/api-client';
|
|
9
10
|
|
|
10
11
|
type Annotation = components['schemas']['Annotation'];
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
// Composition-based event tracker
|
|
14
|
+
interface TrackedEvent {
|
|
15
|
+
event: string;
|
|
16
|
+
payload: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createEventTracker() {
|
|
20
|
+
const events: TrackedEvent[] = [];
|
|
21
|
+
|
|
22
|
+
function EventTrackingWrapper({ children }: { children: React.ReactNode }) {
|
|
23
|
+
const eventBus = useEventBus();
|
|
24
|
+
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
const handlers: Array<() => void> = [];
|
|
27
|
+
|
|
28
|
+
const trackEvent = (eventName: string) => (payload: any) => {
|
|
29
|
+
events.push({ event: eventName, payload });
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const panelEvents = ['annotation:create'];
|
|
33
|
+
|
|
34
|
+
panelEvents.forEach(eventName => {
|
|
35
|
+
const handler = trackEvent(eventName);
|
|
36
|
+
eventBus.on(eventName, handler);
|
|
37
|
+
handlers.push(() => eventBus.off(eventName, handler));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return () => {
|
|
41
|
+
handlers.forEach(cleanup => cleanup());
|
|
42
|
+
};
|
|
43
|
+
}, [eventBus]);
|
|
44
|
+
|
|
45
|
+
return <>{children}</>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
EventTrackingWrapper,
|
|
50
|
+
events,
|
|
51
|
+
clear: () => {
|
|
52
|
+
events.length = 0;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Helper to render with EventBusProvider
|
|
58
|
+
const renderWithEventBus = (component: React.ReactElement, tracker?: ReturnType<typeof createEventTracker>) => {
|
|
59
|
+
if (tracker) {
|
|
60
|
+
return render(
|
|
61
|
+
<EventBusProvider>
|
|
62
|
+
<tracker.EventTrackingWrapper>
|
|
63
|
+
{component}
|
|
64
|
+
</tracker.EventTrackingWrapper>
|
|
65
|
+
</EventBusProvider>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return render(
|
|
70
|
+
<EventBusProvider>
|
|
71
|
+
{component}
|
|
72
|
+
</EventBusProvider>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
20
75
|
|
|
21
76
|
// Mock TranslationContext
|
|
22
77
|
vi.mock('../../../../contexts/TranslationContext', () => ({
|
|
@@ -31,6 +86,7 @@ vi.mock('../../../../contexts/TranslationContext', () => ({
|
|
|
31
86
|
};
|
|
32
87
|
return translations[key] || key;
|
|
33
88
|
}),
|
|
89
|
+
TranslationProvider: ({ children }: { children: React.ReactNode }) => children,
|
|
34
90
|
}));
|
|
35
91
|
|
|
36
92
|
// Mock @semiont/api-client utilities
|
|
@@ -45,29 +101,19 @@ vi.mock('@semiont/api-client', async () => {
|
|
|
45
101
|
|
|
46
102
|
// Mock AssessmentEntry component to simplify testing
|
|
47
103
|
vi.mock('../AssessmentEntry', () => ({
|
|
48
|
-
AssessmentEntry: ({ assessment,
|
|
49
|
-
<div
|
|
50
|
-
data-testid={`assessment-${assessment.id}`}
|
|
51
|
-
onClick={() => onClick()}
|
|
52
|
-
>
|
|
53
|
-
<button
|
|
54
|
-
onMouseEnter={() => onAssessmentHover?.(assessment.id)}
|
|
55
|
-
onMouseLeave={() => onAssessmentHover?.(null)}
|
|
56
|
-
>
|
|
57
|
-
Hover
|
|
58
|
-
</button>
|
|
104
|
+
AssessmentEntry: ({ assessment, onAssessmentRef }: any) => (
|
|
105
|
+
<div data-testid={`assessment-${assessment.id}`}>
|
|
59
106
|
<div>{assessment.id}</div>
|
|
60
107
|
</div>
|
|
61
108
|
),
|
|
62
109
|
}));
|
|
63
110
|
|
|
64
|
-
// Mock DetectSection component
|
|
111
|
+
// Mock DetectSection component - it will internally use the mocked useEventBus
|
|
112
|
+
// Just render a simplified version
|
|
65
113
|
vi.mock('../DetectSection', () => ({
|
|
66
|
-
DetectSection: ({ annotationType, isDetecting
|
|
114
|
+
DetectSection: ({ annotationType, isDetecting }: any) => (
|
|
67
115
|
<div data-testid="detect-section">
|
|
68
|
-
<button
|
|
69
|
-
Start Detection
|
|
70
|
-
</button>
|
|
116
|
+
<button>Start Detection</button>
|
|
71
117
|
{isDetecting && <div>Detecting...</div>}
|
|
72
118
|
</div>
|
|
73
119
|
),
|
|
@@ -128,13 +174,11 @@ const createPendingAnnotation = (exact: string) => ({
|
|
|
128
174
|
describe('AssessmentPanel Component', () => {
|
|
129
175
|
const defaultProps = {
|
|
130
176
|
annotations: mockAssessments.empty,
|
|
131
|
-
onAnnotationClick: vi.fn(),
|
|
132
|
-
onCreate: vi.fn(),
|
|
133
|
-
focusedAnnotationId: null,
|
|
134
177
|
pendingAnnotation: null,
|
|
135
178
|
};
|
|
136
179
|
|
|
137
180
|
beforeEach(() => {
|
|
181
|
+
resetEventBusForTesting();
|
|
138
182
|
vi.clearAllMocks();
|
|
139
183
|
|
|
140
184
|
// Mock scrollIntoView for jsdom
|
|
@@ -156,20 +200,20 @@ describe('AssessmentPanel Component', () => {
|
|
|
156
200
|
|
|
157
201
|
describe('Rendering', () => {
|
|
158
202
|
it('should render panel header with title and count', () => {
|
|
159
|
-
|
|
203
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} annotations={mockAssessments.multiple} />);
|
|
160
204
|
|
|
161
205
|
expect(screen.getByText(/Assessments/)).toBeInTheDocument();
|
|
162
206
|
expect(screen.getByText(/\(3\)/)).toBeInTheDocument();
|
|
163
207
|
});
|
|
164
208
|
|
|
165
209
|
it('should show empty state when no assessments', () => {
|
|
166
|
-
|
|
210
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} />);
|
|
167
211
|
|
|
168
212
|
expect(screen.getByText(/No assessments yet/)).toBeInTheDocument();
|
|
169
213
|
});
|
|
170
214
|
|
|
171
215
|
it('should render all assessments', () => {
|
|
172
|
-
|
|
216
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} annotations={mockAssessments.multiple} />);
|
|
173
217
|
|
|
174
218
|
expect(screen.getByTestId('assessment-1')).toBeInTheDocument();
|
|
175
219
|
expect(screen.getByTestId('assessment-2')).toBeInTheDocument();
|
|
@@ -177,7 +221,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
177
221
|
});
|
|
178
222
|
|
|
179
223
|
it('should have proper panel structure', () => {
|
|
180
|
-
const { container } =
|
|
224
|
+
const { container } = renderWithEventBus(<AssessmentPanel {...defaultProps} />);
|
|
181
225
|
|
|
182
226
|
const panel = container.firstChild as HTMLElement;
|
|
183
227
|
expect(panel).toHaveClass('semiont-panel');
|
|
@@ -186,7 +230,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
186
230
|
|
|
187
231
|
describe('Assessment Sorting', () => {
|
|
188
232
|
it('should sort assessments by position in resource', () => {
|
|
189
|
-
|
|
233
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} annotations={mockAssessments.multiple} />);
|
|
190
234
|
|
|
191
235
|
const assessments = screen.getAllByTestId(/assessment-/);
|
|
192
236
|
|
|
@@ -200,14 +244,14 @@ describe('AssessmentPanel Component', () => {
|
|
|
200
244
|
mockGetTextPositionSelector.mockReturnValue(null);
|
|
201
245
|
|
|
202
246
|
expect(() => {
|
|
203
|
-
|
|
247
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} annotations={mockAssessments.multiple} />);
|
|
204
248
|
}).not.toThrow();
|
|
205
249
|
});
|
|
206
250
|
});
|
|
207
251
|
|
|
208
252
|
describe('New Assessment Creation', () => {
|
|
209
253
|
it('should not show new assessment input by default', () => {
|
|
210
|
-
|
|
254
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} />);
|
|
211
255
|
|
|
212
256
|
expect(screen.queryByPlaceholderText(/Type your assessment here/)).not.toBeInTheDocument();
|
|
213
257
|
});
|
|
@@ -215,7 +259,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
215
259
|
it('should show new assessment input when pendingAnnotation exists', () => {
|
|
216
260
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
217
261
|
|
|
218
|
-
|
|
262
|
+
renderWithEventBus(
|
|
219
263
|
<AssessmentPanel
|
|
220
264
|
{...defaultProps}
|
|
221
265
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -228,7 +272,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
228
272
|
it('should display quoted selected text in new assessment area', () => {
|
|
229
273
|
const pendingAnnotation = createPendingAnnotation('Selected text for assessment');
|
|
230
274
|
|
|
231
|
-
|
|
275
|
+
renderWithEventBus(
|
|
232
276
|
<AssessmentPanel
|
|
233
277
|
{...defaultProps}
|
|
234
278
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -242,7 +286,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
242
286
|
const longText = 'A'.repeat(150);
|
|
243
287
|
const pendingAnnotation = createPendingAnnotation(longText);
|
|
244
288
|
|
|
245
|
-
|
|
289
|
+
renderWithEventBus(
|
|
246
290
|
<AssessmentPanel
|
|
247
291
|
{...defaultProps}
|
|
248
292
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -256,7 +300,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
256
300
|
it('should allow typing in new assessment textarea', async () => {
|
|
257
301
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
258
302
|
|
|
259
|
-
|
|
303
|
+
renderWithEventBus(
|
|
260
304
|
<AssessmentPanel
|
|
261
305
|
{...defaultProps}
|
|
262
306
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -272,7 +316,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
272
316
|
it('should show character count', async () => {
|
|
273
317
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
274
318
|
|
|
275
|
-
|
|
319
|
+
renderWithEventBus(
|
|
276
320
|
<AssessmentPanel
|
|
277
321
|
{...defaultProps}
|
|
278
322
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -290,7 +334,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
290
334
|
it('should enforce maxLength of 2000 characters', () => {
|
|
291
335
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
292
336
|
|
|
293
|
-
|
|
337
|
+
renderWithEventBus(
|
|
294
338
|
<AssessmentPanel
|
|
295
339
|
{...defaultProps}
|
|
296
340
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -304,7 +348,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
304
348
|
it('should auto-focus new assessment textarea', () => {
|
|
305
349
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
306
350
|
|
|
307
|
-
|
|
351
|
+
renderWithEventBus(
|
|
308
352
|
<AssessmentPanel
|
|
309
353
|
{...defaultProps}
|
|
310
354
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -315,16 +359,16 @@ describe('AssessmentPanel Component', () => {
|
|
|
315
359
|
expect(textarea).toHaveFocus();
|
|
316
360
|
});
|
|
317
361
|
|
|
318
|
-
it('should
|
|
319
|
-
const
|
|
362
|
+
it('should emit annotation:create event when save is clicked', async () => {
|
|
363
|
+
const tracker = createEventTracker();
|
|
320
364
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
321
365
|
|
|
322
|
-
|
|
366
|
+
renderWithEventBus(
|
|
323
367
|
<AssessmentPanel
|
|
324
368
|
{...defaultProps}
|
|
325
369
|
pendingAnnotation={pendingAnnotation}
|
|
326
|
-
|
|
327
|
-
|
|
370
|
+
/>,
|
|
371
|
+
tracker
|
|
328
372
|
);
|
|
329
373
|
|
|
330
374
|
const textarea = screen.getByPlaceholderText(/Type your assessment here/);
|
|
@@ -333,13 +377,19 @@ describe('AssessmentPanel Component', () => {
|
|
|
333
377
|
const saveButton = screen.getByText('Save');
|
|
334
378
|
await userEvent.click(saveButton);
|
|
335
379
|
|
|
336
|
-
|
|
380
|
+
await waitFor(() => {
|
|
381
|
+
expect(tracker.events.some(e =>
|
|
382
|
+
e.event === 'annotation:create' &&
|
|
383
|
+
e.payload?.motivation === 'assessing' &&
|
|
384
|
+
e.payload?.body?.[0]?.value === 'My assessment'
|
|
385
|
+
)).toBe(true);
|
|
386
|
+
});
|
|
337
387
|
});
|
|
338
388
|
|
|
339
389
|
it('should clear textarea after successful save', async () => {
|
|
340
390
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
341
391
|
|
|
342
|
-
|
|
392
|
+
renderWithEventBus(
|
|
343
393
|
<AssessmentPanel
|
|
344
394
|
{...defaultProps}
|
|
345
395
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -353,29 +403,35 @@ describe('AssessmentPanel Component', () => {
|
|
|
353
403
|
expect(textarea).toHaveValue('');
|
|
354
404
|
});
|
|
355
405
|
|
|
356
|
-
it('should
|
|
357
|
-
const
|
|
406
|
+
it('should emit event when saving with empty text (text is optional for assessments)', async () => {
|
|
407
|
+
const tracker = createEventTracker();
|
|
358
408
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
359
409
|
|
|
360
|
-
|
|
410
|
+
renderWithEventBus(
|
|
361
411
|
<AssessmentPanel
|
|
362
412
|
{...defaultProps}
|
|
363
413
|
pendingAnnotation={pendingAnnotation}
|
|
364
|
-
|
|
365
|
-
|
|
414
|
+
/>,
|
|
415
|
+
tracker
|
|
366
416
|
);
|
|
367
417
|
|
|
368
418
|
const saveButton = screen.getByText('Save');
|
|
369
419
|
await userEvent.click(saveButton);
|
|
370
420
|
|
|
371
|
-
|
|
372
|
-
|
|
421
|
+
await waitFor(() => {
|
|
422
|
+
expect(tracker.events.some(e =>
|
|
423
|
+
e.event === 'annotation:create' &&
|
|
424
|
+
e.payload?.motivation === 'assessing' &&
|
|
425
|
+
Array.isArray(e.payload?.body) &&
|
|
426
|
+
e.payload.body.length === 0
|
|
427
|
+
)).toBe(true);
|
|
428
|
+
});
|
|
373
429
|
});
|
|
374
430
|
|
|
375
431
|
it('should have proper styling for new assessment area', () => {
|
|
376
432
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
377
433
|
|
|
378
|
-
const { container } =
|
|
434
|
+
const { container } = renderWithEventBus(
|
|
379
435
|
<AssessmentPanel
|
|
380
436
|
{...defaultProps}
|
|
381
437
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -389,43 +445,23 @@ describe('AssessmentPanel Component', () => {
|
|
|
389
445
|
});
|
|
390
446
|
|
|
391
447
|
describe('Assessment Interactions', () => {
|
|
392
|
-
it('should
|
|
393
|
-
|
|
394
|
-
render(
|
|
448
|
+
it('should render assessment entries', () => {
|
|
449
|
+
renderWithEventBus(
|
|
395
450
|
<AssessmentPanel
|
|
396
451
|
{...defaultProps}
|
|
397
452
|
annotations={mockAssessments.single}
|
|
398
|
-
onAnnotationClick={onAnnotationClick}
|
|
399
453
|
/>
|
|
400
454
|
);
|
|
401
455
|
|
|
402
456
|
const assessment = screen.getByTestId('assessment-1');
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
expect(onAnnotationClick).toHaveBeenCalledWith(mockAssessments.single[0]);
|
|
457
|
+
expect(assessment).toBeInTheDocument();
|
|
406
458
|
});
|
|
407
459
|
});
|
|
408
460
|
|
|
409
461
|
describe('Assessment Hover Behavior', () => {
|
|
410
|
-
it('should
|
|
411
|
-
const onAnnotationHover = vi.fn();
|
|
412
|
-
render(
|
|
413
|
-
<AssessmentPanel
|
|
414
|
-
{...defaultProps}
|
|
415
|
-
annotations={mockAssessments.single}
|
|
416
|
-
onAnnotationHover={onAnnotationHover}
|
|
417
|
-
/>
|
|
418
|
-
);
|
|
419
|
-
|
|
420
|
-
const hoverButton = screen.getByText('Hover');
|
|
421
|
-
fireEvent.mouseEnter(hoverButton);
|
|
422
|
-
|
|
423
|
-
expect(onAnnotationHover).toHaveBeenCalledWith('1');
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('should not error when onAnnotationHover is not provided', () => {
|
|
462
|
+
it('should render without errors', () => {
|
|
427
463
|
expect(() => {
|
|
428
|
-
|
|
464
|
+
renderWithEventBus(
|
|
429
465
|
<AssessmentPanel
|
|
430
466
|
{...defaultProps}
|
|
431
467
|
annotations={mockAssessments.single}
|
|
@@ -436,11 +472,10 @@ describe('AssessmentPanel Component', () => {
|
|
|
436
472
|
});
|
|
437
473
|
|
|
438
474
|
describe('Detection Section', () => {
|
|
439
|
-
it('should render DetectSection when
|
|
440
|
-
|
|
475
|
+
it('should render DetectSection when annotateMode is true', () => {
|
|
476
|
+
renderWithEventBus(
|
|
441
477
|
<AssessmentPanel
|
|
442
478
|
{...defaultProps}
|
|
443
|
-
onDetect={vi.fn()}
|
|
444
479
|
annotateMode={true}
|
|
445
480
|
/>
|
|
446
481
|
);
|
|
@@ -448,22 +483,10 @@ describe('AssessmentPanel Component', () => {
|
|
|
448
483
|
expect(screen.getByTestId('detect-section')).toBeInTheDocument();
|
|
449
484
|
});
|
|
450
485
|
|
|
451
|
-
it('should not render DetectSection when onDetect is not provided', () => {
|
|
452
|
-
render(
|
|
453
|
-
<AssessmentPanel
|
|
454
|
-
{...defaultProps}
|
|
455
|
-
annotateMode={true}
|
|
456
|
-
/>
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
expect(screen.queryByTestId('detect-section')).not.toBeInTheDocument();
|
|
460
|
-
});
|
|
461
|
-
|
|
462
486
|
it('should not render DetectSection when annotateMode is false', () => {
|
|
463
|
-
|
|
487
|
+
renderWithEventBus(
|
|
464
488
|
<AssessmentPanel
|
|
465
489
|
{...defaultProps}
|
|
466
|
-
onDetect={vi.fn()}
|
|
467
490
|
annotateMode={false}
|
|
468
491
|
/>
|
|
469
492
|
);
|
|
@@ -471,20 +494,16 @@ describe('AssessmentPanel Component', () => {
|
|
|
471
494
|
expect(screen.queryByTestId('detect-section')).not.toBeInTheDocument();
|
|
472
495
|
});
|
|
473
496
|
|
|
474
|
-
it('should
|
|
475
|
-
|
|
476
|
-
render(
|
|
497
|
+
it('should render DetectSection with correct annotationType', () => {
|
|
498
|
+
renderWithEventBus(
|
|
477
499
|
<AssessmentPanel
|
|
478
500
|
{...defaultProps}
|
|
479
|
-
onDetect={onDetect}
|
|
480
501
|
annotateMode={true}
|
|
481
502
|
/>
|
|
482
503
|
);
|
|
483
504
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
expect(onDetect).toHaveBeenCalledWith('test instructions');
|
|
505
|
+
// DetectSection is rendered (mocked component renders the button)
|
|
506
|
+
expect(screen.getByText('Start Detection')).toBeInTheDocument();
|
|
488
507
|
});
|
|
489
508
|
});
|
|
490
509
|
|
|
@@ -492,7 +511,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
492
511
|
it('should show Cancel button when pendingAnnotation exists', () => {
|
|
493
512
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
494
513
|
|
|
495
|
-
|
|
514
|
+
renderWithEventBus(
|
|
496
515
|
<AssessmentPanel
|
|
497
516
|
{...defaultProps}
|
|
498
517
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -505,7 +524,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
505
524
|
it('should clear textarea when Cancel button is clicked', async () => {
|
|
506
525
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
507
526
|
|
|
508
|
-
|
|
527
|
+
renderWithEventBus(
|
|
509
528
|
<AssessmentPanel
|
|
510
529
|
{...defaultProps}
|
|
511
530
|
pendingAnnotation={pendingAnnotation}
|
|
@@ -524,7 +543,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
524
543
|
|
|
525
544
|
describe('Accessibility', () => {
|
|
526
545
|
it('should have proper heading structure', () => {
|
|
527
|
-
|
|
546
|
+
renderWithEventBus(<AssessmentPanel {...defaultProps} />);
|
|
528
547
|
|
|
529
548
|
const heading = screen.getByText(/Assessments/);
|
|
530
549
|
expect(heading).toHaveClass('semiont-panel-header__text');
|
|
@@ -533,7 +552,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
533
552
|
it('should have proper textarea attributes for new assessments', () => {
|
|
534
553
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
535
554
|
|
|
536
|
-
|
|
555
|
+
renderWithEventBus(
|
|
537
556
|
<AssessmentPanel
|
|
538
557
|
{...defaultProps}
|
|
539
558
|
pendingAnnotation={pendingAnnotation}
|