@semiont/react-ui 0.5.10 → 0.5.12
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/README.md +1 -1
- package/dist/{PdfAnnotationCanvas.client-P37SXBWQ.js → PdfAnnotationCanvas.client-75GY2EDR.js} +15 -6
- package/dist/PdfAnnotationCanvas.client-75GY2EDR.js.map +1 -0
- package/dist/{chunk-5LFFAVDI.js → chunk-PFUXQPWJ.js} +96 -96
- package/dist/{chunk-5LFFAVDI.js.map → chunk-PFUXQPWJ.js.map} +1 -1
- package/dist/{chunk-O2MD7TGE.js → chunk-VXASXU4K.js} +10 -2
- package/dist/chunk-VXASXU4K.js.map +1 -0
- package/dist/index.css +150 -112
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +334 -48
- package/dist/index.js +2494 -2201
- package/dist/index.js.map +1 -1
- package/dist/test-utils.d.ts +5 -1
- package/dist/test-utils.js +10 -4
- package/dist/test-utils.js.map +1 -1
- package/package.json +7 -7
- package/src/components/ResourceTagsInline.tsx +94 -11
- package/src/components/StatusDisplay.css +36 -0
- package/src/components/__tests__/ResourceTagsInline.test.tsx +101 -3
- package/src/components/annotation/AnnotateToolbar.tsx +53 -28
- package/src/components/annotation/__tests__/AnnotateToolbar.display.test.tsx +76 -0
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +124 -360
- package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +17 -5
- package/src/components/image-annotation/__tests__/AnnotationOverlay.click.test.tsx +137 -0
- package/src/components/image-annotation/__tests__/SvgDrawingCanvas.click.test.tsx +108 -0
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +17 -4
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +143 -7
- package/src/components/resource/AnnotateView.tsx +59 -38
- package/src/components/resource/BrowseView.tsx +172 -138
- package/src/components/resource/ResourceViewer.tsx +123 -130
- package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +55 -0
- package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +49 -0
- package/src/components/resource/__tests__/BrowseView.links.test.tsx +60 -0
- package/src/components/resource/__tests__/BrowseView.overlay-async.test.tsx +113 -0
- package/src/components/resource/__tests__/BrowseView.reference-hover.test.tsx +161 -0
- package/src/components/resource/__tests__/BrowseView.registry.test.tsx +43 -0
- package/src/components/resource/__tests__/BrowseView.test.tsx +133 -53
- package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +102 -0
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +12 -7
- package/src/components/resource/__tests__/ResourceViewer.toolbar-opt-out.test.tsx +135 -0
- package/src/components/resource/__tests__/ResourceViewer.toolbar-prefs.test.tsx +200 -0
- package/src/components/resource/__tests__/browse-renderers.dispatch.test.tsx +113 -0
- package/src/components/resource/__tests__/browse-renderers.test.tsx +34 -0
- package/src/components/resource/__tests__/inline-embedding.test.tsx +81 -0
- package/src/components/resource/__tests__/media-completeness.test.tsx +88 -0
- package/src/components/resource/browse-renderers.tsx +85 -0
- package/src/components/resource/panels/AssessmentEntry.tsx +5 -4
- package/src/components/resource/panels/AssessmentPanel.tsx +12 -5
- package/src/components/resource/panels/AssistSection.tsx +4 -3
- package/src/components/resource/panels/CommentEntry.tsx +5 -4
- package/src/components/resource/panels/CommentsPanel.tsx +12 -5
- package/src/components/resource/panels/HighlightEntry.tsx +5 -4
- package/src/components/resource/panels/HighlightPanel.tsx +12 -5
- package/src/components/resource/panels/ReferenceEntry.tsx +9 -10
- package/src/components/resource/panels/ReferencesPanel.tsx +15 -6
- package/src/components/resource/panels/ResourceInfoPanel.tsx +4 -3
- package/src/components/resource/panels/TagEntry.tsx +5 -3
- package/src/components/resource/panels/TaggingPanel.tsx +11 -4
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +15 -2
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +28 -20
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +39 -28
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +46 -17
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +65 -57
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +54 -24
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +27 -17
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +23 -17
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +48 -77
- package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +87 -0
- package/src/components/resource/panels/__tests__/ReferencesPanel.observable-flow.test.tsx +15 -9
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +78 -59
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +11 -4
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +33 -19
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +16 -7
- package/src/components/toolbar/Toolbar.css +14 -0
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +7 -17
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +43 -17
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +2 -14
- package/src/styles/features/resource-viewer.css +19 -0
- package/dist/PdfAnnotationCanvas.client-P37SXBWQ.js.map +0 -1
- package/dist/chunk-O2MD7TGE.js.map +0 -1
|
@@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
5
5
|
import '@testing-library/jest-dom';
|
|
6
6
|
import { ReferencesPanel } from '../ReferencesPanel';
|
|
7
7
|
import type { EventBus } from '@semiont/core';
|
|
8
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
8
9
|
import { createTestSemiontWrapper } from '../../../../test-utils';
|
|
9
10
|
|
|
10
11
|
// Composition-based event tracker
|
|
@@ -29,8 +30,20 @@ function createEventTracker() {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
// Per-test session/wrapper: created in beforeEach — test-utils disposes every
|
|
34
|
+
// created client in a module-scope afterEach, so a module-scope factory call
|
|
35
|
+
// would hand tests after the first a disposed client. The component is
|
|
36
|
+
// provider-free: the `session` passed as a prop (same factory call as the
|
|
37
|
+
// eventBus the tracker attaches to) is the only session it sees.
|
|
38
|
+
let session: SemiontSession;
|
|
39
|
+
let eventBus: EventBus;
|
|
40
|
+
let SemiontWrapper: React.ComponentType<{ children: React.ReactNode }>;
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
({ session, eventBus, SemiontWrapper } = createTestSemiontWrapper());
|
|
44
|
+
});
|
|
45
|
+
|
|
32
46
|
const renderWithEventBus = (component: React.ReactElement, tracker?: ReturnType<typeof createEventTracker>) => {
|
|
33
|
-
const { SemiontWrapper, eventBus } = createTestSemiontWrapper();
|
|
34
47
|
if (tracker) tracker._attach(eventBus);
|
|
35
48
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
36
49
|
<SemiontWrapper>{children}</SemiontWrapper>
|
|
@@ -86,6 +99,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
86
99
|
} as any;
|
|
87
100
|
|
|
88
101
|
const defaultProps = {
|
|
102
|
+
resourceId: 'res-1',
|
|
89
103
|
allEntityTypes: ['Person', 'Organization', 'Location', 'Date'],
|
|
90
104
|
isAssisting: false,
|
|
91
105
|
progress: null,
|
|
@@ -95,6 +109,11 @@ describe('ReferencesPanel Component', () => {
|
|
|
95
109
|
pendingAnnotation: null,
|
|
96
110
|
};
|
|
97
111
|
|
|
112
|
+
// Per-test props: merges the beforeEach-created session at render time.
|
|
113
|
+
// (Module/describe-scope defaultProps must stay session-free — disposal
|
|
114
|
+
// hazard, see note above renderWithEventBus.)
|
|
115
|
+
const panelProps = () => ({ ...defaultProps, session });
|
|
116
|
+
|
|
98
117
|
beforeEach(() => {
|
|
99
118
|
vi.clearAllMocks();
|
|
100
119
|
});
|
|
@@ -105,13 +124,13 @@ describe('ReferencesPanel Component', () => {
|
|
|
105
124
|
|
|
106
125
|
describe('Rendering', () => {
|
|
107
126
|
it('should render panel with title', () => {
|
|
108
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
127
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
109
128
|
|
|
110
129
|
expect(screen.getByText('Annotate References')).toBeInTheDocument();
|
|
111
130
|
});
|
|
112
131
|
|
|
113
132
|
it('should render all entity type buttons', () => {
|
|
114
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
133
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
115
134
|
|
|
116
135
|
expect(screen.getByText('Person')).toBeInTheDocument();
|
|
117
136
|
expect(screen.getByText('Organization')).toBeInTheDocument();
|
|
@@ -120,13 +139,13 @@ describe('ReferencesPanel Component', () => {
|
|
|
120
139
|
});
|
|
121
140
|
|
|
122
141
|
it('should show message when no entity types available', () => {
|
|
123
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
142
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} allEntityTypes={[]} />);
|
|
124
143
|
|
|
125
144
|
expect(screen.getByText('No entity types available')).toBeInTheDocument();
|
|
126
145
|
});
|
|
127
146
|
|
|
128
147
|
it('should render start detection button', () => {
|
|
129
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
148
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
130
149
|
|
|
131
150
|
expect(screen.getByTitle('Annotate')).toBeInTheDocument();
|
|
132
151
|
});
|
|
@@ -134,7 +153,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
134
153
|
|
|
135
154
|
describe('Entity Type Selection', () => {
|
|
136
155
|
it('should toggle entity type selection on click', async () => {
|
|
137
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
156
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
138
157
|
|
|
139
158
|
const personButton = screen.getByText('Person');
|
|
140
159
|
|
|
@@ -153,7 +172,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
153
172
|
});
|
|
154
173
|
|
|
155
174
|
it('should allow multiple selections', async () => {
|
|
156
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
175
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
157
176
|
|
|
158
177
|
const personButton = screen.getByText('Person');
|
|
159
178
|
const orgButton = screen.getByText('Organization');
|
|
@@ -169,7 +188,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
169
188
|
});
|
|
170
189
|
|
|
171
190
|
it('should deselect when clicking selected type', async () => {
|
|
172
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
191
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
173
192
|
|
|
174
193
|
const personButton = screen.getByText('Person');
|
|
175
194
|
|
|
@@ -181,7 +200,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
181
200
|
});
|
|
182
201
|
|
|
183
202
|
it('should show selected count', async () => {
|
|
184
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
203
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
185
204
|
|
|
186
205
|
const personButton = screen.getByText('Person');
|
|
187
206
|
const orgButton = screen.getByText('Organization');
|
|
@@ -198,7 +217,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
198
217
|
});
|
|
199
218
|
|
|
200
219
|
it('should not show selected count when none selected', () => {
|
|
201
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
220
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
202
221
|
|
|
203
222
|
expect(screen.queryByText(/selected/i)).not.toBeInTheDocument();
|
|
204
223
|
});
|
|
@@ -206,7 +225,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
206
225
|
|
|
207
226
|
describe('Button Styling', () => {
|
|
208
227
|
it('should style selected buttons differently', async () => {
|
|
209
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
228
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
210
229
|
|
|
211
230
|
const personButton = screen.getByText('Person');
|
|
212
231
|
|
|
@@ -221,7 +240,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
221
240
|
});
|
|
222
241
|
|
|
223
242
|
it('should have proper ARIA attributes', () => {
|
|
224
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
243
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
225
244
|
|
|
226
245
|
const personButton = screen.getByText('Person');
|
|
227
246
|
|
|
@@ -230,7 +249,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
230
249
|
});
|
|
231
250
|
|
|
232
251
|
it('should have focus styles', () => {
|
|
233
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
252
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
234
253
|
|
|
235
254
|
const personButton = screen.getByText('Person');
|
|
236
255
|
|
|
@@ -240,7 +259,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
240
259
|
|
|
241
260
|
describe('Start Annotate Button', () => {
|
|
242
261
|
it('should be disabled when no types selected', () => {
|
|
243
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
262
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
244
263
|
|
|
245
264
|
const startButton = screen.getByTitle('Annotate');
|
|
246
265
|
|
|
@@ -248,7 +267,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
248
267
|
});
|
|
249
268
|
|
|
250
269
|
it('should be enabled when types are selected', async () => {
|
|
251
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
270
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
252
271
|
|
|
253
272
|
const personButton = screen.getByText('Person');
|
|
254
273
|
await userEvent.click(personButton);
|
|
@@ -260,7 +279,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
260
279
|
|
|
261
280
|
it('should emit annotate:detect-request event with selected types and includeDescriptiveReferences', async () => {
|
|
262
281
|
const tracker = createEventTracker();
|
|
263
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
282
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />, tracker);
|
|
264
283
|
|
|
265
284
|
await userEvent.click(screen.getByText('Person'));
|
|
266
285
|
await userEvent.click(screen.getByText('Organization'));
|
|
@@ -281,7 +300,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
281
300
|
|
|
282
301
|
it('should emit annotate:detect-request event with includeDescriptiveReferences when checkbox is checked', async () => {
|
|
283
302
|
const tracker = createEventTracker();
|
|
284
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
303
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />, tracker);
|
|
285
304
|
|
|
286
305
|
await userEvent.click(screen.getByText('Person'));
|
|
287
306
|
|
|
@@ -304,7 +323,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
304
323
|
});
|
|
305
324
|
|
|
306
325
|
it('should clear selected types after detection starts', async () => {
|
|
307
|
-
const { rerender } = renderWithEventBus(<ReferencesPanel {...
|
|
326
|
+
const { rerender } = renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
308
327
|
|
|
309
328
|
await userEvent.click(screen.getByText('Person'));
|
|
310
329
|
|
|
@@ -314,7 +333,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
314
333
|
// Simulate detection starting
|
|
315
334
|
rerender(
|
|
316
335
|
<ReferencesPanel
|
|
317
|
-
{...
|
|
336
|
+
{...panelProps()}
|
|
318
337
|
isAssisting={true}
|
|
319
338
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
320
339
|
/>
|
|
@@ -323,7 +342,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
323
342
|
// Simulate detection completing
|
|
324
343
|
rerender(
|
|
325
344
|
<ReferencesPanel
|
|
326
|
-
{...
|
|
345
|
+
{...panelProps()}
|
|
327
346
|
isAssisting={false}
|
|
328
347
|
progress={{
|
|
329
348
|
stage: 'complete',
|
|
@@ -339,7 +358,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
339
358
|
});
|
|
340
359
|
|
|
341
360
|
it('should have proper styling when disabled', () => {
|
|
342
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
361
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
343
362
|
|
|
344
363
|
const startButton = screen.getByTitle('Annotate');
|
|
345
364
|
|
|
@@ -350,7 +369,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
350
369
|
});
|
|
351
370
|
|
|
352
371
|
it('should have proper styling when enabled', async () => {
|
|
353
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
372
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
354
373
|
|
|
355
374
|
await userEvent.click(screen.getByText('Person'));
|
|
356
375
|
|
|
@@ -367,7 +386,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
367
386
|
it('should show progress widget when detecting', () => {
|
|
368
387
|
renderWithEventBus(
|
|
369
388
|
<ReferencesPanel
|
|
370
|
-
{...
|
|
389
|
+
{...panelProps()}
|
|
371
390
|
isAssisting={true}
|
|
372
391
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
373
392
|
/>
|
|
@@ -389,7 +408,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
389
408
|
|
|
390
409
|
renderWithEventBus(
|
|
391
410
|
<ReferencesPanel
|
|
392
|
-
{...
|
|
411
|
+
{...panelProps()}
|
|
393
412
|
isAssisting={true}
|
|
394
413
|
progress={progress}
|
|
395
414
|
/>
|
|
@@ -403,7 +422,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
403
422
|
it('should hide entity type selection during detection', () => {
|
|
404
423
|
renderWithEventBus(
|
|
405
424
|
<ReferencesPanel
|
|
406
|
-
{...
|
|
425
|
+
{...panelProps()}
|
|
407
426
|
isAssisting={true}
|
|
408
427
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
409
428
|
/>
|
|
@@ -416,7 +435,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
416
435
|
it('should render cancel button when detecting', async () => {
|
|
417
436
|
renderWithEventBus(
|
|
418
437
|
<ReferencesPanel
|
|
419
|
-
{...
|
|
438
|
+
{...panelProps()}
|
|
420
439
|
isAssisting={true}
|
|
421
440
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
422
441
|
/>
|
|
@@ -431,7 +450,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
431
450
|
it('should show completed log after detection finishes', () => {
|
|
432
451
|
const { rerender } = renderWithEventBus(
|
|
433
452
|
<ReferencesPanel
|
|
434
|
-
{...
|
|
453
|
+
{...panelProps()}
|
|
435
454
|
isAssisting={false}
|
|
436
455
|
progress={{
|
|
437
456
|
stage: 'complete',
|
|
@@ -448,7 +467,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
448
467
|
// Parent clears progress after completion
|
|
449
468
|
rerender(
|
|
450
469
|
<ReferencesPanel
|
|
451
|
-
{...
|
|
470
|
+
{...panelProps()}
|
|
452
471
|
isAssisting={false}
|
|
453
472
|
progress={null}
|
|
454
473
|
/>
|
|
@@ -461,7 +480,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
461
480
|
it('should show found counts in log', () => {
|
|
462
481
|
const { rerender } = renderWithEventBus(
|
|
463
482
|
<ReferencesPanel
|
|
464
|
-
{...
|
|
483
|
+
{...panelProps()}
|
|
465
484
|
isAssisting={false}
|
|
466
485
|
progress={{
|
|
467
486
|
stage: 'complete',
|
|
@@ -473,7 +492,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
473
492
|
);
|
|
474
493
|
|
|
475
494
|
rerender(
|
|
476
|
-
<ReferencesPanel {...
|
|
495
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
477
496
|
);
|
|
478
497
|
expect(screen.getByText(/Found.*5/i)).toBeInTheDocument();
|
|
479
498
|
});
|
|
@@ -481,7 +500,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
481
500
|
it('should show checkmarks for completed types', () => {
|
|
482
501
|
const { rerender } = renderWithEventBus(
|
|
483
502
|
<ReferencesPanel
|
|
484
|
-
{...
|
|
503
|
+
{...panelProps()}
|
|
485
504
|
isAssisting={false}
|
|
486
505
|
progress={{
|
|
487
506
|
stage: 'complete',
|
|
@@ -493,7 +512,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
493
512
|
);
|
|
494
513
|
|
|
495
514
|
rerender(
|
|
496
|
-
<ReferencesPanel {...
|
|
515
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
497
516
|
);
|
|
498
517
|
expect(screen.getByText('✓')).toBeInTheDocument();
|
|
499
518
|
});
|
|
@@ -501,7 +520,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
501
520
|
it('should show detection log and selection UI together after completion', () => {
|
|
502
521
|
const { rerender } = renderWithEventBus(
|
|
503
522
|
<ReferencesPanel
|
|
504
|
-
{...
|
|
523
|
+
{...panelProps()}
|
|
505
524
|
isAssisting={false}
|
|
506
525
|
progress={{
|
|
507
526
|
stage: 'complete',
|
|
@@ -513,7 +532,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
513
532
|
);
|
|
514
533
|
|
|
515
534
|
rerender(
|
|
516
|
-
<ReferencesPanel {...
|
|
535
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
517
536
|
);
|
|
518
537
|
|
|
519
538
|
// Should show both the completed log AND the selection UI
|
|
@@ -524,7 +543,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
524
543
|
it('should show selection UI immediately after detection completes', async () => {
|
|
525
544
|
const { rerender } = renderWithEventBus(
|
|
526
545
|
<ReferencesPanel
|
|
527
|
-
{...
|
|
546
|
+
{...panelProps()}
|
|
528
547
|
isAssisting={false}
|
|
529
548
|
progress={{
|
|
530
549
|
stage: 'complete',
|
|
@@ -536,7 +555,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
536
555
|
);
|
|
537
556
|
|
|
538
557
|
rerender(
|
|
539
|
-
<ReferencesPanel {...
|
|
558
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
540
559
|
);
|
|
541
560
|
|
|
542
561
|
// Selection UI should be immediately available (no button click needed)
|
|
@@ -547,7 +566,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
547
566
|
it('should not show log when empty', () => {
|
|
548
567
|
renderWithEventBus(
|
|
549
568
|
<ReferencesPanel
|
|
550
|
-
{...
|
|
569
|
+
{...panelProps()}
|
|
551
570
|
isAssisting={false}
|
|
552
571
|
progress={{
|
|
553
572
|
stage: 'complete',
|
|
@@ -566,7 +585,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
566
585
|
|
|
567
586
|
describe('State Transitions', () => {
|
|
568
587
|
it('should transition from idle to detecting', () => {
|
|
569
|
-
const { rerender } = renderWithEventBus(<ReferencesPanel {...
|
|
588
|
+
const { rerender } = renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
570
589
|
|
|
571
590
|
// Idle state
|
|
572
591
|
expect(screen.getByText('Select entity types')).toBeInTheDocument();
|
|
@@ -574,7 +593,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
574
593
|
// Start detecting
|
|
575
594
|
rerender(
|
|
576
595
|
<ReferencesPanel
|
|
577
|
-
{...
|
|
596
|
+
{...panelProps()}
|
|
578
597
|
isAssisting={true}
|
|
579
598
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
580
599
|
/>
|
|
@@ -588,7 +607,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
588
607
|
it('should transition from detecting to complete', () => {
|
|
589
608
|
const { rerender } = renderWithEventBus(
|
|
590
609
|
<ReferencesPanel
|
|
591
|
-
{...
|
|
610
|
+
{...panelProps()}
|
|
592
611
|
isAssisting={true}
|
|
593
612
|
progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
|
|
594
613
|
/>
|
|
@@ -600,7 +619,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
600
619
|
// Complete - first trigger useEffect to copy to lastDetectionLog
|
|
601
620
|
rerender(
|
|
602
621
|
<ReferencesPanel
|
|
603
|
-
{...
|
|
622
|
+
{...panelProps()}
|
|
604
623
|
isAssisting={false}
|
|
605
624
|
progress={{
|
|
606
625
|
stage: 'complete',
|
|
@@ -613,7 +632,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
613
632
|
|
|
614
633
|
// Then clear progress to show the log
|
|
615
634
|
rerender(
|
|
616
|
-
<ReferencesPanel {...
|
|
635
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
617
636
|
);
|
|
618
637
|
|
|
619
638
|
expect(screen.queryByTestId('annotation-progress-widget')).not.toBeInTheDocument();
|
|
@@ -625,7 +644,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
625
644
|
it('should show selection UI after detection completes', async () => {
|
|
626
645
|
const { rerender } = renderWithEventBus(
|
|
627
646
|
<ReferencesPanel
|
|
628
|
-
{...
|
|
647
|
+
{...panelProps()}
|
|
629
648
|
isAssisting={false}
|
|
630
649
|
progress={{
|
|
631
650
|
stage: 'complete',
|
|
@@ -638,14 +657,14 @@ describe('ReferencesPanel Component', () => {
|
|
|
638
657
|
|
|
639
658
|
// Clear progress to show the log
|
|
640
659
|
rerender(
|
|
641
|
-
<ReferencesPanel {...
|
|
660
|
+
<ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
|
|
642
661
|
);
|
|
643
662
|
|
|
644
663
|
// Selection UI should be immediately available
|
|
645
664
|
expect(screen.getByText('Select entity types')).toBeInTheDocument();
|
|
646
665
|
|
|
647
666
|
rerender(
|
|
648
|
-
<ReferencesPanel {...
|
|
667
|
+
<ReferencesPanel {...panelProps()} />
|
|
649
668
|
);
|
|
650
669
|
|
|
651
670
|
expect(screen.getByText('Select entity types')).toBeInTheDocument();
|
|
@@ -655,7 +674,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
655
674
|
describe('Edge Cases', () => {
|
|
656
675
|
it('should handle empty entity types array', () => {
|
|
657
676
|
expect(() => {
|
|
658
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
677
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} allEntityTypes={[]} />);
|
|
659
678
|
}).not.toThrow();
|
|
660
679
|
});
|
|
661
680
|
|
|
@@ -663,7 +682,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
663
682
|
const manyTypes = Array.from({ length: 50 }, (_, i) => `Type${i}`);
|
|
664
683
|
|
|
665
684
|
expect(() => {
|
|
666
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
685
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} allEntityTypes={manyTypes} />);
|
|
667
686
|
}).not.toThrow();
|
|
668
687
|
|
|
669
688
|
expect(screen.getByText('Type0')).toBeInTheDocument();
|
|
@@ -673,7 +692,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
673
692
|
it('should handle entity types with special characters', () => {
|
|
674
693
|
const specialTypes = ['Type-A', 'Type_B', 'Type.C', 'Type/D'];
|
|
675
694
|
|
|
676
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
695
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} allEntityTypes={specialTypes} />);
|
|
677
696
|
|
|
678
697
|
specialTypes.forEach(type => {
|
|
679
698
|
expect(screen.getByText(type)).toBeInTheDocument();
|
|
@@ -681,7 +700,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
681
700
|
});
|
|
682
701
|
|
|
683
702
|
it('should handle selecting and deselecting all types', async () => {
|
|
684
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
703
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
685
704
|
|
|
686
705
|
// Select all
|
|
687
706
|
for (const type of defaultProps.allEntityTypes) {
|
|
@@ -703,7 +722,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
703
722
|
});
|
|
704
723
|
|
|
705
724
|
it('should handle rapid selection changes', async () => {
|
|
706
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
725
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
707
726
|
|
|
708
727
|
const personButton = screen.getByText('Person');
|
|
709
728
|
|
|
@@ -719,7 +738,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
719
738
|
it('should handle zero found count in results', () => {
|
|
720
739
|
renderWithEventBus(
|
|
721
740
|
<ReferencesPanel
|
|
722
|
-
{...
|
|
741
|
+
{...panelProps()}
|
|
723
742
|
isAssisting={false}
|
|
724
743
|
progress={{
|
|
725
744
|
stage: 'complete',
|
|
@@ -737,7 +756,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
737
756
|
expect(() => {
|
|
738
757
|
renderWithEventBus(
|
|
739
758
|
<ReferencesPanel
|
|
740
|
-
{...
|
|
759
|
+
{...panelProps()}
|
|
741
760
|
isAssisting={false}
|
|
742
761
|
progress={undefined as any}
|
|
743
762
|
/>
|
|
@@ -748,21 +767,21 @@ describe('ReferencesPanel Component', () => {
|
|
|
748
767
|
|
|
749
768
|
describe('Styling and Appearance', () => {
|
|
750
769
|
it('should have proper panel structure', () => {
|
|
751
|
-
const { container } = renderWithEventBus(<ReferencesPanel {...
|
|
770
|
+
const { container } = renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
752
771
|
|
|
753
772
|
const panel = container.firstChild as HTMLElement;
|
|
754
773
|
expect(panel).toHaveClass('semiont-panel');
|
|
755
774
|
});
|
|
756
775
|
|
|
757
776
|
it('should support dark mode', () => {
|
|
758
|
-
const { container } = renderWithEventBus(<ReferencesPanel {...
|
|
777
|
+
const { container } = renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
759
778
|
|
|
760
779
|
const panel = container.firstChild as HTMLElement;
|
|
761
780
|
expect(panel).toHaveClass('semiont-panel');
|
|
762
781
|
});
|
|
763
782
|
|
|
764
783
|
it('should have title without emoji', () => {
|
|
765
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
784
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
766
785
|
|
|
767
786
|
// The emoji is no longer in the title (it's only in the tab now)
|
|
768
787
|
const title = screen.getByRole('heading', { level: 2 });
|
|
@@ -771,7 +790,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
771
790
|
});
|
|
772
791
|
|
|
773
792
|
it('should have proper button layout', () => {
|
|
774
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
793
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
775
794
|
|
|
776
795
|
const buttonContainer = screen.getByText('Person').parentElement;
|
|
777
796
|
expect(buttonContainer).toHaveClass('semiont-assist-widget__chips');
|
|
@@ -780,7 +799,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
780
799
|
|
|
781
800
|
describe('Accessibility', () => {
|
|
782
801
|
it('should have proper ARIA labels for selection', async () => {
|
|
783
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
802
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
784
803
|
|
|
785
804
|
const personButton = screen.getByText('Person');
|
|
786
805
|
|
|
@@ -794,7 +813,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
794
813
|
});
|
|
795
814
|
|
|
796
815
|
it('should have proper ARIA pressed states', async () => {
|
|
797
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
816
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
798
817
|
|
|
799
818
|
const personButton = screen.getByText('Person');
|
|
800
819
|
|
|
@@ -806,7 +825,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
806
825
|
});
|
|
807
826
|
|
|
808
827
|
it('should be keyboard navigable', () => {
|
|
809
|
-
renderWithEventBus(<ReferencesPanel {...
|
|
828
|
+
renderWithEventBus(<ReferencesPanel {...panelProps()} />);
|
|
810
829
|
|
|
811
830
|
const personButton = screen.getByText('Person');
|
|
812
831
|
personButton.focus();
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
5
|
import type { EventBus } from '@semiont/core';
|
|
6
|
-
import type { SemiontClient } from '@semiont/sdk';
|
|
6
|
+
import type { SemiontClient, SemiontSession } from '@semiont/sdk';
|
|
7
7
|
import { ResourceInfoPanel } from '../ResourceInfoPanel';
|
|
8
8
|
import { createTestSemiontWrapper } from '../../../../test-utils';
|
|
9
9
|
|
|
@@ -87,13 +87,15 @@ function createEventTracker() {
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
const renderWithEventBus = (component: React.ReactElement
|
|
91
|
-
const { SemiontWrapper, eventBus, client } = createTestSemiontWrapper();
|
|
90
|
+
const renderWithEventBus = (component: React.ReactElement<{ session: SemiontSession | null }>, tracker?: ReturnType<typeof createEventTracker>) => {
|
|
91
|
+
const { SemiontWrapper, eventBus, client, session } = createTestSemiontWrapper();
|
|
92
92
|
if (tracker) tracker._attach(eventBus, client);
|
|
93
93
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
94
94
|
<SemiontWrapper>{children}</SemiontWrapper>
|
|
95
95
|
);
|
|
96
|
-
|
|
96
|
+
// The component is provider-free: inject the factory session so it is the
|
|
97
|
+
// SAME session whose client the tracker spies on / whose bus it subscribes.
|
|
98
|
+
return render(React.cloneElement(component, { session }), { wrapper: Wrapper });
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
describe('ResourceInfoPanel Component', () => {
|
|
@@ -103,6 +105,11 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
103
105
|
documentLocale: undefined,
|
|
104
106
|
primaryMediaType: undefined,
|
|
105
107
|
primaryByteSize: undefined,
|
|
108
|
+
// Satisfies JSX at element construction only; renderWithEventBus always
|
|
109
|
+
// replaces it (via cloneElement) with the per-test factory session. Never
|
|
110
|
+
// put a live session here — module-scope clients get disposed after the
|
|
111
|
+
// first test.
|
|
112
|
+
session: null,
|
|
106
113
|
};
|
|
107
114
|
|
|
108
115
|
beforeEach(() => {
|