@eeacms/volto-eea-chatbot 2.0.1 → 2.0.3
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/.eslintrc.js +6 -6
- package/CHANGELOG.md +20 -0
- package/artifacts/ONYX_V3_INTEGRATION.md +34 -0
- package/jest-addon.config.js +2 -1
- package/package.json +1 -1
- package/src/ChatBlock/ChatBlockEdit.jsx +2 -1
- package/src/ChatBlock/chat/AIMessage.tsx +36 -16
- package/src/ChatBlock/chat/ChatMessage.tsx +1 -1
- package/src/ChatBlock/chat/ChatWindow.tsx +13 -11
- package/src/ChatBlock/chat/UserMessage.tsx +4 -4
- package/src/ChatBlock/components/AutoResizeTextarea.jsx +1 -1
- package/src/ChatBlock/components/ChatMessageFeedback.jsx +2 -2
- package/src/ChatBlock/components/EmptyState.jsx +1 -1
- package/src/ChatBlock/components/FeedbackModal.jsx +1 -1
- package/src/ChatBlock/components/HalloumiFeedback.jsx +2 -2
- package/src/ChatBlock/components/Source.jsx +2 -2
- package/src/ChatBlock/components/UserActionsToolbar.jsx +3 -3
- package/src/ChatBlock/components/WebResultIcon.tsx +2 -2
- package/src/ChatBlock/components/markdown/ClaimModal.jsx +3 -3
- package/src/ChatBlock/components/markdown/ClaimSegments.jsx +4 -4
- package/src/ChatBlock/components/markdown/{index.js → index.jsx} +1 -1
- package/src/ChatBlock/hooks/useChatController.ts +67 -14
- package/src/ChatBlock/hooks/useChatStreaming.ts +4 -4
- package/src/ChatBlock/hooks/useToolDisplayTiming.ts +2 -1
- package/src/ChatBlock/packets/MultiToolRenderer.tsx +86 -56
- package/src/ChatBlock/packets/RendererComponent.tsx +13 -5
- package/src/ChatBlock/packets/renderers/CustomToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/FetchToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/ImageToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/MessageTextRenderer.tsx +14 -9
- package/src/ChatBlock/packets/renderers/ReasoningRenderer.tsx +6 -5
- package/src/ChatBlock/packets/renderers/SearchToolRenderer.tsx +30 -21
- package/src/ChatBlock/{schema.js → schema.jsx} +13 -0
- package/src/ChatBlock/services/messageProcessor.ts +72 -17
- package/src/ChatBlock/services/packetUtils.ts +13 -3
- package/src/ChatBlock/services/streamingService.ts +155 -68
- package/src/ChatBlock/types/streamingModels.ts +47 -2
- package/src/ChatBlock/utils/citations.ts +1 -1
- package/src/halloumi/filtering.test.js +199 -1
- package/src/middleware.js +18 -1
- package/src/middleware.test.js +14 -0
- package/src/ChatBlock/tests/AIMessage.test.jsx +0 -95
- package/src/ChatBlock/tests/AutoResizeTextarea.test.jsx +0 -49
- package/src/ChatBlock/tests/BlinkingDot.test.jsx +0 -71
- package/src/ChatBlock/tests/ChatMessage.test.jsx +0 -75
- package/src/ChatBlock/tests/ChatMessageFeedback.test.jsx +0 -73
- package/src/ChatBlock/tests/Citation.test.jsx +0 -107
- package/src/ChatBlock/tests/ClaimModal.test.jsx +0 -136
- package/src/ChatBlock/tests/ClaimSegments.test.jsx +0 -206
- package/src/ChatBlock/tests/CustomToolRenderer.test.jsx +0 -241
- package/src/ChatBlock/tests/EmptyState.test.jsx +0 -137
- package/src/ChatBlock/tests/FeedbackModal.test.jsx +0 -138
- package/src/ChatBlock/tests/FetchToolRenderer.test.jsx +0 -161
- package/src/ChatBlock/tests/HalloumiFeedback.test.jsx +0 -94
- package/src/ChatBlock/tests/ImageToolRenderer.test.jsx +0 -178
- package/src/ChatBlock/tests/MessageTextRenderer.test.jsx +0 -227
- package/src/ChatBlock/tests/MultiToolRenderer.test.jsx +0 -134
- package/src/ChatBlock/tests/QualityCheckToggle.test.jsx +0 -105
- package/src/ChatBlock/tests/ReasoningRenderer.test.jsx +0 -163
- package/src/ChatBlock/tests/RelatedQuestions.test.jsx +0 -215
- package/src/ChatBlock/tests/RenderClaimView.test.jsx +0 -191
- package/src/ChatBlock/tests/RendererComponent.test.jsx +0 -139
- package/src/ChatBlock/tests/SearchToolRenderer.test.jsx +0 -295
- package/src/ChatBlock/tests/Source.test.jsx +0 -79
- package/src/ChatBlock/tests/SourceChip.test.jsx +0 -108
- package/src/ChatBlock/tests/Spinner.test.jsx +0 -18
- package/src/ChatBlock/tests/UserActionsToolbar.test.jsx +0 -135
- package/src/ChatBlock/tests/UserMessage.test.jsx +0 -83
- package/src/ChatBlock/tests/WebResultIcon.test.jsx +0 -61
- package/src/ChatBlock/tests/citations.test.js +0 -114
- package/src/ChatBlock/tests/index.test.js +0 -51
- package/src/ChatBlock/tests/messageProcessor.test.jsx +0 -438
- package/src/ChatBlock/tests/packetUtils.test.js +0 -158
- package/src/ChatBlock/tests/schema.test.js +0 -166
- package/src/ChatBlock/tests/streamingService.test.js +0 -467
- package/src/ChatBlock/tests/useChatController.test.jsx +0 -268
- package/src/ChatBlock/tests/useChatStreaming.test.jsx +0 -163
- package/src/ChatBlock/tests/useDeepCompareMemoize.test.js +0 -107
- package/src/ChatBlock/tests/useMarked.test.jsx +0 -107
- package/src/ChatBlock/tests/useQualityMarkers.test.jsx +0 -150
- package/src/ChatBlock/tests/useScrollonStream.test.jsx +0 -121
- package/src/ChatBlock/tests/useToolDisplayTiming.test.jsx +0 -151
- package/src/ChatBlock/tests/utils.test.jsx +0 -241
- package/src/ChatBlock/tests/withOnyxData.test.jsx +0 -81
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
2
|
-
import configureStore from 'redux-mock-store';
|
|
3
|
-
import renderer from 'react-test-renderer';
|
|
4
|
-
|
|
5
|
-
import '@testing-library/jest-dom';
|
|
6
|
-
import { Provider } from 'react-intl-redux';
|
|
7
|
-
import { AIMessage } from '../chat/AIMessage';
|
|
8
|
-
|
|
9
|
-
const mockStore = configureStore();
|
|
10
|
-
|
|
11
|
-
describe('AIMessage', () => {
|
|
12
|
-
let store;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
store = mockStore({
|
|
16
|
-
userSession: { token: '1234' },
|
|
17
|
-
intl: { locale: 'en', messages: {} },
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const renderComponent = (props) =>
|
|
22
|
-
renderer.create(
|
|
23
|
-
<Provider store={store}>
|
|
24
|
-
<MemoryRouter>
|
|
25
|
-
<AIMessage {...props} />
|
|
26
|
-
</MemoryRouter>
|
|
27
|
-
</Provider>,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
it('renders AI message with content', () => {
|
|
31
|
-
const props = {
|
|
32
|
-
message: {
|
|
33
|
-
messageId: 1,
|
|
34
|
-
message: 'Hello, I am an AI assistant',
|
|
35
|
-
type: 'assistant',
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const component = renderComponent(props);
|
|
40
|
-
const json = component.toJSON();
|
|
41
|
-
expect(json).toMatchSnapshot();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('renders AI message with sources', () => {
|
|
45
|
-
const props = {
|
|
46
|
-
message: {
|
|
47
|
-
messageId: 1,
|
|
48
|
-
message: 'Here is some information',
|
|
49
|
-
type: 'assistant',
|
|
50
|
-
documents: [
|
|
51
|
-
{
|
|
52
|
-
document_id: 'doc1',
|
|
53
|
-
semantic_identifier: 'Source 1',
|
|
54
|
-
link: 'https://example.com/1',
|
|
55
|
-
source_type: 'web',
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const component = renderComponent(props);
|
|
62
|
-
const json = component.toJSON();
|
|
63
|
-
expect(json).toMatchSnapshot();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('renders AI message with feedback options', () => {
|
|
67
|
-
const props = {
|
|
68
|
-
message: {
|
|
69
|
-
messageId: 1,
|
|
70
|
-
message: 'This is a response',
|
|
71
|
-
type: 'assistant',
|
|
72
|
-
},
|
|
73
|
-
onFeedback: jest.fn(),
|
|
74
|
-
enableFeedback: true,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const component = renderComponent(props);
|
|
78
|
-
const json = component.toJSON();
|
|
79
|
-
expect(json).toMatchSnapshot();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('renders empty AI message', () => {
|
|
83
|
-
const props = {
|
|
84
|
-
message: {
|
|
85
|
-
messageId: 1,
|
|
86
|
-
message: '',
|
|
87
|
-
type: 'assistant',
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const component = renderComponent(props);
|
|
92
|
-
const json = component.toJSON();
|
|
93
|
-
expect(json).toMatchSnapshot();
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { render, fireEvent } from '@testing-library/react';
|
|
2
|
-
import '@testing-library/jest-dom';
|
|
3
|
-
import AutoResizeTextarea from '../components/AutoResizeTextarea';
|
|
4
|
-
|
|
5
|
-
jest.mock('@eeacms/volto-matomo/utils', () => ({
|
|
6
|
-
trackEvent: jest.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
describe('AutoResizeTextarea', () => {
|
|
10
|
-
it('renders textarea and button', () => {
|
|
11
|
-
const { getByRole, getByLabelText } = render(
|
|
12
|
-
<AutoResizeTextarea onSubmit={jest.fn()} />,
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
expect(getByRole('textbox')).toBeInTheDocument();
|
|
16
|
-
expect(getByLabelText('Send')).toBeInTheDocument();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('calls onSubmit with input text on Enter key press', () => {
|
|
20
|
-
const mockSubmit = jest.fn();
|
|
21
|
-
const { getByRole } = render(<AutoResizeTextarea onSubmit={mockSubmit} />);
|
|
22
|
-
const textarea = getByRole('textbox');
|
|
23
|
-
|
|
24
|
-
fireEvent.change(textarea, { target: { value: 'Hello' } });
|
|
25
|
-
fireEvent.keyDown(textarea, { key: 'Enter', code: 'Enter' });
|
|
26
|
-
|
|
27
|
-
expect(mockSubmit).toHaveBeenCalledWith({ message: 'Hello' });
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('does not call onSubmit if input is empty', () => {
|
|
31
|
-
const mockSubmit = jest.fn();
|
|
32
|
-
const { getByRole } = render(<AutoResizeTextarea onSubmit={mockSubmit} />);
|
|
33
|
-
const textarea = getByRole('textbox');
|
|
34
|
-
|
|
35
|
-
fireEvent.keyDown(textarea, { key: 'Enter', code: 'Enter' });
|
|
36
|
-
|
|
37
|
-
expect(mockSubmit).not.toHaveBeenCalled();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('adds newline on Shift+Enter', () => {
|
|
41
|
-
const { getByRole } = render(<AutoResizeTextarea onSubmit={jest.fn()} />);
|
|
42
|
-
const textarea = getByRole('textbox');
|
|
43
|
-
|
|
44
|
-
fireEvent.change(textarea, { target: { value: 'Line 1' } });
|
|
45
|
-
fireEvent.keyDown(textarea, { key: 'Enter', shiftKey: true });
|
|
46
|
-
|
|
47
|
-
expect(textarea.value).toBe('Line 1\n');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
2
|
-
import configureStore from 'redux-mock-store';
|
|
3
|
-
import renderer from 'react-test-renderer';
|
|
4
|
-
|
|
5
|
-
import '@testing-library/jest-dom';
|
|
6
|
-
import { Provider } from 'react-intl-redux';
|
|
7
|
-
import { BlinkingDot } from '../components/BlinkingDot';
|
|
8
|
-
|
|
9
|
-
const mockStore = configureStore();
|
|
10
|
-
|
|
11
|
-
describe('BlinkingDot', () => {
|
|
12
|
-
let store;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
store = mockStore({
|
|
16
|
-
userSession: { token: '1234' },
|
|
17
|
-
intl: { locale: 'en', messages: {} },
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const renderComponent = (props) =>
|
|
22
|
-
renderer.create(
|
|
23
|
-
<Provider store={store}>
|
|
24
|
-
<MemoryRouter>
|
|
25
|
-
<BlinkingDot {...props} />
|
|
26
|
-
</MemoryRouter>
|
|
27
|
-
</Provider>,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
it('renders blinking dot when active', () => {
|
|
31
|
-
const props = {
|
|
32
|
-
isActive: true,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const component = renderComponent(props);
|
|
36
|
-
const json = component.toJSON();
|
|
37
|
-
expect(json).toMatchSnapshot();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('renders inactive dot when not active', () => {
|
|
41
|
-
const props = {
|
|
42
|
-
isActive: false,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const component = renderComponent(props);
|
|
46
|
-
const json = component.toJSON();
|
|
47
|
-
expect(json).toMatchSnapshot();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('applies custom className', () => {
|
|
51
|
-
const props = {
|
|
52
|
-
isActive: true,
|
|
53
|
-
className: 'custom-class',
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const component = renderComponent(props);
|
|
57
|
-
const json = component.toJSON();
|
|
58
|
-
expect(json).toMatchSnapshot();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('applies custom size', () => {
|
|
62
|
-
const props = {
|
|
63
|
-
isActive: true,
|
|
64
|
-
size: 20,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const component = renderComponent(props);
|
|
68
|
-
const json = component.toJSON();
|
|
69
|
-
expect(json).toMatchSnapshot();
|
|
70
|
-
});
|
|
71
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
2
|
-
import configureStore from 'redux-mock-store';
|
|
3
|
-
import renderer from 'react-test-renderer';
|
|
4
|
-
|
|
5
|
-
import '@testing-library/jest-dom';
|
|
6
|
-
import { Provider } from 'react-intl-redux';
|
|
7
|
-
import { ChatMessage } from '../chat/ChatMessage';
|
|
8
|
-
|
|
9
|
-
const mockStore = configureStore();
|
|
10
|
-
|
|
11
|
-
// Mock loadable components
|
|
12
|
-
jest.mock('@loadable/component', () => {
|
|
13
|
-
const loadable = () => {
|
|
14
|
-
const MockComponent = ({ children }) => <div>{children}</div>;
|
|
15
|
-
return MockComponent;
|
|
16
|
-
};
|
|
17
|
-
loadable.lib = () => {
|
|
18
|
-
const MockComponent = ({ children }) =>
|
|
19
|
-
children ? children({ default: {} }) : null;
|
|
20
|
-
return MockComponent;
|
|
21
|
-
};
|
|
22
|
-
return { __esModule: true, default: loadable };
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('ChatMessage', () => {
|
|
26
|
-
let store;
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
store = mockStore({
|
|
30
|
-
userSession: { token: '1234' },
|
|
31
|
-
intl: { locale: 'en', messages: {} },
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const renderComponent = (props) =>
|
|
36
|
-
renderer.create(
|
|
37
|
-
<Provider store={store}>
|
|
38
|
-
<MemoryRouter>
|
|
39
|
-
<ChatMessage {...props} />
|
|
40
|
-
</MemoryRouter>
|
|
41
|
-
</Provider>,
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
it('renders error message correctly', () => {
|
|
45
|
-
const props = {
|
|
46
|
-
message: {
|
|
47
|
-
messageId: 3,
|
|
48
|
-
type: 'error',
|
|
49
|
-
error: 'Something went wrong',
|
|
50
|
-
},
|
|
51
|
-
libs: { remarkGfm: { default: [] } },
|
|
52
|
-
isLoading: false,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const component = renderComponent(props);
|
|
56
|
-
const json = component.toJSON();
|
|
57
|
-
expect(json).toMatchSnapshot();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('returns null for unknown message type', () => {
|
|
61
|
-
const props = {
|
|
62
|
-
message: {
|
|
63
|
-
messageId: 4,
|
|
64
|
-
message: 'Unknown type',
|
|
65
|
-
type: 'unknown',
|
|
66
|
-
},
|
|
67
|
-
libs: { remarkGfm: { default: [] } },
|
|
68
|
-
isLoading: false,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const component = renderComponent(props);
|
|
72
|
-
const json = component.toJSON();
|
|
73
|
-
expect(json).toBeNull();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import ChatMessageFeedback from '../components/ChatMessageFeedback';
|
|
4
|
-
|
|
5
|
-
jest.mock('../components/FeedbackModal', () => (props) => {
|
|
6
|
-
const { modalOpen, onClose, onToast } = props;
|
|
7
|
-
|
|
8
|
-
return modalOpen ? (
|
|
9
|
-
<div data-testid="feedback-modal">
|
|
10
|
-
Modal Open
|
|
11
|
-
<button
|
|
12
|
-
onClick={() => {
|
|
13
|
-
onToast('Thank you for your feedback!', 'success');
|
|
14
|
-
onClose();
|
|
15
|
-
}}
|
|
16
|
-
>
|
|
17
|
-
Submit Feedback
|
|
18
|
-
</button>
|
|
19
|
-
</div>
|
|
20
|
-
) : null;
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
jest.mock('../components/Icon', () => ({ name }) => (
|
|
24
|
-
<img src={name} alt="icon" />
|
|
25
|
-
));
|
|
26
|
-
|
|
27
|
-
jest.mock('../components/markdown', () => ({
|
|
28
|
-
SVGIcon: ({ name }) => <img src={name} alt="icon" />,
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
jest.mock('../../icons/thumbs-up.svg', () => 'thumbs-up.svg');
|
|
32
|
-
jest.mock('../../icons/thumbs-down.svg', () => 'thumbs-down.svg');
|
|
33
|
-
|
|
34
|
-
describe('ChatMessageFeedback', () => {
|
|
35
|
-
const defaultProps = {
|
|
36
|
-
message: {
|
|
37
|
-
messageId: 1,
|
|
38
|
-
message: 'Test message',
|
|
39
|
-
type: 'assistant',
|
|
40
|
-
},
|
|
41
|
-
feedbackReasons: ['Reason 1', 'Reason 2'],
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
it('renders Like and Dislike buttons', () => {
|
|
45
|
-
render(<ChatMessageFeedback {...defaultProps} />);
|
|
46
|
-
expect(screen.getByLabelText('Like')).toBeInTheDocument();
|
|
47
|
-
expect(screen.getByLabelText('Dislike')).toBeInTheDocument();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('opens modal when Like is clicked', () => {
|
|
51
|
-
render(<ChatMessageFeedback {...defaultProps} />);
|
|
52
|
-
fireEvent.click(screen.getByLabelText('Like'));
|
|
53
|
-
expect(screen.getByTestId('feedback-modal')).toBeInTheDocument();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('opens modal when Dislike is clicked', () => {
|
|
57
|
-
render(<ChatMessageFeedback {...defaultProps} />);
|
|
58
|
-
fireEvent.click(screen.getByLabelText('Dislike'));
|
|
59
|
-
expect(screen.getByTestId('feedback-modal')).toBeInTheDocument();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('shows toast after submitting feedback in modal', () => {
|
|
63
|
-
render(<ChatMessageFeedback {...defaultProps} />);
|
|
64
|
-
fireEvent.click(screen.getByLabelText('Like'));
|
|
65
|
-
|
|
66
|
-
const submitButton = screen.getByText('Submit Feedback');
|
|
67
|
-
fireEvent.click(submitButton);
|
|
68
|
-
|
|
69
|
-
expect(
|
|
70
|
-
screen.getByText('Thank you for your feedback!'),
|
|
71
|
-
).toBeInTheDocument();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
2
|
-
import configureStore from 'redux-mock-store';
|
|
3
|
-
import renderer from 'react-test-renderer';
|
|
4
|
-
|
|
5
|
-
import '@testing-library/jest-dom';
|
|
6
|
-
import { Provider } from 'react-intl-redux';
|
|
7
|
-
import { Citation } from '../components/markdown/Citation';
|
|
8
|
-
|
|
9
|
-
const mockStore = configureStore();
|
|
10
|
-
|
|
11
|
-
describe('Citation', () => {
|
|
12
|
-
it('should render the component with link', () => {
|
|
13
|
-
const store = mockStore({
|
|
14
|
-
userSession: { token: '1234' },
|
|
15
|
-
intl: {
|
|
16
|
-
locale: 'en',
|
|
17
|
-
messages: {},
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const component = renderer.create(
|
|
22
|
-
<Provider store={store}>
|
|
23
|
-
<MemoryRouter>
|
|
24
|
-
<Citation
|
|
25
|
-
message={{
|
|
26
|
-
messageId: 6428,
|
|
27
|
-
message: 'Donec quam felis ultricies nec',
|
|
28
|
-
type: 'assistant',
|
|
29
|
-
query: 'Pellentesque libero tortor tincidunt et?',
|
|
30
|
-
documents: [
|
|
31
|
-
{
|
|
32
|
-
document_id: 'https://www.example.com',
|
|
33
|
-
semantic_identifier: 'Nam ipsum risus rutrum vitae',
|
|
34
|
-
link: 'https://www.example.com',
|
|
35
|
-
blurb:
|
|
36
|
-
'Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. ',
|
|
37
|
-
source_type: 'web',
|
|
38
|
-
match_highlights: ['', 'Praesent ac sem eget est', ''],
|
|
39
|
-
updated_at: null,
|
|
40
|
-
db_doc_id: 99186,
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
citations: {
|
|
44
|
-
1: 99186,
|
|
45
|
-
},
|
|
46
|
-
parentMessageId: 6427,
|
|
47
|
-
alternateAssistantID: null,
|
|
48
|
-
}}
|
|
49
|
-
value={['[1]']}
|
|
50
|
-
link="https://www.example.com"
|
|
51
|
-
/>
|
|
52
|
-
</MemoryRouter>
|
|
53
|
-
</Provider>,
|
|
54
|
-
);
|
|
55
|
-
const json = component.toJSON();
|
|
56
|
-
expect(json).toMatchSnapshot();
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('Citation', () => {
|
|
61
|
-
it('should render the component without link', () => {
|
|
62
|
-
const store = mockStore({
|
|
63
|
-
userSession: { token: '1234' },
|
|
64
|
-
intl: {
|
|
65
|
-
locale: 'en',
|
|
66
|
-
messages: {},
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const component = renderer.create(
|
|
71
|
-
<Provider store={store}>
|
|
72
|
-
<MemoryRouter>
|
|
73
|
-
<Citation
|
|
74
|
-
message={{
|
|
75
|
-
messageId: 6428,
|
|
76
|
-
message: 'Donec quam felis ultricies nec',
|
|
77
|
-
type: 'assistant',
|
|
78
|
-
query: 'Pellentesque libero tortor tincidunt et?',
|
|
79
|
-
documents: [
|
|
80
|
-
{
|
|
81
|
-
document_id: 'https://www.example.com',
|
|
82
|
-
semantic_identifier: 'Nam ipsum risus rutrum vitae',
|
|
83
|
-
link: 'https://www.example.com',
|
|
84
|
-
blurb:
|
|
85
|
-
'Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. ',
|
|
86
|
-
source_type: 'web',
|
|
87
|
-
match_highlights: ['', 'Praesent ac sem eget est', ''],
|
|
88
|
-
updated_at: null,
|
|
89
|
-
db_doc_id: 99186,
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
citations: {
|
|
93
|
-
1: 99186,
|
|
94
|
-
},
|
|
95
|
-
parentMessageId: 6427,
|
|
96
|
-
alternateAssistantID: null,
|
|
97
|
-
}}
|
|
98
|
-
value={['[1]']}
|
|
99
|
-
link=""
|
|
100
|
-
/>
|
|
101
|
-
</MemoryRouter>
|
|
102
|
-
</Provider>,
|
|
103
|
-
);
|
|
104
|
-
const json = component.toJSON();
|
|
105
|
-
expect(json).toMatchSnapshot();
|
|
106
|
-
});
|
|
107
|
-
});
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import renderer from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
import { ClaimModal } from '../components/markdown/ClaimModal';
|
|
5
|
-
|
|
6
|
-
// Mock semantic-ui-react Modal
|
|
7
|
-
jest.mock('semantic-ui-react', () => ({
|
|
8
|
-
Modal: ({ children, trigger, className }) => (
|
|
9
|
-
<div className={className} data-testid="modal">
|
|
10
|
-
<div data-testid="trigger">{trigger}</div>
|
|
11
|
-
<div data-testid="content">{children}</div>
|
|
12
|
-
</div>
|
|
13
|
-
),
|
|
14
|
-
ModalHeader: ({ children }) => <div data-testid="header">{children}</div>,
|
|
15
|
-
ModalContent: ({ children }) => (
|
|
16
|
-
<div data-testid="modal-content">{children}</div>
|
|
17
|
-
),
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
// Mock ClaimSegments
|
|
21
|
-
jest.mock('../components/markdown/ClaimSegments', () => ({
|
|
22
|
-
ClaimSegments: () => <div data-testid="claim-segments">ClaimSegments</div>,
|
|
23
|
-
}));
|
|
24
|
-
|
|
25
|
-
describe('ClaimModal', () => {
|
|
26
|
-
const defaultProps = {
|
|
27
|
-
claim: {
|
|
28
|
-
score: 0.85,
|
|
29
|
-
claimString: 'This is a claim about something important.',
|
|
30
|
-
rationale: 'The claim is supported by multiple sources.',
|
|
31
|
-
segmentIds: [1, 2, 3],
|
|
32
|
-
},
|
|
33
|
-
markers: {
|
|
34
|
-
segments: {
|
|
35
|
-
1: { id: 1, text: 'segment 1' },
|
|
36
|
-
2: { id: 2, text: 'segment 2' },
|
|
37
|
-
3: { id: 3, text: 'segment 3' },
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
text: ['something important'],
|
|
41
|
-
citedSources: [
|
|
42
|
-
{ id: 1, semantic_identifier: 'Source 1', link: 'https://example.com' },
|
|
43
|
-
],
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
it('renders the claim modal with high score', () => {
|
|
47
|
-
const component = renderer.create(<ClaimModal {...defaultProps} />);
|
|
48
|
-
const json = component.toJSON();
|
|
49
|
-
expect(json).toMatchSnapshot();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('renders with low score', () => {
|
|
53
|
-
const props = {
|
|
54
|
-
...defaultProps,
|
|
55
|
-
claim: {
|
|
56
|
-
...defaultProps.claim,
|
|
57
|
-
score: 0.3,
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
61
|
-
const json = component.toJSON();
|
|
62
|
-
expect(json).toMatchSnapshot();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('renders with medium score', () => {
|
|
66
|
-
const props = {
|
|
67
|
-
...defaultProps,
|
|
68
|
-
claim: {
|
|
69
|
-
...defaultProps.claim,
|
|
70
|
-
score: 0.6,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
74
|
-
const json = component.toJSON();
|
|
75
|
-
expect(json).toMatchSnapshot();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('handles empty text array', () => {
|
|
79
|
-
const props = {
|
|
80
|
-
...defaultProps,
|
|
81
|
-
text: [],
|
|
82
|
-
};
|
|
83
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
84
|
-
const json = component.toJSON();
|
|
85
|
-
expect(json).toMatchSnapshot();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('handles claim with markdown formatting', () => {
|
|
89
|
-
const props = {
|
|
90
|
-
...defaultProps,
|
|
91
|
-
claim: {
|
|
92
|
-
...defaultProps.claim,
|
|
93
|
-
claimString: '**Bold claim** with *italic* and [[1]](url)',
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
97
|
-
const json = component.toJSON();
|
|
98
|
-
expect(json).toMatchSnapshot();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('renders with empty markers', () => {
|
|
102
|
-
const props = {
|
|
103
|
-
...defaultProps,
|
|
104
|
-
markers: {},
|
|
105
|
-
};
|
|
106
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
107
|
-
const json = component.toJSON();
|
|
108
|
-
expect(json).toMatchSnapshot();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('handles zero score', () => {
|
|
112
|
-
const props = {
|
|
113
|
-
...defaultProps,
|
|
114
|
-
claim: {
|
|
115
|
-
...defaultProps.claim,
|
|
116
|
-
score: 0,
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
120
|
-
const json = component.toJSON();
|
|
121
|
-
expect(json).toMatchSnapshot();
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('handles perfect score', () => {
|
|
125
|
-
const props = {
|
|
126
|
-
...defaultProps,
|
|
127
|
-
claim: {
|
|
128
|
-
...defaultProps.claim,
|
|
129
|
-
score: 1.0,
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
const component = renderer.create(<ClaimModal {...props} />);
|
|
133
|
-
const json = component.toJSON();
|
|
134
|
-
expect(json).toMatchSnapshot();
|
|
135
|
-
});
|
|
136
|
-
});
|