@eeacms/volto-eea-chatbot 2.0.0 → 2.0.2
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 +12 -1
- package/jest-addon.config.js +1 -0
- package/package.json +1 -1
- package/src/ChatBlock/ChatBlockEdit.jsx +2 -1
- package/src/ChatBlock/chat/AIMessage.tsx +20 -16
- package/src/ChatBlock/chat/ChatMessage.tsx +1 -1
- package/src/ChatBlock/chat/ChatWindow.tsx +10 -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 +7 -4
- package/src/ChatBlock/hooks/useChatStreaming.ts +4 -4
- package/src/ChatBlock/hooks/useToolDisplayTiming.ts +1 -1
- package/src/ChatBlock/index.js +8 -0
- package/src/ChatBlock/packets/MultiToolRenderer.tsx +11 -12
- package/src/ChatBlock/packets/RendererComponent.tsx +6 -3
- 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 +8 -8
- package/src/ChatBlock/packets/renderers/ReasoningRenderer.tsx +5 -5
- package/src/ChatBlock/packets/renderers/SearchToolRenderer.tsx +10 -10
- package/src/ChatBlock/services/messageProcessor.ts +6 -3
- package/src/ChatBlock/services/packetUtils.ts +2 -2
- package/src/ChatBlock/services/streamingService.ts +8 -2
- package/src/ChatBlock/utils/citations.ts +1 -1
- package/src/halloumi/filtering.test.js +199 -1
- 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
- /package/src/ChatBlock/{schema.js → schema.jsx} +0 -0
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent, act } from '@testing-library/react';
|
|
2
|
-
import '@testing-library/jest-dom';
|
|
3
|
-
import FeedbackModal from '../components/FeedbackModal';
|
|
4
|
-
import * as lib from '../utils';
|
|
5
|
-
|
|
6
|
-
jest.mock('../utils');
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
jest.clearAllMocks();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe('FeedbackModal', () => {
|
|
13
|
-
const baseProps = {
|
|
14
|
-
modalOpen: true,
|
|
15
|
-
onClose: jest.fn(),
|
|
16
|
-
setToast: jest.fn(),
|
|
17
|
-
onToast: jest.fn(),
|
|
18
|
-
setIsToastActive: jest.fn(),
|
|
19
|
-
message: { messageId: '1234' },
|
|
20
|
-
feedbackReasons: ['Reason 1', 'Reason 2'],
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
it('submits positive feedback successfully', async () => {
|
|
24
|
-
lib.createChatMessageFeedback.mockResolvedValue({});
|
|
25
|
-
|
|
26
|
-
render(<FeedbackModal {...baseProps} isPositive={true} />);
|
|
27
|
-
|
|
28
|
-
fireEvent.change(
|
|
29
|
-
screen.getByPlaceholderText(/What did you like about this response/i),
|
|
30
|
-
{ target: { value: 'Great response!' } },
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
await act(async () => {
|
|
34
|
-
fireEvent.click(screen.getByText('Submit Feedback'));
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(lib.createChatMessageFeedback).toHaveBeenCalledWith({
|
|
38
|
-
chat_message_id: '1234',
|
|
39
|
-
feedback_text: 'Great response!',
|
|
40
|
-
is_positive: true,
|
|
41
|
-
predefined_feedback: '',
|
|
42
|
-
});
|
|
43
|
-
expect(baseProps.onToast).toHaveBeenCalledWith(
|
|
44
|
-
'Thanks for your feedback!',
|
|
45
|
-
'success',
|
|
46
|
-
);
|
|
47
|
-
expect(baseProps.setIsToastActive).toHaveBeenCalledWith(true);
|
|
48
|
-
expect(baseProps.onClose).toHaveBeenCalled();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('submits negative feedback with selected reason', async () => {
|
|
52
|
-
lib.createChatMessageFeedback.mockResolvedValue({});
|
|
53
|
-
|
|
54
|
-
render(<FeedbackModal {...baseProps} isPositive={false} />);
|
|
55
|
-
|
|
56
|
-
const reasonBtn = screen.getByRole('button', { name: 'Reason 1' });
|
|
57
|
-
fireEvent.click(reasonBtn);
|
|
58
|
-
expect(reasonBtn.classList.contains('primary')).toBe(true);
|
|
59
|
-
|
|
60
|
-
fireEvent.change(screen.getByPlaceholderText(/What could be improved/i), {
|
|
61
|
-
target: { value: 'Needs more details' },
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
await act(async () => {
|
|
65
|
-
fireEvent.click(screen.getByText('Submit Feedback'));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(lib.createChatMessageFeedback).toHaveBeenCalledWith({
|
|
69
|
-
chat_message_id: '1234',
|
|
70
|
-
feedback_text: 'Needs more details',
|
|
71
|
-
is_positive: false,
|
|
72
|
-
predefined_feedback: 'Reason 1',
|
|
73
|
-
});
|
|
74
|
-
expect(baseProps.onToast).toHaveBeenCalledWith(
|
|
75
|
-
'Thanks for your feedback!',
|
|
76
|
-
'success',
|
|
77
|
-
);
|
|
78
|
-
expect(baseProps.onClose).toHaveBeenCalled();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('handles submission failure', async () => {
|
|
82
|
-
lib.createChatMessageFeedback.mockRejectedValue(new Error('fail'));
|
|
83
|
-
|
|
84
|
-
render(<FeedbackModal {...baseProps} isPositive={true} />);
|
|
85
|
-
|
|
86
|
-
await act(async () => {
|
|
87
|
-
fireEvent.click(screen.getByText('Submit Feedback'));
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
expect(baseProps.onToast).toHaveBeenCalledWith(
|
|
91
|
-
'Failed to submit feedback.',
|
|
92
|
-
'error',
|
|
93
|
-
);
|
|
94
|
-
expect(baseProps.setIsToastActive).toHaveBeenCalledWith(true);
|
|
95
|
-
expect(baseProps.onClose).toHaveBeenCalled();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('resets and closes modal on Cancel click', () => {
|
|
99
|
-
render(<FeedbackModal {...baseProps} isPositive={true} />);
|
|
100
|
-
|
|
101
|
-
const textarea = screen.getByPlaceholderText(
|
|
102
|
-
/What did you like about this response/i,
|
|
103
|
-
);
|
|
104
|
-
fireEvent.change(textarea, { target: { value: 'Some feedback' } });
|
|
105
|
-
expect(textarea.value).toBe('Some feedback');
|
|
106
|
-
|
|
107
|
-
fireEvent.click(screen.getByText('Cancel'));
|
|
108
|
-
expect(baseProps.onClose).toHaveBeenCalled();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('toggles reason button selected state on click', () => {
|
|
112
|
-
render(<FeedbackModal {...baseProps} isPositive={false} />);
|
|
113
|
-
|
|
114
|
-
const reason1 = screen.getByRole('button', { name: 'Reason 1' });
|
|
115
|
-
const reason2 = screen.getByRole('button', { name: 'Reason 2' });
|
|
116
|
-
|
|
117
|
-
expect(reason1.classList.contains('inverted')).toBe(true);
|
|
118
|
-
expect(reason2.classList.contains('inverted')).toBe(true);
|
|
119
|
-
|
|
120
|
-
fireEvent.click(reason1);
|
|
121
|
-
expect(reason1.classList.contains('inverted')).toBe(false);
|
|
122
|
-
expect(reason2.classList.contains('inverted')).toBe(true);
|
|
123
|
-
|
|
124
|
-
fireEvent.click(reason2);
|
|
125
|
-
expect(reason1.classList.contains('inverted')).toBe(true);
|
|
126
|
-
expect(reason2.classList.contains('inverted')).toBe(false);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('updates textarea value on user input', () => {
|
|
130
|
-
render(<FeedbackModal {...baseProps} isPositive={true} />);
|
|
131
|
-
|
|
132
|
-
const textarea = screen.getByPlaceholderText(
|
|
133
|
-
/What did you like about this response/i,
|
|
134
|
-
);
|
|
135
|
-
fireEvent.change(textarea, { target: { value: 'Awesome!' } });
|
|
136
|
-
expect(textarea.value).toBe('Awesome!');
|
|
137
|
-
});
|
|
138
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
import { FetchToolRenderer } from '../packets/renderers/FetchToolRenderer';
|
|
5
|
-
import { PacketType } from '../types/streamingModels';
|
|
6
|
-
|
|
7
|
-
describe('FetchToolRenderer', () => {
|
|
8
|
-
const mockChildRenderer = (result) => (
|
|
9
|
-
<div data-testid="renderer-result">
|
|
10
|
-
<div data-testid="status">{result.status}</div>
|
|
11
|
-
<div data-testid="content">{result.content}</div>
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
it('renders fetching state when not complete', () => {
|
|
16
|
-
const props = {
|
|
17
|
-
packets: [
|
|
18
|
-
{
|
|
19
|
-
ind: 1,
|
|
20
|
-
obj: {
|
|
21
|
-
type: PacketType.FETCH_TOOL_START,
|
|
22
|
-
queries: ['search query'],
|
|
23
|
-
documents: null,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
onComplete: jest.fn(),
|
|
28
|
-
children: mockChildRenderer,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
32
|
-
const json = component.toJSON();
|
|
33
|
-
expect(json).toMatchSnapshot();
|
|
34
|
-
expect(props.onComplete).not.toHaveBeenCalled();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('renders complete state', () => {
|
|
38
|
-
const props = {
|
|
39
|
-
packets: [
|
|
40
|
-
{
|
|
41
|
-
ind: 1,
|
|
42
|
-
obj: {
|
|
43
|
-
type: PacketType.FETCH_TOOL_START,
|
|
44
|
-
queries: ['search query'],
|
|
45
|
-
documents: [
|
|
46
|
-
{
|
|
47
|
-
document_id: 'doc1',
|
|
48
|
-
semantic_identifier: 'Document 1',
|
|
49
|
-
link: 'https://example.com/1',
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
55
|
-
],
|
|
56
|
-
onComplete: jest.fn(),
|
|
57
|
-
children: mockChildRenderer,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
61
|
-
const json = component.toJSON();
|
|
62
|
-
expect(json).toMatchSnapshot();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('renders with multiple queries', () => {
|
|
66
|
-
const props = {
|
|
67
|
-
packets: [
|
|
68
|
-
{
|
|
69
|
-
ind: 1,
|
|
70
|
-
obj: {
|
|
71
|
-
type: PacketType.FETCH_TOOL_START,
|
|
72
|
-
queries: ['first query', 'second query', 'third query'],
|
|
73
|
-
documents: null,
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
onComplete: jest.fn(),
|
|
78
|
-
children: mockChildRenderer,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
82
|
-
const json = component.toJSON();
|
|
83
|
-
expect(json).toMatchSnapshot();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('renders with multiple documents', () => {
|
|
87
|
-
const props = {
|
|
88
|
-
packets: [
|
|
89
|
-
{
|
|
90
|
-
ind: 1,
|
|
91
|
-
obj: {
|
|
92
|
-
type: PacketType.FETCH_TOOL_START,
|
|
93
|
-
queries: ['query'],
|
|
94
|
-
documents: [
|
|
95
|
-
{ document_id: 'doc1' },
|
|
96
|
-
{ document_id: 'doc2' },
|
|
97
|
-
{ document_id: 'doc3' },
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
102
|
-
],
|
|
103
|
-
onComplete: jest.fn(),
|
|
104
|
-
children: mockChildRenderer,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
108
|
-
const json = component.toJSON();
|
|
109
|
-
expect(json).toMatchSnapshot();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('handles empty queries and documents', () => {
|
|
113
|
-
const props = {
|
|
114
|
-
packets: [
|
|
115
|
-
{
|
|
116
|
-
ind: 1,
|
|
117
|
-
obj: {
|
|
118
|
-
type: PacketType.FETCH_TOOL_START,
|
|
119
|
-
queries: null,
|
|
120
|
-
documents: null,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
onComplete: jest.fn(),
|
|
125
|
-
children: mockChildRenderer,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
129
|
-
const json = component.toJSON();
|
|
130
|
-
expect(json).toMatchSnapshot();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('handles empty packets array', () => {
|
|
134
|
-
const props = {
|
|
135
|
-
packets: [],
|
|
136
|
-
onComplete: jest.fn(),
|
|
137
|
-
children: mockChildRenderer,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const component = renderer.create(<FetchToolRenderer {...props} />);
|
|
141
|
-
const json = component.toJSON();
|
|
142
|
-
expect(json).toMatchSnapshot();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('calls onComplete when section end is received', () => {
|
|
146
|
-
const onComplete = jest.fn();
|
|
147
|
-
const props = {
|
|
148
|
-
packets: [
|
|
149
|
-
{ ind: 1, obj: { type: PacketType.FETCH_TOOL_START, queries: [] } },
|
|
150
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
151
|
-
],
|
|
152
|
-
onComplete,
|
|
153
|
-
children: mockChildRenderer,
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
act(() => {
|
|
157
|
-
renderer.create(<FetchToolRenderer {...props} />);
|
|
158
|
-
});
|
|
159
|
-
expect(onComplete).toHaveBeenCalled();
|
|
160
|
-
});
|
|
161
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import HalloumiFeedback from '../components/HalloumiFeedback';
|
|
4
|
-
|
|
5
|
-
jest.mock('../components/Spinner', () => () => (
|
|
6
|
-
<div data-testid="spinner">Loading...</div>
|
|
7
|
-
));
|
|
8
|
-
|
|
9
|
-
jest.mock('../components/Icon', () => ({ name }) => (
|
|
10
|
-
<img src={name} alt="icon" />
|
|
11
|
-
));
|
|
12
|
-
|
|
13
|
-
jest.mock('../../icons/glasses.svg', () => 'glasses.svg');
|
|
14
|
-
|
|
15
|
-
jest.mock('@plone/volto-slate/editor/render', () => ({
|
|
16
|
-
serializeNodes: (nodes) => {
|
|
17
|
-
const visitTextNodes = (node) => {
|
|
18
|
-
if (Array.isArray(node)) return node.map(visitTextNodes).join('');
|
|
19
|
-
if (node && typeof node === 'object') {
|
|
20
|
-
if (node.text) return node.text;
|
|
21
|
-
if (node.children) return visitTextNodes(node.children);
|
|
22
|
-
}
|
|
23
|
-
return '';
|
|
24
|
-
};
|
|
25
|
-
return visitTextNodes(nodes);
|
|
26
|
-
},
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
describe('HalloumiFeedback', () => {
|
|
30
|
-
const defaultProps = {
|
|
31
|
-
halloumiMessage: null,
|
|
32
|
-
isLoadingHalloumi: false,
|
|
33
|
-
markers: { claims: [{ score: 50, rationale: 'Some rationale' }] },
|
|
34
|
-
score: 75,
|
|
35
|
-
scoreColor: 'green',
|
|
36
|
-
onManualVerify: jest.fn(),
|
|
37
|
-
showVerifyClaimsButton: false,
|
|
38
|
-
sources: [],
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
it('renders fact-check button when showVerifyClaimsButton is true', () => {
|
|
42
|
-
render(<HalloumiFeedback {...defaultProps} showVerifyClaimsButton />);
|
|
43
|
-
const button = screen.getByRole('button', {
|
|
44
|
-
name: /Fact-check AI answer/i,
|
|
45
|
-
});
|
|
46
|
-
expect(button).toBeInTheDocument();
|
|
47
|
-
fireEvent.click(button);
|
|
48
|
-
expect(defaultProps.onManualVerify).toHaveBeenCalled();
|
|
49
|
-
expect(screen.getByText(/Please allow a few minutes/i)).toBeInTheDocument();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('renders VerifyClaims message when loading and sources exist', () => {
|
|
53
|
-
render(
|
|
54
|
-
<HalloumiFeedback
|
|
55
|
-
{...defaultProps}
|
|
56
|
-
isLoadingHalloumi
|
|
57
|
-
sources={['doc1']}
|
|
58
|
-
showVerifyClaimsButton
|
|
59
|
-
/>,
|
|
60
|
-
);
|
|
61
|
-
expect(screen.getByTestId('spinner')).toBeInTheDocument();
|
|
62
|
-
expect(screen.getByText(/Going through each claim/i)).toBeInTheDocument();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('renders rationale message when no claims score', () => {
|
|
66
|
-
render(
|
|
67
|
-
<HalloumiFeedback
|
|
68
|
-
{...defaultProps}
|
|
69
|
-
markers={{ claims: [{ score: null, rationale: 'Failed to verify' }] }}
|
|
70
|
-
/>,
|
|
71
|
-
);
|
|
72
|
-
expect(screen.getByText('Failed to verify')).toBeInTheDocument();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('renders halloumiMessage with score replaced', () => {
|
|
76
|
-
const halloumiMessage = [
|
|
77
|
-
{ type: 'paragraph', children: [{ text: 'Score: {score}' }] },
|
|
78
|
-
];
|
|
79
|
-
render(
|
|
80
|
-
<HalloumiFeedback
|
|
81
|
-
{...defaultProps}
|
|
82
|
-
halloumiMessage={halloumiMessage}
|
|
83
|
-
score={88}
|
|
84
|
-
/>,
|
|
85
|
-
);
|
|
86
|
-
expect(screen.getByText('Score: 88%')).toBeInTheDocument();
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('does not render anything extra when no special props', () => {
|
|
90
|
-
render(<HalloumiFeedback {...defaultProps} />);
|
|
91
|
-
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
92
|
-
expect(screen.queryByTestId('spinner')).not.toBeInTheDocument();
|
|
93
|
-
});
|
|
94
|
-
});
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
import { ImageToolRenderer } from '../packets/renderers/ImageToolRenderer';
|
|
5
|
-
import { PacketType } from '../types/streamingModels';
|
|
6
|
-
|
|
7
|
-
describe('ImageToolRenderer', () => {
|
|
8
|
-
const mockChildRenderer = (result) => (
|
|
9
|
-
<div data-testid="renderer-result">
|
|
10
|
-
<div data-testid="status">{result.status}</div>
|
|
11
|
-
<div data-testid="content">{result.content}</div>
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
it('renders generating state when not complete', () => {
|
|
16
|
-
const props = {
|
|
17
|
-
packets: [
|
|
18
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
19
|
-
],
|
|
20
|
-
onComplete: jest.fn(),
|
|
21
|
-
children: mockChildRenderer,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
25
|
-
const json = component.toJSON();
|
|
26
|
-
expect(json).toMatchSnapshot();
|
|
27
|
-
expect(props.onComplete).not.toHaveBeenCalled();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('renders complete state with images', () => {
|
|
31
|
-
const props = {
|
|
32
|
-
packets: [
|
|
33
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
34
|
-
{
|
|
35
|
-
ind: 1,
|
|
36
|
-
obj: {
|
|
37
|
-
type: PacketType.IMAGE_GENERATION_TOOL_DELTA,
|
|
38
|
-
images: [
|
|
39
|
-
{
|
|
40
|
-
file_id: 'img1',
|
|
41
|
-
url: 'https://example.com/image1.png',
|
|
42
|
-
revised_prompt: 'A beautiful landscape',
|
|
43
|
-
shape: 'landscape',
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
49
|
-
],
|
|
50
|
-
onComplete: jest.fn(),
|
|
51
|
-
children: mockChildRenderer,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
55
|
-
const json = component.toJSON();
|
|
56
|
-
expect(json).toMatchSnapshot();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('renders multiple images', () => {
|
|
60
|
-
const props = {
|
|
61
|
-
packets: [
|
|
62
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
63
|
-
{
|
|
64
|
-
ind: 1,
|
|
65
|
-
obj: {
|
|
66
|
-
type: PacketType.IMAGE_GENERATION_TOOL_DELTA,
|
|
67
|
-
images: [
|
|
68
|
-
{
|
|
69
|
-
file_id: 'img1',
|
|
70
|
-
url: 'https://example.com/image1.png',
|
|
71
|
-
revised_prompt: 'First image',
|
|
72
|
-
shape: 'square',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
file_id: 'img2',
|
|
76
|
-
url: 'https://example.com/image2.png',
|
|
77
|
-
revised_prompt: 'Second image',
|
|
78
|
-
shape: 'portrait',
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
84
|
-
],
|
|
85
|
-
onComplete: jest.fn(),
|
|
86
|
-
children: mockChildRenderer,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
90
|
-
const json = component.toJSON();
|
|
91
|
-
expect(json).toMatchSnapshot();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('handles image without revised_prompt', () => {
|
|
95
|
-
const props = {
|
|
96
|
-
packets: [
|
|
97
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
98
|
-
{
|
|
99
|
-
ind: 1,
|
|
100
|
-
obj: {
|
|
101
|
-
type: PacketType.IMAGE_GENERATION_TOOL_DELTA,
|
|
102
|
-
images: [
|
|
103
|
-
{
|
|
104
|
-
file_id: 'img1',
|
|
105
|
-
url: 'https://example.com/image1.png',
|
|
106
|
-
revised_prompt: '',
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
112
|
-
],
|
|
113
|
-
onComplete: jest.fn(),
|
|
114
|
-
children: mockChildRenderer,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
118
|
-
const json = component.toJSON();
|
|
119
|
-
expect(json).toMatchSnapshot();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('handles image without shape (defaults to square)', () => {
|
|
123
|
-
const props = {
|
|
124
|
-
packets: [
|
|
125
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
126
|
-
{
|
|
127
|
-
ind: 1,
|
|
128
|
-
obj: {
|
|
129
|
-
type: PacketType.IMAGE_GENERATION_TOOL_DELTA,
|
|
130
|
-
images: [
|
|
131
|
-
{
|
|
132
|
-
file_id: 'img1',
|
|
133
|
-
url: 'https://example.com/image1.png',
|
|
134
|
-
revised_prompt: 'Test',
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
140
|
-
],
|
|
141
|
-
onComplete: jest.fn(),
|
|
142
|
-
children: mockChildRenderer,
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
146
|
-
const json = component.toJSON();
|
|
147
|
-
expect(json).toMatchSnapshot();
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('handles empty packets array', () => {
|
|
151
|
-
const props = {
|
|
152
|
-
packets: [],
|
|
153
|
-
onComplete: jest.fn(),
|
|
154
|
-
children: mockChildRenderer,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const component = renderer.create(<ImageToolRenderer {...props} />);
|
|
158
|
-
const json = component.toJSON();
|
|
159
|
-
expect(json).toMatchSnapshot();
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('calls onComplete when section end is received', () => {
|
|
163
|
-
const onComplete = jest.fn();
|
|
164
|
-
const props = {
|
|
165
|
-
packets: [
|
|
166
|
-
{ ind: 1, obj: { type: PacketType.IMAGE_GENERATION_TOOL_START } },
|
|
167
|
-
{ ind: 1, obj: { type: PacketType.SECTION_END } },
|
|
168
|
-
],
|
|
169
|
-
onComplete,
|
|
170
|
-
children: mockChildRenderer,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
act(() => {
|
|
174
|
-
renderer.create(<ImageToolRenderer {...props} />);
|
|
175
|
-
});
|
|
176
|
-
expect(onComplete).toHaveBeenCalled();
|
|
177
|
-
});
|
|
178
|
-
});
|