@patternfly/chatbot 6.3.0-prerelease.10 → 6.3.0-prerelease.12

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 (51) hide show
  1. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +1 -1
  2. package/dist/cjs/Message/Message.test.js +3 -3
  3. package/dist/cjs/MessageBar/AttachButton.js +1 -1
  4. package/dist/cjs/MessageBar/AttachButton.test.js +7 -7
  5. package/dist/cjs/MessageBar/MessageBar.test.js +29 -29
  6. package/dist/cjs/MessageBar/MicrophoneButton.js +1 -1
  7. package/dist/cjs/MessageBar/SendButton.js +1 -1
  8. package/dist/cjs/MessageBar/SendButton.test.js +5 -5
  9. package/dist/cjs/MessageBar/StopButton.js +1 -1
  10. package/dist/cjs/MessageBar/StopButton.test.js +5 -5
  11. package/dist/cjs/MessageBox/JumpButton.js +1 -1
  12. package/dist/cjs/MessageBox/JumpButton.test.js +4 -4
  13. package/dist/cjs/MessageBox/MessageBox.test.js +2 -2
  14. package/dist/cjs/ResponseActions/ResponseActionButton.d.ts +2 -2
  15. package/dist/cjs/ResponseActions/ResponseActions.d.ts +4 -1
  16. package/dist/cjs/ResponseActions/ResponseActions.js +6 -6
  17. package/dist/cjs/ResponseActions/ResponseActions.test.js +16 -1
  18. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +1 -1
  19. package/dist/esm/Message/Message.test.js +3 -3
  20. package/dist/esm/MessageBar/AttachButton.js +1 -1
  21. package/dist/esm/MessageBar/AttachButton.test.js +7 -7
  22. package/dist/esm/MessageBar/MessageBar.test.js +29 -29
  23. package/dist/esm/MessageBar/MicrophoneButton.js +1 -1
  24. package/dist/esm/MessageBar/SendButton.js +1 -1
  25. package/dist/esm/MessageBar/SendButton.test.js +5 -5
  26. package/dist/esm/MessageBar/StopButton.js +1 -1
  27. package/dist/esm/MessageBar/StopButton.test.js +5 -5
  28. package/dist/esm/MessageBox/JumpButton.js +1 -1
  29. package/dist/esm/MessageBox/JumpButton.test.js +4 -4
  30. package/dist/esm/MessageBox/MessageBox.test.js +2 -2
  31. package/dist/esm/ResponseActions/ResponseActionButton.d.ts +2 -2
  32. package/dist/esm/ResponseActions/ResponseActions.d.ts +4 -1
  33. package/dist/esm/ResponseActions/ResponseActions.js +6 -6
  34. package/dist/esm/ResponseActions/ResponseActions.test.js +16 -1
  35. package/package.json +1 -1
  36. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +1 -1
  37. package/src/Message/Message.test.tsx +3 -3
  38. package/src/MessageBar/AttachButton.test.tsx +7 -7
  39. package/src/MessageBar/AttachButton.tsx +1 -1
  40. package/src/MessageBar/MessageBar.test.tsx +29 -29
  41. package/src/MessageBar/MicrophoneButton.tsx +2 -1
  42. package/src/MessageBar/SendButton.test.tsx +5 -5
  43. package/src/MessageBar/SendButton.tsx +1 -1
  44. package/src/MessageBar/StopButton.test.tsx +5 -5
  45. package/src/MessageBar/StopButton.tsx +1 -1
  46. package/src/MessageBox/JumpButton.test.tsx +4 -4
  47. package/src/MessageBox/JumpButton.tsx +1 -1
  48. package/src/MessageBox/MessageBox.test.tsx +2 -2
  49. package/src/ResponseActions/ResponseActionButton.tsx +2 -2
  50. package/src/ResponseActions/ResponseActions.test.tsx +18 -1
  51. package/src/ResponseActions/ResponseActions.tsx +10 -1
@@ -73,9 +73,9 @@ describe('Message bar', () => {
73
73
  });
