@semiont/react-ui 0.5.5 → 0.5.7
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 +59 -55
- package/dist/{PdfAnnotationCanvas.client-CN3C3S55.js → PdfAnnotationCanvas.client-NIMALXNZ.js} +7 -27
- package/dist/PdfAnnotationCanvas.client-NIMALXNZ.js.map +1 -0
- package/dist/{ar-U2EXWUMQ.js → ar-SONK6MON.js} +3 -7
- package/dist/ar-SONK6MON.js.map +1 -0
- package/dist/{bn-DRJGV772.js → bn-ZKPRITNG.js} +3 -7
- package/dist/bn-ZKPRITNG.js.map +1 -0
- package/dist/{chunk-3Q3TUKWP.js → chunk-Y2EEAOMZ.js} +29 -29
- package/dist/{cs-PTWDM23V.js → cs-LPXQ7NHQ.js} +3 -7
- package/dist/cs-LPXQ7NHQ.js.map +1 -0
- package/dist/{da-KSNIKYSS.js → da-6TKY7MCY.js} +6 -10
- package/dist/da-6TKY7MCY.js.map +1 -0
- package/dist/{de-F2XBEWFY.js → de-C3GNII74.js} +3 -7
- package/dist/de-C3GNII74.js.map +1 -0
- package/dist/{el-DLD2GWAP.js → el-UBCXQDJ7.js} +3 -7
- package/dist/el-UBCXQDJ7.js.map +1 -0
- package/dist/{es-WLPYWGB5.js → es-BQ23TRI7.js} +11 -15
- package/dist/es-BQ23TRI7.js.map +1 -0
- package/dist/{fa-BAXHSDZG.js → fa-AFTBZB77.js} +3 -7
- package/dist/fa-AFTBZB77.js.map +1 -0
- package/dist/{fi-FCHSYVOT.js → fi-WOYNLZC2.js} +3 -7
- package/dist/fi-WOYNLZC2.js.map +1 -0
- package/dist/{fr-3UERBSL6.js → fr-NDSMIFJM.js} +3 -7
- package/dist/fr-NDSMIFJM.js.map +1 -0
- package/dist/{he-F6F3FV2K.js → he-VJXVRDOY.js} +3 -7
- package/dist/he-VJXVRDOY.js.map +1 -0
- package/dist/{hi-4BK6IK7Q.js → hi-BF6PHIE2.js} +3 -7
- package/dist/hi-BF6PHIE2.js.map +1 -0
- package/dist/{id-7ECCWP3J.js → id-GXG5QCZY.js} +3 -7
- package/dist/id-GXG5QCZY.js.map +1 -0
- package/dist/index.css +103 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +271 -120
- package/dist/index.js +877 -698
- package/dist/index.js.map +1 -1
- package/dist/{it-234Z6XK6.js → it-XKHHCBAF.js} +3 -7
- package/dist/it-XKHHCBAF.js.map +1 -0
- package/dist/{ja-PJWQI4OQ.js → ja-TX7VM4XD.js} +3 -7
- package/dist/ja-TX7VM4XD.js.map +1 -0
- package/dist/{ko-APUEW2RS.js → ko-DNC7EQ7J.js} +3 -7
- package/dist/ko-DNC7EQ7J.js.map +1 -0
- package/dist/{ms-PJBZWZWD.js → ms-POZGBKPH.js} +3 -7
- package/dist/ms-POZGBKPH.js.map +1 -0
- package/dist/{nl-L4C3ZBCU.js → nl-IRMTKI7Z.js} +4 -11
- package/dist/nl-IRMTKI7Z.js.map +1 -0
- package/dist/{no-QE5N5KNG.js → no-ZUDJA4S6.js} +20 -24
- package/dist/no-ZUDJA4S6.js.map +1 -0
- package/dist/{pl-5Q2D23PD.js → pl-2NGAXL5U.js} +3 -7
- package/dist/pl-2NGAXL5U.js.map +1 -0
- package/dist/{pt-AIGUOIOC.js → pt-ABMCXZUM.js} +118 -122
- package/dist/pt-ABMCXZUM.js.map +1 -0
- package/dist/{ro-T56CSHTY.js → ro-VOJP6O5X.js} +3 -7
- package/dist/ro-VOJP6O5X.js.map +1 -0
- package/dist/{sv-L4TJQ2UH.js → sv-4HVFIIE5.js} +43 -47
- package/dist/sv-4HVFIIE5.js.map +1 -0
- package/dist/test-utils.js +2 -2
- package/dist/test-utils.js.map +1 -1
- package/dist/{th-6O7Y6O2Q.js → th-IFPZP3HQ.js} +3 -7
- package/dist/th-IFPZP3HQ.js.map +1 -0
- package/dist/{tr-D4CQCSNO.js → tr-2GYEAMJ4.js} +3 -7
- package/dist/tr-2GYEAMJ4.js.map +1 -0
- package/dist/{uk-2HMQG6ND.js → uk-XCJBVLLD.js} +3 -7
- package/dist/uk-XCJBVLLD.js.map +1 -0
- package/dist/{vi-XVJ4RUEJ.js → vi-4FR7CB2F.js} +3 -7
- package/dist/vi-4FR7CB2F.js.map +1 -0
- package/dist/{zh-K2KDPGHK.js → zh-NSKFOINB.js} +3 -7
- package/dist/zh-NSKFOINB.js.map +1 -0
- package/package.json +17 -13
- package/src/components/Button/__tests__/Button.test.tsx +0 -2
- package/src/components/CodeMirrorRenderer.tsx +2 -0
- package/src/components/ErrorBoundary.tsx +0 -9
- package/src/components/ProtectedErrorBoundary.css +119 -0
- package/src/components/ProtectedErrorBoundary.tsx +24 -15
- package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +0 -1
- package/src/components/__tests__/ErrorBoundary.test.tsx +20 -13
- package/src/components/__tests__/LiveRegion.hooks.test.tsx +1 -1
- package/src/components/__tests__/ProtectedErrorBoundary.test.tsx +2 -1
- package/src/components/__tests__/ResizeHandle.test.tsx +0 -1
- package/src/components/__tests__/SessionExpiryBanner.test.tsx +0 -1
- package/src/components/__tests__/StatusDisplay.test.tsx +0 -1
- package/src/components/__tests__/Toast.test.tsx +2 -3
- package/src/components/__tests__/Toolbar.test.tsx +0 -1
- package/src/components/annotation/annotations.css +14 -0
- package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +3 -5
- package/src/components/annotation-popups/__tests__/SharedPopupElements.test.tsx +0 -1
- package/src/components/branding/__tests__/SemiontBranding.test.tsx +1 -2
- package/src/components/layout/__tests__/LeftSidebar.test.tsx +5 -6
- package/src/components/layout/__tests__/PageLayout.test.tsx +1 -3
- package/src/components/layout/__tests__/SkipLinks.a11y.test.tsx +8 -8
- package/src/components/layout/__tests__/UnifiedHeader.test.tsx +12 -1
- package/src/components/modals/__tests__/KeyboardShortcutsHelpModal.test.tsx +0 -1
- package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +3 -4
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +1 -2
- package/src/components/modals/__tests__/SearchModal.basic.test.tsx +1 -1
- package/src/components/modals/__tests__/SearchModal.keyboard.test.tsx +0 -5
- package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +1 -2
- package/src/components/modals/__tests__/SearchModal.visual.test.tsx +2 -2
- package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +0 -1
- package/src/components/navigation/NavigationMenu.tsx +1 -1
- package/src/components/navigation/__tests__/Footer.a11y.test.tsx +4 -0
- package/src/components/navigation/__tests__/Footer.test.tsx +3 -6
- package/src/components/navigation/__tests__/NavigationMenu.a11y.test.tsx +1 -1
- package/src/components/navigation/__tests__/NavigationMenu.test.tsx +7 -9
- package/src/components/navigation/__tests__/ObservableLink.test.tsx +0 -1
- package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +1 -2
- package/src/components/navigation/__tests__/SortableResourceTab.test.tsx +0 -1
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +6 -4
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +10 -19
- package/src/components/resource/AnnotateView.tsx +35 -37
- package/src/components/resource/BrowseView.tsx +31 -31
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +0 -1
- package/src/components/resource/__tests__/BrowseView.test.tsx +12 -14
- package/src/components/resource/__tests__/HistoryEvent.test.tsx +0 -5
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +4 -6
- package/src/components/resource/__tests__/event-formatting.test.ts +1 -1
- package/src/components/resource/panels/CollaborationPanel.tsx +1 -1
- package/src/components/resource/panels/JsonLdPanel.tsx +33 -16
- package/src/components/resource/panels/ReferencesPanel.tsx +1 -1
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +4 -5
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +8 -7
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +14 -10
- package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +31 -18
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +7 -6
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +5 -6
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +19 -13
- package/src/components/resource/panels/__tests__/JsonLdPanel.test.tsx +95 -426
- package/src/components/resource/panels/__tests__/PanelHeader.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +5 -5
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +40 -7
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +30 -32
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +6 -6
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +7 -6
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +0 -1
- package/src/components/viewers/__tests__/ImageViewer.test.tsx +0 -1
- package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +7 -10
- package/src/features/admin-exchange/__tests__/ImportProgress.test.tsx +38 -27
- package/src/features/admin-exchange/components/ImportProgress.tsx +28 -34
- package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +2 -0
- package/src/features/auth/__tests__/SignUpForm.a11y.test.tsx +11 -12
- package/src/features/auth/__tests__/SignUpForm.test.tsx +3 -3
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -0
- package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +11 -9
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +2 -1
- package/src/features/resource-compose/components/ResourceComposePage.tsx +36 -9
- package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -8
- package/src/features/resource-discovery/__tests__/ResourceCard.test.tsx +0 -1
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +33 -35
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +12 -11
- package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +204 -11
- package/src/features/resource-discovery/state/discover-state-unit.ts +70 -11
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +2 -2
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +10 -7
- package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +37 -1
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +14 -7
- package/src/integrations/__tests__/css-modules-helper.test.tsx +2 -3
- package/src/integrations/__tests__/styled-components-theme.test.ts +1 -3
- package/src/styles/features/exchange.css +0 -30
- package/src/styles/index.css +1 -0
- package/translations/ar.json +1 -3
- package/translations/bn.json +1 -3
- package/translations/cs.json +1 -3
- package/translations/da.json +4 -6
- package/translations/de.json +1 -3
- package/translations/el.json +1 -3
- package/translations/es.json +9 -11
- package/translations/fa.json +1 -3
- package/translations/fi.json +1 -3
- package/translations/fr.json +1 -3
- package/translations/he.json +1 -3
- package/translations/hi.json +1 -3
- package/translations/id.json +1 -3
- package/translations/it.json +1 -3
- package/translations/ja.json +1 -3
- package/translations/ko.json +1 -3
- package/translations/ms.json +1 -3
- package/translations/nl.json +2 -7
- package/translations/no.json +18 -20
- package/translations/pl.json +1 -3
- package/translations/pt.json +116 -118
- package/translations/ro.json +1 -3
- package/translations/sv.json +41 -43
- package/translations/th.json +1 -3
- package/translations/tr.json +1 -3
- package/translations/uk.json +1 -3
- package/translations/vi.json +1 -3
- package/translations/zh.json +1 -3
- package/dist/PdfAnnotationCanvas.client-CN3C3S55.js.map +0 -1
- package/dist/ar-U2EXWUMQ.js.map +0 -1
- package/dist/bn-DRJGV772.js.map +0 -1
- package/dist/cs-PTWDM23V.js.map +0 -1
- package/dist/da-KSNIKYSS.js.map +0 -1
- package/dist/de-F2XBEWFY.js.map +0 -1
- package/dist/el-DLD2GWAP.js.map +0 -1
- package/dist/es-WLPYWGB5.js.map +0 -1
- package/dist/fa-BAXHSDZG.js.map +0 -1
- package/dist/fi-FCHSYVOT.js.map +0 -1
- package/dist/fr-3UERBSL6.js.map +0 -1
- package/dist/he-F6F3FV2K.js.map +0 -1
- package/dist/hi-4BK6IK7Q.js.map +0 -1
- package/dist/id-7ECCWP3J.js.map +0 -1
- package/dist/it-234Z6XK6.js.map +0 -1
- package/dist/ja-PJWQI4OQ.js.map +0 -1
- package/dist/ko-APUEW2RS.js.map +0 -1
- package/dist/ms-PJBZWZWD.js.map +0 -1
- package/dist/nl-L4C3ZBCU.js.map +0 -1
- package/dist/no-QE5N5KNG.js.map +0 -1
- package/dist/pl-5Q2D23PD.js.map +0 -1
- package/dist/pt-AIGUOIOC.js.map +0 -1
- package/dist/ro-T56CSHTY.js.map +0 -1
- package/dist/sv-L4TJQ2UH.js.map +0 -1
- package/dist/th-6O7Y6O2Q.js.map +0 -1
- package/dist/tr-D4CQCSNO.js.map +0 -1
- package/dist/uk-2HMQG6ND.js.map +0 -1
- package/dist/vi-XVJ4RUEJ.js.map +0 -1
- package/dist/zh-K2KDPGHK.js.map +0 -1
- /package/dist/{chunk-3Q3TUKWP.js.map → chunk-Y2EEAOMZ.js.map} +0 -0
|
@@ -1,504 +1,173 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
4
3
|
import userEvent from '@testing-library/user-event';
|
|
5
4
|
import '@testing-library/jest-dom';
|
|
6
5
|
import { JsonLdPanel } from '../JsonLdPanel';
|
|
6
|
+
import { resourceId } from '@semiont/core';
|
|
7
7
|
import type { components } from '@semiont/core';
|
|
8
8
|
|
|
9
|
-
type
|
|
9
|
+
type GetResourceResponse = components['schemas']['GetResourceResponse'];
|
|
10
10
|
|
|
11
|
-
// Mock CodeMirror modules
|
|
11
|
+
// Mock CodeMirror modules (the panel still renders the graph in CodeMirror)
|
|
12
12
|
vi.mock('@codemirror/view', () => {
|
|
13
13
|
class MockEditorView {
|
|
14
14
|
destroy = vi.fn();
|
|
15
|
-
constructor(config: any) {
|
|
16
|
-
// Store config if needed for assertions
|
|
17
|
-
}
|
|
18
15
|
static editable = { of: vi.fn() };
|
|
19
16
|
static theme = vi.fn(() => ({}));
|
|
20
17
|
}
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
EditorView: MockEditorView,
|
|
24
|
-
lineNumbers: vi.fn(),
|
|
25
|
-
};
|
|
18
|
+
return { EditorView: MockEditorView, lineNumbers: vi.fn() };
|
|
26
19
|
});
|
|
27
|
-
|
|
28
20
|
vi.mock('@codemirror/state', () => ({
|
|
29
|
-
EditorState: {
|
|
30
|
-
create: vi.fn(() => ({})),
|
|
31
|
-
readOnly: { of: vi.fn() },
|
|
32
|
-
},
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
vi.mock('@codemirror/lang-json', () => ({
|
|
36
|
-
json: vi.fn(),
|
|
21
|
+
EditorState: { create: vi.fn(() => ({})), readOnly: { of: vi.fn() } },
|
|
37
22
|
}));
|
|
38
|
-
|
|
39
|
-
vi.mock('@codemirror/theme-one-dark', () => ({
|
|
40
|
-
oneDark: {},
|
|
41
|
-
}));
|
|
42
|
-
|
|
23
|
+
vi.mock('@codemirror/lang-json', () => ({ json: vi.fn() }));
|
|
24
|
+
vi.mock('@codemirror/theme-one-dark', () => ({ oneDark: {} }));
|
|
43
25
|
vi.mock('@codemirror/language', () => ({
|
|
44
26
|
syntaxHighlighting: vi.fn(),
|
|
45
|
-
HighlightStyle: {
|
|
46
|
-
define: vi.fn(() => ({})),
|
|
47
|
-
},
|
|
27
|
+
HighlightStyle: { define: vi.fn(() => ({})) },
|
|
48
28
|
}));
|
|
49
|
-
|
|
50
29
|
vi.mock('../../../lib/codemirror-json-theme', () => ({
|
|
51
30
|
jsonLightTheme: {},
|
|
52
31
|
jsonLightHighlightStyle: {},
|
|
53
32
|
}));
|
|
54
33
|
|
|
55
|
-
// Mock
|
|
34
|
+
// Mock the hooks the panel consumes — NOT the session/client stack.
|
|
56
35
|
vi.mock('@/hooks/useLineNumbers');
|
|
57
|
-
|
|
58
|
-
import { EditorView } from '@codemirror/view';
|
|
36
|
+
vi.mock('@/hooks/useResourceGraph');
|
|
59
37
|
import { useLineNumbers } from '@/hooks/useLineNumbers';
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
38
|
+
import { useResourceGraph } from '@/hooks/useResourceGraph';
|
|
39
|
+
|
|
40
|
+
const RID = resourceId('test-resource-1');
|
|
41
|
+
|
|
42
|
+
const MOCK_GRAPH: GetResourceResponse = {
|
|
43
|
+
resource: {
|
|
44
|
+
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
45
|
+
'@id': 'test-resource-1',
|
|
46
|
+
id: 'test-resource-1',
|
|
47
|
+
name: 'Test Resource',
|
|
48
|
+
content: 'This is test content',
|
|
49
|
+
format: 'text/plain',
|
|
50
|
+
archived: false,
|
|
51
|
+
entityTypes: ['Person'],
|
|
52
|
+
locale: 'en-US',
|
|
53
|
+
representations: [],
|
|
54
|
+
created: '2024-01-01T10:00:00Z',
|
|
55
|
+
modified: '2024-01-01T10:00:00Z',
|
|
56
|
+
},
|
|
57
|
+
annotations: [],
|
|
58
|
+
entityReferences: [],
|
|
59
|
+
};
|
|
77
60
|
|
|
78
61
|
describe('JsonLdPanel Component', () => {
|
|
79
|
-
let mockClipboard:
|
|
62
|
+
let mockClipboard: { writeText: ReturnType<typeof vi.fn> };
|
|
80
63
|
|
|
81
64
|
beforeEach(() => {
|
|
82
65
|
vi.clearAllMocks();
|
|
83
66
|
|
|
84
|
-
|
|
85
|
-
mockClipboard = {
|
|
86
|
-
writeText: vi.fn().mockResolvedValue(undefined),
|
|
87
|
-
};
|
|
67
|
+
mockClipboard = { writeText: vi.fn().mockResolvedValue(undefined) };
|
|
88
68
|
Object.defineProperty(navigator, 'clipboard', {
|
|
89
|
-
value: mockClipboard,
|
|
90
|
-
writable: true,
|
|
91
|
-
configurable: true,
|
|
69
|
+
value: mockClipboard, writable: true, configurable: true,
|
|
92
70
|
});
|
|
93
|
-
|
|
94
|
-
// Mock document.documentElement for dark mode detection
|
|
95
71
|
Object.defineProperty(document.documentElement, 'classList', {
|
|
96
|
-
value: {
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
writable: true,
|
|
100
|
-
configurable: true,
|
|
72
|
+
value: { contains: vi.fn().mockReturnValue(false) },
|
|
73
|
+
writable: true, configurable: true,
|
|
101
74
|
});
|
|
102
75
|
|
|
103
|
-
// Mock useLineNumbers hook implementation
|
|
104
76
|
vi.mocked(useLineNumbers).mockReturnValue({
|
|
105
|
-
showLineNumbers: true,
|
|
106
|
-
|
|
77
|
+
showLineNumbers: true, toggleLineNumbers: vi.fn(),
|
|
78
|
+
});
|
|
79
|
+
// Default: graph loaded successfully.
|
|
80
|
+
vi.mocked(useResourceGraph).mockReturnValue({
|
|
81
|
+
graph: MOCK_GRAPH, loading: false, error: null,
|
|
107
82
|
});
|
|
108
83
|
});
|
|
109
84
|
|
|
110
|
-
afterEach(() => {
|
|
111
|
-
vi.restoreAllMocks();
|
|
112
|
-
});
|
|
85
|
+
afterEach(() => { vi.restoreAllMocks(); });
|
|
113
86
|
|
|
114
87
|
describe('Rendering', () => {
|
|
115
|
-
it('
|
|
116
|
-
const
|
|
117
|
-
render(<JsonLdPanel resource={resource} />);
|
|
118
|
-
|
|
88
|
+
it('renders the header, copy button, and editor container', () => {
|
|
89
|
+
const { container } = render(<JsonLdPanel resourceId={RID} />);
|
|
119
90
|
expect(screen.getByText('JSON-LD')).toBeInTheDocument();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should render copy button', () => {
|
|
123
|
-
const resource = createMockResource();
|
|
124
|
-
render(<JsonLdPanel resource={resource} />);
|
|
125
|
-
|
|
126
91
|
expect(screen.getByText(/Copy/)).toBeInTheDocument();
|
|
92
|
+
expect(container.querySelector('.semiont-jsonld-panel__editor')).toBeInTheDocument();
|
|
127
93
|
});
|
|
128
94
|
|
|
129
|
-
it('
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const editorDiv = container.querySelector('.semiont-jsonld-panel__editor');
|
|
134
|
-
expect(editorDiv).toBeInTheDocument();
|
|
95
|
+
it('fetches the graph for the given resourceId', () => {
|
|
96
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
97
|
+
expect(useResourceGraph).toHaveBeenCalledWith(RID);
|
|
135
98
|
});
|
|
136
99
|
});
|
|
137
100
|
|
|
138
|
-
describe('
|
|
139
|
-
it('
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const editorDiv = container.querySelector('.semiont-jsonld-panel__editor');
|
|
145
|
-
expect(editorDiv).toBeInTheDocument();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('should pass resource as JSON to editor', () => {
|
|
149
|
-
const resource = createMockResource();
|
|
150
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
151
|
-
|
|
152
|
-
// Verify component renders without errors
|
|
153
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('should format JSON with indentation', () => {
|
|
157
|
-
const resource = createMockResource();
|
|
158
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
159
|
-
|
|
160
|
-
// Verify component renders without errors
|
|
161
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
101
|
+
describe('Loading / error states', () => {
|
|
102
|
+
it('shows a loading state and disables Copy while loading', () => {
|
|
103
|
+
vi.mocked(useResourceGraph).mockReturnValue({ graph: null, loading: true, error: null });
|
|
104
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
105
|
+
expect(screen.getByText(/Loading JSON-LD/i)).toBeInTheDocument();
|
|
106
|
+
expect(screen.getByText(/Copy/).closest('button')).toBeDisabled();
|
|
162
107
|
});
|
|
163
108
|
|
|
164
|
-
it('
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// Verify component renders without errors (read-only is configured internally)
|
|
169
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('should include line numbers when enabled', () => {
|
|
173
|
-
vi.mocked(useLineNumbers).mockReturnValue({ showLineNumbers: true, toggleLineNumbers: vi.fn() });
|
|
174
|
-
|
|
175
|
-
const resource = createMockResource();
|
|
176
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
177
|
-
|
|
178
|
-
// Verify component renders without errors (line numbers configured internally)
|
|
179
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should not include line numbers when disabled', () => {
|
|
183
|
-
vi.mocked(useLineNumbers).mockReturnValue({ showLineNumbers: false, toggleLineNumbers: vi.fn() });
|
|
184
|
-
|
|
185
|
-
const resource = createMockResource();
|
|
186
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
187
|
-
|
|
188
|
-
// Verify component renders without errors (line numbers not included)
|
|
189
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('should cleanup editor on unmount', () => {
|
|
193
|
-
const resource = createMockResource();
|
|
194
|
-
const { unmount } = render(<JsonLdPanel resource={resource} />);
|
|
195
|
-
|
|
196
|
-
// Should unmount without errors (cleanup happens internally)
|
|
197
|
-
expect(() => unmount()).not.toThrow();
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe('Dark Mode Support', () => {
|
|
202
|
-
it('should use dark theme when dark mode is active', () => {
|
|
203
|
-
Object.defineProperty(document.documentElement, 'classList', {
|
|
204
|
-
value: {
|
|
205
|
-
contains: vi.fn().mockReturnValue(true), // Dark mode active
|
|
206
|
-
},
|
|
207
|
-
writable: true,
|
|
208
|
-
configurable: true,
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
const resource = createMockResource();
|
|
212
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
213
|
-
|
|
214
|
-
// Verify component renders without errors (dark theme configured internally)
|
|
215
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('should use light theme when dark mode is not active', () => {
|
|
219
|
-
Object.defineProperty(document.documentElement, 'classList', {
|
|
220
|
-
value: {
|
|
221
|
-
contains: vi.fn().mockReturnValue(false), // Light mode
|
|
222
|
-
},
|
|
223
|
-
writable: true,
|
|
224
|
-
configurable: true,
|
|
109
|
+
it('shows an error state and disables Copy on failure', () => {
|
|
110
|
+
vi.mocked(useResourceGraph).mockReturnValue({
|
|
111
|
+
graph: null, loading: false, error: new Error('boom'),
|
|
225
112
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// Verify component renders without errors (light theme configured internally)
|
|
231
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
113
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
114
|
+
expect(screen.getByText(/Failed to load JSON-LD/i)).toBeInTheDocument();
|
|
115
|
+
expect(screen.getByText(/Copy/).closest('button')).toBeDisabled();
|
|
232
116
|
});
|
|
233
117
|
});
|
|
234
118
|
|
|
235
|
-
describe('Copy to
|
|
236
|
-
it('
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const copyButton = screen.getByText(/Copy/);
|
|
241
|
-
await userEvent.click(copyButton);
|
|
119
|
+
describe('Copy to clipboard', () => {
|
|
120
|
+
it('copies the full graph — not the bare descriptor', async () => {
|
|
121
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
122
|
+
await userEvent.click(screen.getByText(/Copy/));
|
|
242
123
|
|
|
243
124
|
expect(mockClipboard.writeText).toHaveBeenCalledOnce();
|
|
125
|
+
const parsed = JSON.parse(mockClipboard.writeText.mock.calls[0][0]);
|
|
244
126
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
expect(
|
|
127
|
+
// The graph wraps the descriptor and adds annotation collections; a bare
|
|
128
|
+
// ResourceDescriptor would have `id` at the top level and no `resource`.
|
|
129
|
+
expect(parsed.resource.id).toBe('test-resource-1');
|
|
130
|
+
expect(Array.isArray(parsed.annotations)).toBe(true);
|
|
131
|
+
expect(Array.isArray(parsed.entityReferences)).toBe(true);
|
|
132
|
+
expect(parsed.id).toBeUndefined();
|
|
248
133
|
});
|
|
249
134
|
|
|
250
|
-
it('
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// Should be formatted with indentation
|
|
260
|
-
expect(copiedText).toContain('\n');
|
|
261
|
-
expect(copiedText).toContain(' ');
|
|
135
|
+
it('copies pretty-printed, valid JSON', async () => {
|
|
136
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
137
|
+
await userEvent.click(screen.getByText(/Copy/));
|
|
138
|
+
const copied = mockClipboard.writeText.mock.calls[0][0];
|
|
139
|
+
expect(copied).toContain('\n');
|
|
140
|
+
expect(copied).toContain(' ');
|
|
141
|
+
expect(() => JSON.parse(copied)).not.toThrow();
|
|
142
|
+
});
|
|
262
143
|
|
|
263
|
-
|
|
264
|
-
|
|
144
|
+
it('does not copy when there is no graph yet', async () => {
|
|
145
|
+
vi.mocked(useResourceGraph).mockReturnValue({ graph: null, loading: true, error: null });
|
|
146
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
147
|
+
const button = screen.getByText(/Copy/).closest('button')!;
|
|
148
|
+
await userEvent.click(button);
|
|
149
|
+
expect(mockClipboard.writeText).not.toHaveBeenCalled();
|
|
265
150
|
});
|
|
266
151
|
|
|
267
|
-
it('
|
|
152
|
+
it('handles clipboard errors gracefully', async () => {
|
|
268
153
|
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
269
154
|
mockClipboard.writeText.mockRejectedValue(new Error('Clipboard error'));
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
render(<JsonLdPanel resource={resource} />);
|
|
273
|
-
|
|
274
|
-
const copyButton = screen.getByText(/Copy/);
|
|
275
|
-
|
|
276
|
-
await expect(async () => {
|
|
277
|
-
await userEvent.click(copyButton);
|
|
278
|
-
}).not.toThrow();
|
|
279
|
-
|
|
155
|
+
render(<JsonLdPanel resourceId={RID} />);
|
|
156
|
+
await userEvent.click(screen.getByText(/Copy/));
|
|
280
157
|
await waitFor(() => {
|
|
281
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
282
|
-
'Failed to copy JSON-LD:',
|
|
283
|
-
expect.any(Error)
|
|
284
|
-
);
|
|
158
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to copy JSON-LD:', expect.any(Error));
|
|
285
159
|
});
|
|
286
|
-
|
|
287
160
|
consoleErrorSpy.mockRestore();
|
|
288
161
|
});
|
|
289
162
|
});
|
|
290
163
|
|
|
291
|
-
describe('
|
|
292
|
-
it('
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
expect(container.firstChild).toBeInTheDocument();
|
|
297
|
-
|
|
298
|
-
const resource2 = createMockResource({ id: 'resource-2', name: 'Resource 2' });
|
|
299
|
-
|
|
300
|
-
// Should rerender without errors
|
|
301
|
-
expect(() => rerender(<JsonLdPanel resource={resource2} />)).not.toThrow();
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it('should reinitialize editor when line numbers setting changes', () => {
|
|
305
|
-
vi.mocked(useLineNumbers).mockReturnValue({ showLineNumbers: true, toggleLineNumbers: vi.fn() });
|
|
306
|
-
|
|
307
|
-
const resource = createMockResource();
|
|
308
|
-
const { rerender } = render(<JsonLdPanel resource={resource} />);
|
|
309
|
-
|
|
310
|
-
vi.mocked(useLineNumbers).mockReturnValue({ showLineNumbers: false, toggleLineNumbers: vi.fn() });
|
|
311
|
-
|
|
312
|
-
// Should rerender without errors
|
|
313
|
-
expect(() => rerender(<JsonLdPanel resource={resource} />)).not.toThrow();
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
describe('Edge Cases', () => {
|
|
318
|
-
it('should handle resource with minimal data', () => {
|
|
319
|
-
const minimalResource: SemiontResource = {
|
|
320
|
-
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
321
|
-
'@id': 'minimal',
|
|
322
|
-
id: 'minimal',
|
|
323
|
-
name: 'Minimal',
|
|
324
|
-
content: 'Test',
|
|
325
|
-
format: 'text/plain',
|
|
326
|
-
archived: false,
|
|
327
|
-
representations: [],
|
|
328
|
-
created: '2024-01-01T00:00:00Z',
|
|
329
|
-
modified: '2024-01-01T00:00:00Z',
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
expect(() => {
|
|
333
|
-
render(<JsonLdPanel resource={minimalResource} />);
|
|
334
|
-
}).not.toThrow();
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it('should handle resource with special characters', () => {
|
|
338
|
-
const resource = createMockResource({
|
|
339
|
-
name: 'Test "Resource" with \'quotes\' & special <chars>',
|
|
340
|
-
content: 'Content with\nnewlines\tand\ttabs',
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
expect(() => {
|
|
344
|
-
render(<JsonLdPanel resource={resource} />);
|
|
345
|
-
}).not.toThrow();
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it('should handle very large resource data', () => {
|
|
349
|
-
const largeContent = 'A'.repeat(100000);
|
|
350
|
-
const resource = createMockResource({
|
|
351
|
-
content: largeContent,
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
expect(() => {
|
|
355
|
-
render(<JsonLdPanel resource={resource} />);
|
|
356
|
-
}).not.toThrow();
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it('should handle resource with unicode characters', () => {
|
|
360
|
-
const resource = createMockResource({
|
|
361
|
-
name: '测试资源 テストリソース ресурс тест',
|
|
362
|
-
content: '🎉🔥💯 Unicode content',
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
expect(() => {
|
|
366
|
-
render(<JsonLdPanel resource={resource} />);
|
|
367
|
-
}).not.toThrow();
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
it('should handle undefined optional fields', () => {
|
|
371
|
-
const resource: SemiontResource = {
|
|
372
|
-
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
373
|
-
'@id': 'test',
|
|
374
|
-
id: 'test',
|
|
375
|
-
name: 'Test',
|
|
376
|
-
content: 'Content',
|
|
377
|
-
format: 'text/plain',
|
|
378
|
-
archived: false,
|
|
379
|
-
representations: [],
|
|
380
|
-
created: '2024-01-01T00:00:00Z',
|
|
381
|
-
modified: '2024-01-01T00:00:00Z',
|
|
382
|
-
// Optional fields omitted
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
expect(() => {
|
|
386
|
-
render(<JsonLdPanel resource={resource} />);
|
|
387
|
-
}).not.toThrow();
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
describe('Styling and Appearance', () => {
|
|
392
|
-
it('should have proper panel structure', () => {
|
|
393
|
-
const resource = createMockResource();
|
|
394
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
395
|
-
|
|
396
|
-
const panel = container.firstChild as HTMLElement;
|
|
397
|
-
expect(panel).toHaveClass('semiont-jsonld-panel');
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it('should have proper header styling', () => {
|
|
401
|
-
const resource = createMockResource();
|
|
402
|
-
render(<JsonLdPanel resource={resource} />);
|
|
403
|
-
|
|
404
|
-
const header = screen.getByText('JSON-LD').parentElement;
|
|
405
|
-
expect(header).toHaveClass('semiont-jsonld-panel__header');
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it('should have proper button styling', () => {
|
|
409
|
-
const resource = createMockResource();
|
|
410
|
-
render(<JsonLdPanel resource={resource} />);
|
|
411
|
-
|
|
412
|
-
const copyButton = screen.getByText(/Copy/).closest('button');
|
|
413
|
-
expect(copyButton).toHaveClass('semiont-button', 'semiont-button--icon');
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('should have proper editor container styling', () => {
|
|
417
|
-
const resource = createMockResource();
|
|
418
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
419
|
-
|
|
420
|
-
const editorContainer = container.querySelector('.semiont-jsonld-panel__editor');
|
|
421
|
-
expect(editorContainer).toBeInTheDocument();
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
it('should support dark mode styling', () => {
|
|
425
|
-
const resource = createMockResource();
|
|
426
|
-
const { container } = render(<JsonLdPanel resource={resource} />);
|
|
427
|
-
|
|
428
|
-
const panel = container.firstChild as HTMLElement;
|
|
429
|
-
expect(panel).toHaveClass('semiont-jsonld-panel');
|
|
430
|
-
});
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
describe('Accessibility', () => {
|
|
434
|
-
it('should have title attribute on copy button', () => {
|
|
435
|
-
const resource = createMockResource();
|
|
436
|
-
render(<JsonLdPanel resource={resource} />);
|
|
437
|
-
|
|
164
|
+
describe('Accessibility / structure', () => {
|
|
165
|
+
it('has the panel structure and a titled copy button', () => {
|
|
166
|
+
const { container } = render(<JsonLdPanel resourceId={RID} />);
|
|
167
|
+
expect(container.firstChild).toHaveClass('semiont-jsonld-panel');
|
|
438
168
|
const copyButton = screen.getByText(/Copy/).closest('button');
|
|
439
169
|
expect(copyButton).toHaveAttribute('title', 'Copy to clipboard');
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
it('should have semantic heading', () => {
|
|
443
|
-
const resource = createMockResource();
|
|
444
|
-
render(<JsonLdPanel resource={resource} />);
|
|
445
|
-
|
|
446
|
-
const heading = screen.getByText('JSON-LD');
|
|
447
|
-
expect(heading).toHaveClass('semiont-jsonld-panel__title');
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
it('should have proper button structure', () => {
|
|
451
|
-
const resource = createMockResource();
|
|
452
|
-
render(<JsonLdPanel resource={resource} />);
|
|
453
|
-
|
|
454
|
-
const copyButton = screen.getByText(/Copy/).closest('button');
|
|
455
|
-
expect(copyButton?.tagName).toBe('BUTTON');
|
|
456
|
-
});
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
describe('JSON-LD Format', () => {
|
|
460
|
-
it('should produce valid JSON', async () => {
|
|
461
|
-
const resource = createMockResource();
|
|
462
|
-
render(<JsonLdPanel resource={resource} />);
|
|
463
|
-
|
|
464
|
-
const copyButton = screen.getByText(/Copy/);
|
|
465
|
-
await userEvent.click(copyButton);
|
|
466
|
-
|
|
467
|
-
const copiedText = mockClipboard.writeText.mock.calls[0][0];
|
|
468
|
-
|
|
469
|
-
expect(() => {
|
|
470
|
-
const parsed = JSON.parse(copiedText);
|
|
471
|
-
expect(parsed).toHaveProperty('id');
|
|
472
|
-
expect(parsed).toHaveProperty('name');
|
|
473
|
-
expect(parsed).toHaveProperty('content');
|
|
474
|
-
}).not.toThrow();
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it('should include all resource fields', async () => {
|
|
478
|
-
const resource = createMockResource({
|
|
479
|
-
id: 'full-resource',
|
|
480
|
-
name: 'Full Resource',
|
|
481
|
-
content: 'Complete content',
|
|
482
|
-
format: 'text/markdown',
|
|
483
|
-
archived: true,
|
|
484
|
-
entityTypes: ['Person', 'Organization'],
|
|
485
|
-
locale: 'en-US',
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
render(<JsonLdPanel resource={resource} />);
|
|
489
|
-
|
|
490
|
-
const copyButton = screen.getByText(/Copy/);
|
|
491
|
-
await userEvent.click(copyButton);
|
|
492
|
-
|
|
493
|
-
const copiedText = mockClipboard.writeText.mock.calls[0][0];
|
|
494
|
-
const parsed = JSON.parse(copiedText);
|
|
495
|
-
|
|
496
|
-
expect(parsed.id).toBe('full-resource');
|
|
497
|
-
expect(parsed.name).toBe('Full Resource');
|
|
498
|
-
expect(parsed.format).toBe('text/markdown');
|
|
499
|
-
expect(parsed.archived).toBe(true);
|
|
500
|
-
expect(parsed.entityTypes).toEqual(['Person', 'Organization']);
|
|
501
|
-
expect(parsed.locale).toBe('en-US');
|
|
170
|
+
expect(screen.getByText('JSON-LD')).toHaveClass('semiont-jsonld-panel__title');
|
|
502
171
|
});
|
|
503
172
|
});
|
|
504
173
|
});
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { screen } from '@testing-library/react';
|
|
4
3
|
import '@testing-library/jest-dom';
|
|
5
4
|
import { renderWithProviders } from '../../../../test-utils';
|
|
6
5
|
import userEvent from '@testing-library/user-event';
|
|
7
|
-
import type { components } from '@semiont/core';
|
|
8
6
|
import { BindNamespace } from '@semiont/sdk';
|
|
9
7
|
import type { RouteBuilder } from '../../../../contexts/RoutingContext';
|
|
10
8
|
|
|
11
|
-
import type { Annotation } from '@semiont/core';
|
|
9
|
+
import type { Annotation, AnnotationId } from '@semiont/core';
|
|
12
10
|
|
|
13
11
|
// Stable mock functions defined outside vi.mock to avoid re-render loops
|
|
14
12
|
const mockGetAnnotationExactText = vi.fn();
|
|
@@ -54,7 +52,7 @@ import { ReferenceEntry } from '../ReferenceEntry';
|
|
|
54
52
|
|
|
55
53
|
const createMockReference = (overrides?: Partial<Annotation>): Annotation => ({
|
|
56
54
|
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
57
|
-
id: 'ref-1',
|
|
55
|
+
id: 'ref-1' as AnnotationId,
|
|
58
56
|
type: 'Annotation',
|
|
59
57
|
motivation: 'linking',
|
|
60
58
|
created: '2024-06-15T12:00:00Z',
|
|
@@ -75,7 +73,9 @@ const createMockReference = (overrides?: Partial<Annotation>): Annotation => ({
|
|
|
75
73
|
|
|
76
74
|
const mockRoutes: RouteBuilder = {
|
|
77
75
|
resourceDetail: vi.fn((id: string) => `/resources/${id}`),
|
|
78
|
-
|
|
76
|
+
userProfile: vi.fn((id: string) => `/users/${id}`),
|
|
77
|
+
search: vi.fn((query: string) => `/search?q=${query}`),
|
|
78
|
+
home: vi.fn(() => '/'),
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
describe('ReferenceEntry', () => {
|