@semiont/react-ui 0.5.11 → 0.5.13
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/{PdfAnnotationCanvas.client-KWQ7XDWT.js → PdfAnnotationCanvas.client-75GY2EDR.js} +12 -6
- package/dist/PdfAnnotationCanvas.client-75GY2EDR.js.map +1 -0
- package/dist/{chunk-O2MD7TGE.js → chunk-VXASXU4K.js} +10 -2
- package/dist/chunk-VXASXU4K.js.map +1 -0
- package/dist/index.d.ts +54 -16
- package/dist/index.js +395 -343
- package/dist/index.js.map +1 -1
- package/dist/test-utils.d.ts +5 -1
- package/dist/test-utils.js +3 -2
- package/dist/test-utils.js.map +1 -1
- package/package.json +5 -5
- package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +12 -4
- 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 +12 -4
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +137 -1
- package/src/components/resource/BrowseView.tsx +14 -6
- package/src/components/resource/ResourceViewer.tsx +6 -4
- package/src/components/resource/__tests__/BrowseView.test.tsx +98 -31
- package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +40 -1
- package/src/components/resource/__tests__/browse-renderers.dispatch.test.tsx +113 -0
- package/src/components/resource/browse-renderers.tsx +26 -4
- package/src/components/resource/panels/AssessmentEntry.tsx +5 -4
- package/src/components/resource/panels/AssessmentPanel.tsx +8 -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 +8 -5
- package/src/components/resource/panels/HighlightEntry.tsx +5 -4
- package/src/components/resource/panels/HighlightPanel.tsx +8 -5
- package/src/components/resource/panels/ReferenceEntry.tsx +9 -10
- package/src/components/resource/panels/ReferencesPanel.tsx +11 -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 +7 -4
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +10 -0
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +28 -20
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +38 -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 +53 -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 +77 -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 +15 -7
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +3 -0
- package/dist/PdfAnnotationCanvas.client-KWQ7XDWT.js.map +0 -1
- package/dist/chunk-O2MD7TGE.js.map +0 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
|
4
|
-
import { renderWithProviders } from '../../../../test-utils';
|
|
4
|
+
import { renderWithProviders, createTestSemiontWrapper } from '../../../../test-utils';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { CommentEntry } from '../CommentEntry';
|
|
8
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
8
9
|
|
|
9
|
-
import type { Annotation, AnnotationId } from '@semiont/core';
|
|
10
|
+
import type { Annotation, AnnotationId, EventBus } from '@semiont/core';
|
|
10
11
|
|
|
11
12
|
// Mock TranslationContext
|
|
12
13
|
vi.mock('../../../../contexts/TranslationContext', () => ({
|
|
@@ -99,8 +100,17 @@ describe('CommentEntry Component', () => {
|
|
|
99
100
|
isFocused: false,
|
|
100
101
|
};
|
|
101
102
|
|
|
103
|
+
// Per-test session/bus — created in beforeEach because test-utils disposes
|
|
104
|
+
// every created client after each test (a module-scope session would be
|
|
105
|
+
// disposed after the first test). The component is provider-free: the
|
|
106
|
+
// session prop is the only session it sees, so event assertions subscribe
|
|
107
|
+
// on the eventBus from the SAME factory call.
|
|
108
|
+
let session: SemiontSession;
|
|
109
|
+
let eventBus: EventBus;
|
|
110
|
+
|
|
102
111
|
beforeEach(() => {
|
|
103
112
|
vi.clearAllMocks();
|
|
113
|
+
({ session, eventBus } = createTestSemiontWrapper());
|
|
104
114
|
mockGetCommentText.mockReturnValue('This is a test comment');
|
|
105
115
|
mockGetAnnotationExactText.mockReturnValue('This is th');
|
|
106
116
|
|
|
@@ -114,14 +124,14 @@ describe('CommentEntry Component', () => {
|
|
|
114
124
|
|
|
115
125
|
describe('Rendering', () => {
|
|
116
126
|
it('should render comment with text and metadata', () => {
|
|
117
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
127
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
118
128
|
|
|
119
129
|
expect(screen.getByText('This is a test comment')).toBeInTheDocument();
|
|
120
130
|
expect(screen.getByText(/user@example.com/)).toBeInTheDocument();
|
|
121
131
|
});
|
|
122
132
|
|
|
123
133
|
it('should render selected text quote', () => {
|
|
124
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
134
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
125
135
|
|
|
126
136
|
const quote = container.querySelector('.semiont-annotation-entry__quote');
|
|
127
137
|
expect(quote).toBeInTheDocument();
|
|
@@ -132,7 +142,7 @@ describe('CommentEntry Component', () => {
|
|
|
132
142
|
const longText = 'A'.repeat(150);
|
|
133
143
|
mockGetAnnotationExactText.mockReturnValue(longText);
|
|
134
144
|
|
|
135
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
145
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
136
146
|
|
|
137
147
|
expect(screen.getByText(new RegExp(`"${'A'.repeat(100)}`))).toBeInTheDocument();
|
|
138
148
|
expect(screen.getByText(/\.\.\./)).toBeInTheDocument();
|
|
@@ -141,6 +151,7 @@ describe('CommentEntry Component', () => {
|
|
|
141
151
|
it('should render creator name from creator object', () => {
|
|
142
152
|
renderWithProviders(
|
|
143
153
|
<CommentEntry
|
|
154
|
+
session={session}
|
|
144
155
|
{...defaultProps}
|
|
145
156
|
comment={mockCommentStates.withCreatorObject}
|
|
146
157
|
/>
|
|
@@ -150,7 +161,7 @@ describe('CommentEntry Component', () => {
|
|
|
150
161
|
});
|
|
151
162
|
|
|
152
163
|
it('should handle creator as object with name', () => {
|
|
153
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
164
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
154
165
|
|
|
155
166
|
expect(screen.getByText(/user@example.com/)).toBeInTheDocument();
|
|
156
167
|
});
|
|
@@ -161,6 +172,7 @@ describe('CommentEntry Component', () => {
|
|
|
161
172
|
|
|
162
173
|
renderWithProviders(
|
|
163
174
|
<CommentEntry
|
|
175
|
+
session={session}
|
|
164
176
|
{...defaultProps}
|
|
165
177
|
comment={commentWithoutCreator}
|
|
166
178
|
/>
|
|
@@ -172,6 +184,7 @@ describe('CommentEntry Component', () => {
|
|
|
172
184
|
it('should format relative time correctly for recent comments', () => {
|
|
173
185
|
renderWithProviders(
|
|
174
186
|
<CommentEntry
|
|
187
|
+
session={session}
|
|
175
188
|
{...defaultProps}
|
|
176
189
|
comment={mockCommentStates.recentComment}
|
|
177
190
|
/>
|
|
@@ -183,6 +196,7 @@ describe('CommentEntry Component', () => {
|
|
|
183
196
|
it('should format relative time correctly for old comments', () => {
|
|
184
197
|
renderWithProviders(
|
|
185
198
|
<CommentEntry
|
|
199
|
+
session={session}
|
|
186
200
|
{...defaultProps}
|
|
187
201
|
comment={mockCommentStates.oldComment}
|
|
188
202
|
/>
|
|
@@ -195,7 +209,7 @@ describe('CommentEntry Component', () => {
|
|
|
195
209
|
describe('Focus State', () => {
|
|
196
210
|
it('should apply focus styles when focused', () => {
|
|
197
211
|
const { container } = renderWithProviders(
|
|
198
|
-
<CommentEntry {...defaultProps} isFocused={true} />
|
|
212
|
+
<CommentEntry session={session} {...defaultProps} isFocused={true} />
|
|
199
213
|
);
|
|
200
214
|
|
|
201
215
|
const commentDiv = container.querySelector('.semiont-annotation-entry');
|
|
@@ -205,7 +219,7 @@ describe('CommentEntry Component', () => {
|
|
|
205
219
|
|
|
206
220
|
it('should not apply focus styles when not focused', () => {
|
|
207
221
|
const { container } = renderWithProviders(
|
|
208
|
-
<CommentEntry {...defaultProps} isFocused={false} />
|
|
222
|
+
<CommentEntry session={session} {...defaultProps} isFocused={false} />
|
|
209
223
|
);
|
|
210
224
|
|
|
211
225
|
const commentDiv = container.querySelector('.semiont-skeleton-outline');
|
|
@@ -217,14 +231,14 @@ describe('CommentEntry Component', () => {
|
|
|
217
231
|
Element.prototype.scrollIntoView = mockScrollIntoView;
|
|
218
232
|
|
|
219
233
|
const { rerender } = renderWithProviders(
|
|
220
|
-
<CommentEntry {...defaultProps} isFocused={false} />
|
|
234
|
+
<CommentEntry session={session} {...defaultProps} isFocused={false} />
|
|
221
235
|
);
|
|
222
236
|
|
|
223
237
|
// Clear any initial calls
|
|
224
238
|
mockScrollIntoView.mockClear();
|
|
225
239
|
|
|
226
240
|
// Becomes focused
|
|
227
|
-
rerender(<CommentEntry {...defaultProps} isFocused={true} />);
|
|
241
|
+
rerender(<CommentEntry session={session} {...defaultProps} isFocused={true} />);
|
|
228
242
|
|
|
229
243
|
await waitFor(() => {
|
|
230
244
|
expect(mockScrollIntoView).toHaveBeenCalledWith({
|
|
@@ -239,13 +253,12 @@ describe('CommentEntry Component', () => {
|
|
|
239
253
|
it('should emit browse:click event when comment is clicked', async () => {
|
|
240
254
|
const clickHandler = vi.fn();
|
|
241
255
|
|
|
242
|
-
const { container
|
|
243
|
-
<CommentEntry {...defaultProps}
|
|
244
|
-
{ returnEventBus: true }
|
|
256
|
+
const { container } = renderWithProviders(
|
|
257
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
245
258
|
);
|
|
246
259
|
|
|
247
260
|
// Subscribe to actual event on real event bus
|
|
248
|
-
const subscription = eventBus
|
|
261
|
+
const subscription = eventBus.get('browse:click').subscribe(clickHandler);
|
|
249
262
|
|
|
250
263
|
const commentDiv = container.firstChild as HTMLElement;
|
|
251
264
|
await userEvent.click(commentDiv);
|
|
@@ -260,7 +273,7 @@ describe('CommentEntry Component', () => {
|
|
|
260
273
|
});
|
|
261
274
|
|
|
262
275
|
it('should be clickable with cursor-pointer class', () => {
|
|
263
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
276
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
264
277
|
|
|
265
278
|
const commentDiv = container.firstChild as HTMLElement;
|
|
266
279
|
expect(commentDiv).toHaveClass('semiont-annotation-entry');
|
|
@@ -272,13 +285,12 @@ describe('CommentEntry Component', () => {
|
|
|
272
285
|
vi.useFakeTimers();
|
|
273
286
|
const hoverHandler = vi.fn();
|
|
274
287
|
|
|
275
|
-
const { container
|
|
276
|
-
<CommentEntry {...defaultProps}
|
|
277
|
-
{ returnEventBus: true }
|
|
288
|
+
const { container } = renderWithProviders(
|
|
289
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
278
290
|
);
|
|
279
291
|
|
|
280
292
|
// Subscribe to actual event
|
|
281
|
-
const subscription = eventBus
|
|
293
|
+
const subscription = eventBus.get('beckon:hover').subscribe(hoverHandler);
|
|
282
294
|
|
|
283
295
|
const commentDiv = container.firstChild as HTMLElement;
|
|
284
296
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -300,13 +312,12 @@ describe('CommentEntry Component', () => {
|
|
|
300
312
|
vi.useFakeTimers();
|
|
301
313
|
const hoverHandler = vi.fn();
|
|
302
314
|
|
|
303
|
-
const { container
|
|
304
|
-
<CommentEntry {...defaultProps}
|
|
305
|
-
{ returnEventBus: true }
|
|
315
|
+
const { container } = renderWithProviders(
|
|
316
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
306
317
|
);
|
|
307
318
|
|
|
308
319
|
// Subscribe to actual event
|
|
309
|
-
const subscription = eventBus
|
|
320
|
+
const subscription = eventBus.get('beckon:hover').subscribe(hoverHandler);
|
|
310
321
|
|
|
311
322
|
const commentDiv = container.firstChild as HTMLElement;
|
|
312
323
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -326,12 +337,11 @@ describe('CommentEntry Component', () => {
|
|
|
326
337
|
vi.useFakeTimers();
|
|
327
338
|
const hoverHandler = vi.fn();
|
|
328
339
|
|
|
329
|
-
const { container
|
|
330
|
-
<CommentEntry {...defaultProps}
|
|
331
|
-
{ returnEventBus: true }
|
|
340
|
+
const { container } = renderWithProviders(
|
|
341
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
332
342
|
);
|
|
333
343
|
|
|
334
|
-
const subscription = eventBus
|
|
344
|
+
const subscription = eventBus.get('beckon:hover').subscribe(hoverHandler);
|
|
335
345
|
|
|
336
346
|
const commentDiv = container.firstChild as HTMLElement;
|
|
337
347
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -348,7 +358,7 @@ describe('CommentEntry Component', () => {
|
|
|
348
358
|
|
|
349
359
|
it('should handle hover events without errors', () => {
|
|
350
360
|
const { container } = renderWithProviders(
|
|
351
|
-
<CommentEntry {...defaultProps} />
|
|
361
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
352
362
|
);
|
|
353
363
|
|
|
354
364
|
const commentDiv = container.firstChild as HTMLElement;
|
|
@@ -362,13 +372,13 @@ describe('CommentEntry Component', () => {
|
|
|
362
372
|
|
|
363
373
|
describe('Edit Functionality', () => {
|
|
364
374
|
it('should show edit button', () => {
|
|
365
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
375
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
366
376
|
|
|
367
377
|
expect(screen.getByText('Edit')).toBeInTheDocument();
|
|
368
378
|
});
|
|
369
379
|
|
|
370
380
|
it('should enter edit mode when edit button is clicked', async () => {
|
|
371
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
381
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
372
382
|
|
|
373
383
|
const editButton = screen.getByText('Edit');
|
|
374
384
|
await userEvent.click(editButton);
|
|
@@ -381,7 +391,7 @@ describe('CommentEntry Component', () => {
|
|
|
381
391
|
});
|
|
382
392
|
|
|
383
393
|
it('should show save and cancel buttons in edit mode', async () => {
|
|
384
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
394
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
385
395
|
|
|
386
396
|
const editButton = screen.getByText('Edit');
|
|
387
397
|
await userEvent.click(editButton);
|
|
@@ -393,12 +403,11 @@ describe('CommentEntry Component', () => {
|
|
|
393
403
|
|
|
394
404
|
it('should stop event propagation when clicking textarea in edit mode', async () => {
|
|
395
405
|
const clickHandler = vi.fn();
|
|
396
|
-
|
|
397
|
-
<CommentEntry {...defaultProps}
|
|
398
|
-
{ returnEventBus: true }
|
|
406
|
+
renderWithProviders(
|
|
407
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
399
408
|
);
|
|
400
409
|
|
|
401
|
-
const subscription = eventBus
|
|
410
|
+
const subscription = eventBus.get('browse:click').subscribe(clickHandler);
|
|
402
411
|
|
|
403
412
|
await userEvent.click(screen.getByText('Edit'));
|
|
404
413
|
|
|
@@ -415,7 +424,7 @@ describe('CommentEntry Component', () => {
|
|
|
415
424
|
});
|
|
416
425
|
|
|
417
426
|
it('should update text in textarea', async () => {
|
|
418
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
427
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
419
428
|
|
|
420
429
|
await userEvent.click(screen.getByText('Edit'));
|
|
421
430
|
const textarea = screen.getByRole('textbox');
|
|
@@ -427,7 +436,7 @@ describe('CommentEntry Component', () => {
|
|
|
427
436
|
});
|
|
428
437
|
|
|
429
438
|
it('should show character count in edit mode', async () => {
|
|
430
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
439
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
431
440
|
|
|
432
441
|
await userEvent.click(screen.getByText('Edit'));
|
|
433
442
|
|
|
@@ -435,7 +444,7 @@ describe('CommentEntry Component', () => {
|
|
|
435
444
|
});
|
|
436
445
|
|
|
437
446
|
it('should enforce max length of 2000 characters', async () => {
|
|
438
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
447
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
439
448
|
|
|
440
449
|
await userEvent.click(screen.getByText('Edit'));
|
|
441
450
|
const textarea = screen.getByRole('textbox') as HTMLTextAreaElement;
|
|
@@ -444,7 +453,7 @@ describe('CommentEntry Component', () => {
|
|
|
444
453
|
});
|
|
445
454
|
|
|
446
455
|
it('should update textarea value and exit edit mode when save is clicked', async () => {
|
|
447
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
456
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
448
457
|
|
|
449
458
|
await userEvent.click(screen.getByText('Edit'));
|
|
450
459
|
const textarea = screen.getByRole('textbox');
|
|
@@ -463,7 +472,7 @@ describe('CommentEntry Component', () => {
|
|
|
463
472
|
});
|
|
464
473
|
|
|
465
474
|
it('should exit edit mode after save', async () => {
|
|
466
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
475
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
467
476
|
|
|
468
477
|
await userEvent.click(screen.getByText('Edit'));
|
|
469
478
|
await userEvent.click(screen.getByText('Save'));
|
|
@@ -473,7 +482,7 @@ describe('CommentEntry Component', () => {
|
|
|
473
482
|
});
|
|
474
483
|
|
|
475
484
|
it('should discard changes when cancel is clicked', async () => {
|
|
476
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
485
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
477
486
|
|
|
478
487
|
await userEvent.click(screen.getByText('Edit'));
|
|
479
488
|
const textarea = screen.getByRole('textbox');
|
|
@@ -489,12 +498,11 @@ describe('CommentEntry Component', () => {
|
|
|
489
498
|
|
|
490
499
|
it('should not emit any update when cancel is clicked', async () => {
|
|
491
500
|
const clickHandler = vi.fn();
|
|
492
|
-
|
|
493
|
-
<CommentEntry {...defaultProps}
|
|
494
|
-
{ returnEventBus: true }
|
|
501
|
+
renderWithProviders(
|
|
502
|
+
<CommentEntry session={session} {...defaultProps} />
|
|
495
503
|
);
|
|
496
504
|
|
|
497
|
-
const subscription = eventBus
|
|
505
|
+
const subscription = eventBus.get('browse:click').subscribe(clickHandler);
|
|
498
506
|
|
|
499
507
|
await userEvent.click(screen.getByText('Edit'));
|
|
500
508
|
clickHandler.mockClear();
|
|
@@ -512,14 +520,14 @@ describe('CommentEntry Component', () => {
|
|
|
512
520
|
|
|
513
521
|
describe('Styling and Appearance', () => {
|
|
514
522
|
it('should have proper border and padding styles', () => {
|
|
515
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
523
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
516
524
|
|
|
517
525
|
const commentDiv = container.firstChild as HTMLElement;
|
|
518
526
|
expect(commentDiv).toHaveClass('semiont-annotation-entry');
|
|
519
527
|
});
|
|
520
528
|
|
|
521
529
|
it('should have hover styles when not focused', () => {
|
|
522
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
530
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
523
531
|
|
|
524
532
|
const commentDiv = container.firstChild as HTMLElement;
|
|
525
533
|
expect(commentDiv).toHaveClass('semiont-annotation-entry');
|
|
@@ -527,7 +535,7 @@ describe('CommentEntry Component', () => {
|
|
|
527
535
|
});
|
|
528
536
|
|
|
529
537
|
it('should support dark mode classes', () => {
|
|
530
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
538
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
531
539
|
|
|
532
540
|
const commentDiv = container.firstChild as HTMLElement;
|
|
533
541
|
expect(commentDiv).toHaveClass('semiont-annotation-entry');
|
|
@@ -535,7 +543,7 @@ describe('CommentEntry Component', () => {
|
|
|
535
543
|
|
|
536
544
|
it('should render comment text with whitespace preserved', () => {
|
|
537
545
|
mockGetCommentText.mockReturnValue('Line 1\nLine 2\nLine 3');
|
|
538
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
546
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
539
547
|
|
|
540
548
|
// Look for the comment text in the annotation entry
|
|
541
549
|
const commentContent = container.querySelector('.semiont-annotation-entry__body');
|
|
@@ -546,7 +554,7 @@ describe('CommentEntry Component', () => {
|
|
|
546
554
|
describe('Edge Cases', () => {
|
|
547
555
|
it('should handle empty comment text', () => {
|
|
548
556
|
mockGetCommentText.mockReturnValue('');
|
|
549
|
-
const { container } = renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
557
|
+
const { container } = renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
550
558
|
|
|
551
559
|
// Check that the annotation entry exists even with empty text
|
|
552
560
|
const commentDiv = container.querySelector('.semiont-annotation-entry');
|
|
@@ -557,7 +565,7 @@ describe('CommentEntry Component', () => {
|
|
|
557
565
|
mockGetAnnotationExactText.mockReturnValue('');
|
|
558
566
|
|
|
559
567
|
expect(() => {
|
|
560
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
568
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
561
569
|
}).not.toThrow();
|
|
562
570
|
});
|
|
563
571
|
|
|
@@ -567,7 +575,7 @@ describe('CommentEntry Component', () => {
|
|
|
567
575
|
|
|
568
576
|
expect(() => {
|
|
569
577
|
renderWithProviders(
|
|
570
|
-
<CommentEntry {...defaultProps} comment={commentWithoutTimestamp} />
|
|
578
|
+
<CommentEntry session={session} {...defaultProps} comment={commentWithoutTimestamp} />
|
|
571
579
|
);
|
|
572
580
|
}).not.toThrow();
|
|
573
581
|
});
|
|
@@ -577,7 +585,7 @@ describe('CommentEntry Component', () => {
|
|
|
577
585
|
mockGetCommentText.mockReturnValue(longText);
|
|
578
586
|
|
|
579
587
|
renderWithProviders(
|
|
580
|
-
<CommentEntry {...defaultProps} comment={mockCommentStates.withLongText} />
|
|
588
|
+
<CommentEntry session={session} {...defaultProps} comment={mockCommentStates.withLongText} />
|
|
581
589
|
);
|
|
582
590
|
|
|
583
591
|
// Use a more flexible matcher for long text
|
|
@@ -587,7 +595,7 @@ describe('CommentEntry Component', () => {
|
|
|
587
595
|
});
|
|
588
596
|
|
|
589
597
|
it('should handle rapid edit/cancel cycles', async () => {
|
|
590
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
598
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
591
599
|
|
|
592
600
|
for (let i = 0; i < 3; i++) {
|
|
593
601
|
await userEvent.click(screen.getByText('Edit'));
|
|
@@ -601,7 +609,7 @@ describe('CommentEntry Component', () => {
|
|
|
601
609
|
|
|
602
610
|
describe('Accessibility', () => {
|
|
603
611
|
it('should have proper ARIA attributes for textarea', async () => {
|
|
604
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
612
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
605
613
|
|
|
606
614
|
await userEvent.click(screen.getByText('Edit'));
|
|
607
615
|
const textarea = screen.getByRole('textbox');
|
|
@@ -610,7 +618,7 @@ describe('CommentEntry Component', () => {
|
|
|
610
618
|
});
|
|
611
619
|
|
|
612
620
|
it('should be keyboard navigable', async () => {
|
|
613
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
621
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
614
622
|
|
|
615
623
|
const editButton = screen.getByText('Edit');
|
|
616
624
|
editButton.focus();
|
|
@@ -619,7 +627,7 @@ describe('CommentEntry Component', () => {
|
|
|
619
627
|
});
|
|
620
628
|
|
|
621
629
|
it('should support keyboard interaction for save/cancel', async () => {
|
|
622
|
-
renderWithProviders(<CommentEntry {...defaultProps} />);
|
|
630
|
+
renderWithProviders(<CommentEntry session={session} {...defaultProps} />);
|
|
623
631
|
|
|
624
632
|
await userEvent.click(screen.getByText('Edit'));
|
|
625
633
|
|