@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.
Files changed (53) hide show
  1. package/dist/{PdfAnnotationCanvas.client-KWQ7XDWT.js → PdfAnnotationCanvas.client-75GY2EDR.js} +12 -6
  2. package/dist/PdfAnnotationCanvas.client-75GY2EDR.js.map +1 -0
  3. package/dist/{chunk-O2MD7TGE.js → chunk-VXASXU4K.js} +10 -2
  4. package/dist/chunk-VXASXU4K.js.map +1 -0
  5. package/dist/index.d.ts +54 -16
  6. package/dist/index.js +395 -343
  7. package/dist/index.js.map +1 -1
  8. package/dist/test-utils.d.ts +5 -1
  9. package/dist/test-utils.js +3 -2
  10. package/dist/test-utils.js.map +1 -1
  11. package/package.json +5 -5
  12. package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
  13. package/src/components/image-annotation/SvgDrawingCanvas.tsx +12 -4
  14. package/src/components/image-annotation/__tests__/AnnotationOverlay.click.test.tsx +137 -0
  15. package/src/components/image-annotation/__tests__/SvgDrawingCanvas.click.test.tsx +108 -0
  16. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +12 -4
  17. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +137 -1
  18. package/src/components/resource/BrowseView.tsx +14 -6
  19. package/src/components/resource/ResourceViewer.tsx +6 -4
  20. package/src/components/resource/__tests__/BrowseView.test.tsx +98 -31
  21. package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +40 -1
  22. package/src/components/resource/__tests__/browse-renderers.dispatch.test.tsx +113 -0
  23. package/src/components/resource/browse-renderers.tsx +26 -4
  24. package/src/components/resource/panels/AssessmentEntry.tsx +5 -4
  25. package/src/components/resource/panels/AssessmentPanel.tsx +8 -5
  26. package/src/components/resource/panels/AssistSection.tsx +4 -3
  27. package/src/components/resource/panels/CommentEntry.tsx +5 -4
  28. package/src/components/resource/panels/CommentsPanel.tsx +8 -5
  29. package/src/components/resource/panels/HighlightEntry.tsx +5 -4
  30. package/src/components/resource/panels/HighlightPanel.tsx +8 -5
  31. package/src/components/resource/panels/ReferenceEntry.tsx +9 -10
  32. package/src/components/resource/panels/ReferencesPanel.tsx +11 -6
  33. package/src/components/resource/panels/ResourceInfoPanel.tsx +4 -3
  34. package/src/components/resource/panels/TagEntry.tsx +5 -3
  35. package/src/components/resource/panels/TaggingPanel.tsx +7 -4
  36. package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +10 -0
  37. package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +28 -20
  38. package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +38 -28
  39. package/src/components/resource/panels/__tests__/AssistSection.test.tsx +46 -17
  40. package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +65 -57
  41. package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +53 -24
  42. package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +27 -17
  43. package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +23 -17
  44. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +48 -77
  45. package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +87 -0
  46. package/src/components/resource/panels/__tests__/ReferencesPanel.observable-flow.test.tsx +15 -9
  47. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +77 -59
  48. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +11 -4
  49. package/src/components/resource/panels/__tests__/TagEntry.test.tsx +33 -19
  50. package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +15 -7
  51. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +3 -0
  52. package/dist/PdfAnnotationCanvas.client-KWQ7XDWT.js.map +0 -1
  53. 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, eventBus } = renderWithProviders(
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!.get('browse:click').subscribe(clickHandler);
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, eventBus } = renderWithProviders(
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!.get('beckon:hover').subscribe(hoverHandler);
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, eventBus } = renderWithProviders(
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!.get('beckon:hover').subscribe(hoverHandler);
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, eventBus } = renderWithProviders(
330
- <CommentEntry {...defaultProps} />,
331
- { returnEventBus: true }
340
+ const { container } = renderWithProviders(
341
+ <CommentEntry session={session} {...defaultProps} />
332
342
  );
333
343
 
334
- const subscription = eventBus!.get('beckon:hover').subscribe(hoverHandler);
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
- const { eventBus } = renderWithProviders(
397
- <CommentEntry {...defaultProps} />,
398
- { returnEventBus: true }
406
+ renderWithProviders(
407
+ <CommentEntry session={session} {...defaultProps} />
399
408
  );
400
409
 
401
- const subscription = eventBus!.get('browse:click').subscribe(clickHandler);
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
- const { eventBus } = renderWithProviders(
493
- <CommentEntry {...defaultProps} />,
494
- { returnEventBus: true }
501
+ renderWithProviders(
502
+ <CommentEntry session={session} {...defaultProps} />
495
503
  );
496
504
 
497
- const subscription = eventBus!.get('browse:click').subscribe(clickHandler);
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