74
74
  it('should render correctly', () => {
75
75
  render(<MessageBar onSendMessage={jest.fn} />);
76
- expect(screen.getByRole('button', { name: 'Attach button' })).toBeTruthy();
77
- expect(screen.queryByRole('button', { name: 'Send button' })).toBeFalsy();
78
- expect(screen.queryByRole('button', { name: 'Microphone button' })).toBeFalsy();
76
+ expect(screen.getByRole('button', { name: 'Attach' })).toBeTruthy();
77
+ expect(screen.queryByRole('button', { name: 'Send' })).toBeFalsy();
78
+ expect(screen.queryByRole('button', { name: 'Use microphone' })).toBeFalsy();
79
79
  expect(screen.getByRole('textbox', { name: /Send a message.../i })).toBeTruthy();
80
80
  });
81
81
  it('can send via enter key', async () => {
@@ -110,15 +110,15 @@ describe('Message bar', () => {
110
110
  const input = screen.getByRole('textbox', { name: /Send a message.../i });
111
111
  await userEvent.type(input, 'Hello world');
112
112
  expect(input).toHaveTextContent('Hello world');
113
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
113
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
114
114
  });
115
115
  it('can disable send button shown when text is input', async () => {
116
116
  render(<MessageBar onSendMessage={jest.fn} isSendButtonDisabled />);
117
117
  const input = screen.getByRole('textbox', { name: /Send a message.../i });
118
118
  await userEvent.type(input, 'Hello world');
119
119
  expect(input).toHaveTextContent('Hello world');
120
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
121
- expect(screen.getByRole('button', { name: 'Send button' })).toBeDisabled();
120
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
121
+ expect(screen.getByRole('button', { name: 'Send' })).toBeDisabled();
122
122
  });
123
123
  it('can click send button', async () => {
124
124
  const spy = jest.fn();
@@ -126,26 +126,26 @@ describe('Message bar', () => {
126
126
  const input = screen.getByRole('textbox', { name: /Send a message.../i });
127
127
  await userEvent.type(input, 'Hello world');
128
128
  expect(input).toHaveTextContent('Hello world');
129
- const sendButton = screen.getByRole('button', { name: 'Send button' });
129
+ const sendButton = screen.getByRole('button', { name: 'Send' });
130
130
  expect(sendButton).toBeTruthy();
131
131
  await userEvent.click(sendButton);
132
132
  expect(spy).toHaveBeenCalledTimes(1);
133
133
  });
134
134
  it('can always show send button', () => {
135
135
  render(<MessageBar onSendMessage={jest.fn} alwayShowSendButton />);
136
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
137
- expect(screen.getByRole('button', { name: 'Send button' })).toBeEnabled();
136
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
137
+ expect(screen.getByRole('button', { name: 'Send' })).toBeEnabled();
138
138
  });
139
139
  it('can disable send button if always showing', () => {
140
140
  render(<MessageBar onSendMessage={jest.fn} alwayShowSendButton isSendButtonDisabled />);
141
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
142
- expect(screen.getByRole('button', { name: 'Send button' })).toBeDisabled();
141
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
142
+ expect(screen.getByRole('button', { name: 'Send' })).toBeDisabled();
143
143
  });
144
144
  it('can handle buttonProps tooltipContent appropriately for send', async () => {
145
145
  render(
146
146
  <MessageBar onSendMessage={jest.fn} alwayShowSendButton buttonProps={{ send: { tooltipContent: 'Test' } }} />
147
147
  );
148
- await userEvent.click(screen.getByRole('button', { name: 'Send button' }));
148
+ await userEvent.click(screen.getByRole('button', { name: 'Send' }));
149
149
  expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
150
150
  });
151
151
  it('can handle buttonProps props appropriately for send', async () => {
@@ -203,13 +203,13 @@ describe('Message bar', () => {
203
203
  expect(screen.queryByRole('menuitem', { name: /Logs/i })).toBeFalsy();
204
204
  expect(screen.queryByRole('menuitem', { name: /YAML - Status/i })).toBeFalsy();
205
205
  expect(screen.queryByRole('menuitem', { name: /YAML - All contents/i })).toBeFalsy();
206
- const attachButton = screen.getByRole('button', { name: 'Attach button' });
206
+ const attachButton = screen.getByRole('button', { name: 'Attach' });
207
207
  await userEvent.click(attachButton);
208
208
  expect(attachToggleClickSpy).toHaveBeenCalledTimes(1);
209
209
  });
210
210
  it('can hide attach button', () => {
211
211
  render(<MessageBar onSendMessage={jest.fn} hasAttachButton={false} />);
212
- expect(screen.queryByRole('button', { name: 'Attach button' })).toBeFalsy();
212
+ expect(screen.queryByRole('button', { name: 'Attach' })).toBeFalsy();
213
213
  });
214
214
  // Based on this because I had no idea how to do this and was looking around: https://stackoverflow.com/a/75562651
215
215
  // See also https://developer.mozilla.org/en-US/docs/Web/API/File/File for what that file variable is doing
@@ -223,17 +223,17 @@ describe('Message bar', () => {
223
223
  buttonProps={{ attach: { inputTestId: 'input' } }}
224
224
  />
225
225
  );
226
- expect(screen.getByRole('button', { name: 'Attach button' })).toBeTruthy();
227
- await userEvent.click(screen.getByRole('button', { name: 'Attach button' }));
226
+ expect(screen.getByRole('button', { name: 'Attach' })).toBeTruthy();
227
+ await userEvent.click(screen.getByRole('button', { name: 'Attach' }));
228
228
  const file = new File(['test'], 'test.json');
229
229
  const input = screen.getByTestId('input') as HTMLInputElement;
230
230
  await userEvent.upload(input, file);
231
231
  expect(input.files).toHaveLength(1);
232
232
  expect(spy).toHaveBeenCalledTimes(1);
233
233
  });
234
- it('can handle buttonProps tooltipContent appropriately for attach', async () => {
234
+ it('can handle buttonProps tooltipContent appropriately for attach', async () => {
235
235
  render(<MessageBar onSendMessage={jest.fn} hasAttachButton buttonProps={{ attach: { tooltipContent: 'Test' } }} />);
236
- await userEvent.click(screen.getByRole('button', { name: 'Attach button' }));
236
+ await userEvent.click(screen.getByRole('button', { name: 'Attach' }));
237
237
  expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
238
238
  });
239
239
  it('can handle buttonProps props appropriately for attach', async () => {
@@ -251,12 +251,12 @@ describe('Message bar', () => {
251
251
  // --------------------------------------------------------------------------
252
252
  it('can show stop button', () => {
253
253
  render(<MessageBar onSendMessage={jest.fn} hasStopButton handleStopButton={jest.fn} />);
254
- expect(screen.getByRole('button', { name: 'Stop button' })).toBeTruthy();
254
+ expect(screen.getByRole('button', { name: 'Stop' })).toBeTruthy();
255
255
  });
256
256
  it('can call handleStopButton', async () => {
257
257
  const spy = jest.fn();
258
258
  render(<MessageBar onSendMessage={jest.fn} hasStopButton handleStopButton={spy} />);
259
- await userEvent.click(screen.getByRole('button', { name: 'Stop button' }));
259
+ await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
260
260
  expect(spy).toHaveBeenCalledTimes(1);
261
261
  });
262
262
  it('can handle buttonProps tooltipContent appropriately for stop', async () => {
@@ -268,7 +268,7 @@ describe('Message bar', () => {
268
268
  buttonProps={{ stop: { tooltipContent: 'Test' } }}
269
269
  />
270
270
  );
271
- await userEvent.click(screen.getByRole('button', { name: 'Stop button' }));
271
+ await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
272
272
  expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
273
273
  });
274
274
  it('can handle buttonProps props appropriately for stop', async () => {
@@ -287,12 +287,12 @@ describe('Message bar', () => {
287
287
  // --------------------------------------------------------------------------
288
288
  it('can hide microphone button when window.SpeechRecognition is not there', () => {
289
289
  render(<MessageBar onSendMessage={jest.fn} hasMicrophoneButton />);
290
- expect(screen.queryByRole('button', { name: 'Microphone button' })).toBeFalsy();
290
+ expect(screen.queryByRole('button', { name: 'Use microphone' })).toBeFalsy();
291
291
  });
292
292
  it('can show microphone button', () => {
293
293
  mockSpeechRecognition();
294
294
  render(<MessageBar onSendMessage={jest.fn} hasMicrophoneButton />);
295
- expect(screen.getByRole('button', { name: 'Microphone button' })).toBeTruthy();
295
+ expect(screen.getByRole('button', { name: 'Use microphone' })).toBeTruthy();
296
296
  });
297
297
  it('can handle buttonProps appropriately for microphone', async () => {
298
298
  mockSpeechRecognition();
@@ -305,15 +305,15 @@ describe('Message bar', () => {
305
305
  }}
306
306
  />
307
307
  );
308
- await userEvent.click(screen.getByRole('button', { name: 'Microphone button' }));
308
+ await userEvent.click(screen.getByRole('button', { name: 'Use microphone' }));
309
309
  expect(screen.getByRole('tooltip', { name: 'Currently listening' })).toBeTruthy();
310
- await userEvent.click(screen.getByRole('button', { name: 'Microphone button' }));
310
+ await userEvent.click(screen.getByRole('button', { name: 'Stop listening' }));
311
311
  expect(screen.getByRole('tooltip', { name: 'Not currently listening' })).toBeTruthy();
312
312
  });
313
313
  it('can customize the listening placeholder', async () => {
314
314
  mockSpeechRecognition();
315
315
  render(<MessageBar onSendMessage={jest.fn} hasMicrophoneButton listeningText="I am listening" />);
316
- await userEvent.click(screen.getByRole('button', { name: 'Microphone button' }));
316
+ await userEvent.click(screen.getByRole('button', { name: 'Use microphone' }));
317
317
  const input = screen.getByRole('textbox', { name: /I am listening/i });
318
318
  expect(input).toBeTruthy();
319
319
  });
@@ -330,9 +330,9 @@ describe('Message bar', () => {
330
330
  });
331
331
  it('can be controlled', () => {
332
332
  render(<MessageBar onSendMessage={jest.fn} value="test" />);
333
- expect(screen.getByRole('button', { name: 'Attach button' })).toBeTruthy();
334
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
335
- expect(screen.queryByRole('button', { name: 'Microphone button' })).toBeFalsy();
333
+ expect(screen.getByRole('button', { name: 'Attach' })).toBeTruthy();
334
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
335
+ expect(screen.queryByRole('button', { name: 'Use microphone' })).toBeFalsy();
336
336
  expect(screen.getByRole('textbox', { name: /Send a message.../i })).toBeTruthy();
337
337
  expect(screen.getByRole('textbox', { name: /Send a message.../i })).toHaveValue('test');
338
338
  });
@@ -105,7 +105,8 @@ export const MicrophoneButton: React.FunctionComponent<MicrophoneButtonProps> =
105
105
  <Button
106
106
  variant="plain"
107
107
  className={`pf-chatbot__button--microphone ${isListening ? 'pf-chatbot__button--microphone--active' : ''} ${isCompact ? 'pf-m-compact' : ''} ${className ?? ''}`}
108
- aria-label={props['aria-label'] || 'Microphone button'}
108
+ aria-label={props['aria-label'] || (isListening ? 'Stop listening' : 'Use microphone')}
109
+ aria-pressed={isListening}
109
110
  onClick={isListening ? stopListening : startListening}
110
111
  icon={
111
112
  <Icon iconSize={isCompact ? 'lg' : 'xl'} isInline>
@@ -12,23 +12,23 @@ const renderSend = (props?: { [key: string]: string | boolean | Omit<TooltipProp
12
12
  describe('Send button', () => {
13
13
  it('should render button correctly', () => {
14
14
  renderSend();
15
- expect(screen.getByRole('button', { name: 'Send button' })).toBeTruthy();
15
+ expect(screen.getByRole('button', { name: 'Send' })).toBeTruthy();
16
16
  });
17
17
  it('should handle onClick correctly', async () => {
18
18
  const spy = jest.fn();
19
19
  render(<SendButton onClick={spy} />);
20
- await userEvent.click(screen.getByRole('button', { name: 'Send button' }));
20
+ await userEvent.click(screen.getByRole('button', { name: 'Send' }));
21
21
  expect(screen.getByRole('tooltip', { name: 'Send' })).toBeTruthy();
22
22
  expect(spy).toHaveBeenCalledTimes(1);
23
23
  });
24
24
  it('should handle custom tooltip correctly', async () => {
25
25
  render(<SendButton onClick={jest.fn} tooltipContent="Test" />);
26
- await userEvent.click(screen.getByRole('button', { name: 'Send button' }));
26
+ await userEvent.click(screen.getByRole('button', { name: 'Send' }));
27
27
  expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
28
28
  });
29
29
  it('should handle className prop', () => {
30
30
  renderSend({ className: 'test' });
31
- expect(screen.getByRole('button', { name: 'Send button' })).toHaveClass('test');
31
+ expect(screen.getByRole('button', { name: 'Send' })).toHaveClass('test');
32
32
  });
33
33
 
34
34
  it('should handle spread props, including aria-label', () => {
@@ -37,7 +37,7 @@ describe('Send button', () => {
37
37
  });
38
38
  it('should handle tooltipProps prop', async () => {
39
39
  renderSend({ tooltipProps: { id: 'test' } });
40
- await userEvent.click(screen.getByRole('button', { name: 'Send button' }));
40
+ await userEvent.click(screen.getByRole('button', { name: 'Send' }));
41
41
  expect(screen.getByRole('tooltip', { name: 'Send' })).toHaveAttribute('id', 'test');
42
42
  });
43
43
  it('should handle isCompact', () => {
@@ -43,7 +43,7 @@ export const SendButton: React.FunctionComponent<SendButtonProps> = ({
43
43
  <Button
44
44
  variant="plain"
45
45
  className={`pf-chatbot__button--send ${isCompact ? 'pf-m-compact' : ''} ${className ?? ''}`}
46
- aria-label={props['aria-label'] || 'Send button'}
46
+ aria-label={props['aria-label'] || 'Send'}
47
47
  onClick={onClick}
48
48
  icon={
49
49
  <Icon iconSize={isCompact ? 'lg' : 'xl'} isInline>
@@ -12,23 +12,23 @@ const renderStop = (props?: { [key: string]: string | boolean | Omit<TooltipProp
12
12
  describe('Stop button', () => {
13
13
  it('should render button correctly', () => {
14
14
  renderStop();
15
- expect(screen.getByRole('button', { name: 'Stop button' })).toBeTruthy();
15
+ expect(screen.getByRole('button', { name: 'Stop' })).toBeTruthy();
16
16
  });
17
17
  it('should handle onClick correctly', async () => {
18
18
  const spy = jest.fn();
19
19
  render(<StopButton onClick={spy} />);
20
- await userEvent.click(screen.getByRole('button', { name: 'Stop button' }));
20
+ await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
21
21
  expect(screen.getByRole('tooltip', { name: 'Stop' })).toBeTruthy();
22
22
  expect(spy).toHaveBeenCalledTimes(1);
23
23
  });
24
24
  it('should handle custom tooltip correctly', async () => {
25
25
  render(<StopButton onClick={jest.fn} tooltipContent="Test" />);
26
- await userEvent.click(screen.getByRole('button', { name: 'Stop button' }));
26
+ await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
27
27
  expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
28
28
  });
29
29
  it('should handle className prop', () => {
30
30
  renderStop({ className: 'test' });
31
- expect(screen.getByRole('button', { name: 'Stop button' })).toHaveClass('test');
31
+ expect(screen.getByRole('button', { name: 'Stop' })).toHaveClass('test');
32
32
  });
33
33
  it('should handle spread props, including aria-label', () => {
34
34
  renderStop({ 'aria-label': 'test' });
@@ -36,7 +36,7 @@ describe('Stop button', () => {
36
36
  });
37
37
  it('should handle tooltipProps prop', async () => {
38
38
  renderStop({ tooltipProps: { id: 'test' } });
39
- await userEvent.click(screen.getByRole('button', { name: 'Stop button' }));
39
+ await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
40
40
  expect(screen.getByRole('tooltip', { name: 'Stop' })).toHaveAttribute('id', 'test');
41
41
  });
42
42
  it('should handle isCompact', () => {
@@ -41,7 +41,7 @@ export const StopButton: React.FunctionComponent<StopButtonProps> = ({
41
41
  <Button
42
42
  className={`pf-chatbot__button--stop ${isCompact ? 'pf-m-compact' : ''} ${className ?? ''}`}
43
43
  variant="link"
44
- aria-label={props['aria-label'] || 'Stop button'}
44
+ aria-label={props['aria-label'] || 'Stop'}
45
45
  onClick={onClick}
46
46
  icon={
47
47
  <Icon iconSize={isCompact ? 'lg' : 'xl'} isInline>
@@ -7,20 +7,20 @@ import userEvent from '@testing-library/user-event';
7
7
  describe('JumpButton', () => {
8
8
  it('should render top button correctly', () => {
9
9
  render(<JumpButton position="top" onClick={jest.fn()} />);
10
- expect(screen.getByRole('button', { name: /Jump top button/i })).toBeTruthy();
10
+ expect(screen.getByRole('button', { name: /Jump top/i })).toBeTruthy();
11
11
  });
12
12
  it('should render bottom button correctly', () => {
13
13
  render(<JumpButton position="bottom" onClick={jest.fn()} />);
14
- expect(screen.getByRole('button', { name: /Jump bottom button/i })).toBeTruthy();
14
+ expect(screen.getByRole('button', { name: /Jump bottom/i })).toBeTruthy();
15
15
  });
16
16
  it('should call onClick appropriately', async () => {
17
17
  const spy = jest.fn();
18
18
  render(<JumpButton position="bottom" onClick={spy} />);
19
- await userEvent.click(screen.getByRole('button', { name: /Jump bottom button/i }));
19
+ await userEvent.click(screen.getByRole('button', { name: /Jump bottom/i }));
20
20
  expect(spy).toHaveBeenCalledTimes(1);
21
21
  });
22
22
  it('should be hidden if isHidden prop is used', async () => {
23
23
  render(<JumpButton position="bottom" onClick={jest.fn()} isHidden />);
24
- expect(screen.queryByRole('button', { name: /Jump bottom button/i })).toBeFalsy();
24
+ expect(screen.queryByRole('button', { name: /Jump bottom/i })).toBeFalsy();
25
25
  });
26
26
  });
@@ -24,7 +24,7 @@ const JumpButton: React.FunctionComponent<JumpButtonProps> = ({ position, isHidd
24
24
  <Button
25
25
  variant="plain"
26
26
  className={`pf-chatbot__jump pf-chatbot__jump--${position}`}
27
- aria-label={`Jump ${position} button`}
27
+ aria-label={`Jump ${position}`}
28
28
  onClick={onClick}
29
29
  >
30
30
  <Icon iconSize="lg" isInline>
@@ -40,7 +40,7 @@ describe('MessageBox', () => {
40
40
  region.dispatchEvent(new Event('scroll'));
41
41
 
42
42
  await waitFor(() => {
43
- userEvent.click(screen.getByRole('button', { name: /Jump bottom button/i }));
43
+ userEvent.click(screen.getByRole('button', { name: /Jump bottom/i }));
44
44
  expect(spy).toHaveBeenCalled();
45
45
  });
46
46
  });
@@ -63,7 +63,7 @@ describe('MessageBox', () => {
63
63
  region.dispatchEvent(new Event('scroll'));
64
64
 
65
65
  await waitFor(() => {
66
- userEvent.click(screen.getByRole('button', { name: /Jump top button/i }));
66
+ userEvent.click(screen.getByRole('button', { name: /Jump top/i }));
67
67
  expect(spy).toHaveBeenCalled();
68
68
  });
69
69
  });
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
- import { Button, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
2
+ import { Button, ButtonProps, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
3
3
 
4
- export interface ResponseActionButtonProps {
4
+ export interface ResponseActionButtonProps extends ButtonProps {
5
5
  /** Aria-label for the button. Defaults to the value of the tooltipContent if none provided */
6
6
  ariaLabel?: string;
7
7
  /** Aria-label for the button, shown when the button is clicked. Defaults to the value of ariaLabel or tooltipContent if not provided. */
@@ -41,6 +41,14 @@ const CUSTOM_ACTIONS = [
41
41
  }
42
42
  ];
43
43
 
44
+ const ALL_ACTIONS_DATA_TEST = [
45
+ { type: 'positive', label: 'Good response', dataTestId: 'positive' },
46
+ { type: 'negative', label: 'Bad response', dataTestId: 'negative' },
47
+ { type: 'copy', label: 'Copy', dataTestId: 'copy' },
48
+ { type: 'share', label: 'Share', dataTestId: 'share' },
49
+ { type: 'listen', label: 'Listen', dataTestId: 'listen' }
50
+ ];
51
+
44
52
  describe('ResponseActions', () => {
45
53
  afterEach(() => {
46
54
  jest.clearAllMocks();
@@ -181,6 +189,13 @@ describe('ResponseActions', () => {
181
189
  });
182
190
  });
183
191
 
192
+ it('should be able to add custom attributes to buttons', () => {
193
+ ALL_ACTIONS_DATA_TEST.forEach(({ type, dataTestId }) => {
194
+ render(<ResponseActions actions={{ [type]: { onClick: jest.fn(), 'data-testid': dataTestId } }} />);
195
+ expect(screen.getByTestId(dataTestId)).toBeTruthy();
196
+ });
197
+ });
198
+
184
199
  it('should be able to add custom actions', () => {
185
200
  CUSTOM_ACTIONS.forEach((action) => {
186
201
  const key = Object.keys(action)[0];
@@ -192,12 +207,14 @@ describe('ResponseActions', () => {
192
207
  onClick: action[key].onClick,
193
208
  // doing this just because it's easier to test without a regex for the button name
194
209
  ariaLabel: action[key].ariaLabel.toLowerCase(),
195
- icon: action[key].icon
210
+ icon: action[key].icon,
211
+ 'data-testid': action[key]
196
212
  }
197
213
  }}
198
214
  />
199
215
  );
200
216
  expect(screen.getByRole('button', { name: key })).toBeTruthy();
217
+ expect(screen.getByTestId(action[key])).toBeTruthy();
201
218
  });
202
219
  });
203
220
  });
@@ -36,9 +36,12 @@ export interface ActionProps extends Omit<ButtonProps, 'ref'> {
36
36
  'aria-controls'?: string;
37
37
  }
38
38
 
39
+ type ExtendedActionProps = ActionProps & {
40
+ [key: string]: any;
41
+ };
39
42
  export interface ResponseActionProps {
40
43
  /** Props for message actions, such as feedback (positive or negative), copy button, share, and listen */
41
- actions: Record<string, ActionProps | undefined> & {
44
+ actions: Record<string, ExtendedActionProps | undefined> & {
42
45
  positive?: ActionProps;
43
46
  negative?: ActionProps;
44
47
  copy?: ActionProps;
@@ -78,6 +81,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
78
81
  <div ref={responseActions} className="pf-chatbot__response-actions">
79
82
  {positive && (
80
83
  <ResponseActionButton
84
+ {...positive}
81
85
  ariaLabel={positive.ariaLabel ?? 'Good response'}
82
86
  clickedAriaLabel={positive.ariaLabel ?? 'Response recorded'}
83
87
  onClick={(e) => handleClick(e, 'positive', positive.onClick)}
@@ -95,6 +99,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
95
99
  )}
96
100
  {negative && (
97
101
  <ResponseActionButton
102
+ {...negative}
98
103
  ariaLabel={negative.ariaLabel ?? 'Bad response'}
99
104
  clickedAriaLabel={negative.ariaLabel ?? 'Response recorded'}
100
105
  onClick={(e) => handleClick(e, 'negative', negative.onClick)}
@@ -112,6 +117,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
112
117
  )}
113
118
  {copy && (
114
119
  <ResponseActionButton
120
+ {...copy}
115
121
  ariaLabel={copy.ariaLabel ?? 'Copy'}
116
122
  clickedAriaLabel={copy.ariaLabel ?? 'Copied'}
117
123
  onClick={(e) => handleClick(e, 'copy', copy.onClick)}
@@ -129,6 +135,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
129
135
  )}
130
136
  {share && (
131
137
  <ResponseActionButton
138
+ {...share}
132
139
  ariaLabel={share.ariaLabel ?? 'Share'}
133
140
  clickedAriaLabel={share.ariaLabel ?? 'Shared'}
134
141
  onClick={(e) => handleClick(e, 'share', share.onClick)}
@@ -146,6 +153,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
146
153
  )}
147
154
  {listen && (
148
155
  <ResponseActionButton
156
+ {...listen}
149
157
  ariaLabel={listen.ariaLabel ?? 'Listen'}
150
158
  clickedAriaLabel={listen.ariaLabel ?? 'Listening'}
151
159
  onClick={(e) => handleClick(e, 'listen', listen.onClick)}
@@ -163,6 +171,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
163
171
  )}
164
172
  {Object.keys(additionalActions).map((action) => (
165
173
  <ResponseActionButton
174
+ {...additionalActions[action]}
166
175
  key={action}
167
176
  ariaLabel={additionalActions[action]?.ariaLabel}
168
177
  clickedAriaLabel={additionalActions[action]?.clickedAriaLabel}