Skip to content

Commit c832b30

Browse files
authored
chore(compass-assistant): fix assistant tests (#7228)
* chore(compass-assistant): fix assistant tests * chore: minimize side effects from scroll to override * chore: move scrollTo to jsdom-extra-mocks-register
1 parent c1c698c commit c832b30

File tree

5 files changed

+122
-50
lines changed

5 files changed

+122
-50
lines changed

configs/mocha-config-compass/register/jsdom-extra-mocks-register.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,6 @@ globalThis.CustomEvent = window.CustomEvent;
5151
globalThis.Event = window.Event;
5252
globalThis.Blob = window.Blob;
5353
globalThis.File = window.File;
54+
55+
// jsdom doesn't support scrollTo on the Element, so make it a no-op
56+
globalThis.Element.prototype.scrollTo = () => {};

configs/webpack-config-compass/src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,23 @@ export function createElectronRendererConfig(
279279
overlay:
280280
process.env.DISABLE_DEVSERVER_OVERLAY === 'true'
281281
? false
282-
: { warnings: false, errors: true, runtimeErrors: true },
282+
: {
283+
runtimeErrors: (error) => {
284+
// ResizeObserver errors are harmless and expected in some cases.
285+
// We currently get them when opening the Assistant drawer.
286+
if (
287+
error?.message ===
288+
'ResizeObserver loop completed with undelivered notifications.'
289+
) {
290+
// eslint-disable-next-line no-console
291+
console.warn(error);
292+
return false;
293+
}
294+
return true;
295+
},
296+
errors: true,
297+
warnings: false,
298+
},
283299
},
284300
https: false,
285301
hot: opts.hot,

packages/compass-assistant/src/assistant-chat.spec.tsx

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import React from 'react';
2-
import { render, screen, userEvent } from '@mongodb-js/testing-library-compass';
2+
import {
3+
render,
4+
screen,
5+
userEvent,
6+
waitFor,
7+
} from '@mongodb-js/testing-library-compass';
38
import { AssistantChat } from './assistant-chat';
49
import { expect } from 'chai';
510
import { createMockChat } from '../test/utils';
611
import type { AssistantMessage } from './compass-assistant-provider';
712

8-
// TODO: some internal logic in lg-chat breaks all these tests, re-enable the tests
9-
describe.skip('AssistantChat', function () {
13+
describe('AssistantChat', function () {
14+
let originalScrollTo: typeof Element.prototype.scrollTo;
15+
// Mock scrollTo method for DOM elements to prevent test failures
16+
before(function () {
17+
originalScrollTo = Element.prototype.scrollTo.bind(Element.prototype);
18+
Element.prototype.scrollTo = () => {};
19+
});
20+
after(function () {
21+
Element.prototype.scrollTo = originalScrollTo;
22+
});
23+
1024
const mockMessages: AssistantMessage[] = [
1125
{
1226
id: 'user',
@@ -36,8 +50,10 @@ describe.skip('AssistantChat', function () {
3650
it('renders input field and send button', function () {
3751
renderWithChat([]);
3852

39-
const inputField = screen.getByTestId('assistant-chat-input');
40-
const sendButton = screen.getByTestId('assistant-chat-send-button');
53+
const inputField = screen.getByPlaceholderText(
54+
'Ask MongoDB Assistant a question'
55+
);
56+
const sendButton = screen.getByLabelText('Send message');
4157

4258
expect(inputField).to.exist;
4359
expect(sendButton).to.exist;
@@ -47,9 +63,9 @@ describe.skip('AssistantChat', function () {
4763
renderWithChat([]);
4864

4965
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
50-
const inputField = screen.getByTestId(
51-
'assistant-chat-input'
52-
) as HTMLInputElement;
66+
const inputField = screen.getByPlaceholderText(
67+
'Ask MongoDB Assistant a question'
68+
) as HTMLTextAreaElement;
5369

5470
userEvent.type(inputField, 'What is MongoDB?');
5571

@@ -60,58 +76,67 @@ describe.skip('AssistantChat', function () {
6076
renderWithChat([]);
6177

6278
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
63-
const sendButton = screen.getByTestId(
64-
'assistant-chat-send-button'
79+
const sendButton = screen.getByLabelText(
80+
'Send message'
6581
) as HTMLButtonElement;
6682

67-
expect(sendButton.disabled).to.be.true;
83+
expect(sendButton.getAttribute('aria-disabled')).to.equal('true');
6884
});
6985

7086
it('send button is enabled when input has text', function () {
7187
renderWithChat([]);
7288

73-
const inputField = screen.getByTestId('assistant-chat-input');
89+
const inputField = screen.getByPlaceholderText(
90+
'Ask MongoDB Assistant a question'
91+
);
7492
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
75-
const sendButton = screen.getByTestId(
76-
'assistant-chat-send-button'
93+
const sendButton = screen.getByLabelText(
94+
'Send message'
7795
) as HTMLButtonElement;
7896

7997
userEvent.type(inputField, 'What is MongoDB?');
8098

8199
expect(sendButton.disabled).to.be.false;
82100
});
83101

84-
it('send button is disabled for whitespace-only input', function () {
102+
// Not currently supported by the LeafyGreen Input Bar
103+
it.skip('send button is disabled for whitespace-only input', async function () {
85104
renderWithChat([]);
86105

87-
const inputField = screen.getByTestId('assistant-chat-input');
106+
const inputField = screen.getByPlaceholderText(
107+
'Ask MongoDB Assistant a question'
108+
);
88109
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
89-
const sendButton = screen.getByTestId(
90-
'assistant-chat-send-button'
110+
const sendButton = screen.getByLabelText(
111+
'Send message'
91112
) as HTMLButtonElement;
92113

93114
userEvent.type(inputField, ' ');
94115

95-
expect(sendButton.disabled).to.be.true;
116+
await waitFor(() => {
117+
expect(sendButton.getAttribute('aria-disabled')).to.equal('true');
118+
});
96119
});
97120

98121
it('displays messages in the chat feed', function () {
99122
renderWithChat(mockMessages);
100123

101124
expect(screen.getByTestId('assistant-message-user')).to.exist;
102125
expect(screen.getByTestId('assistant-message-assistant')).to.exist;
103-
expect(screen.getByTestId('assistant-message-user')).to.have.text(
126+
expect(screen.getByTestId('assistant-message-user')).to.contain.text(
104127
'Hello, MongoDB Assistant!'
105128
);
106-
expect(screen.getByTestId('assistant-message-assistant')).to.have.text(
129+
expect(screen.getByTestId('assistant-message-assistant')).to.contain.text(
107130
'Hello! How can I help you with MongoDB today?'
108131
);
109132
});
110133

111134
it('calls sendMessage when form is submitted', function () {
112135
const { chat } = renderWithChat([]);
113-
const inputField = screen.getByTestId('assistant-chat-input');
114-
const sendButton = screen.getByTestId('assistant-chat-send-button');
136+
const inputField = screen.getByPlaceholderText(
137+
'Ask MongoDB Assistant a question'
138+
);
139+
const sendButton = screen.getByLabelText('Send message');
115140

116141
userEvent.type(inputField, 'What is aggregation?');
117142
userEvent.click(sendButton);
@@ -124,24 +149,26 @@ describe.skip('AssistantChat', function () {
124149
renderWithChat([]);
125150

126151
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
127-
const inputField = screen.getByTestId(
128-
'assistant-chat-input'
129-
) as HTMLInputElement;
152+
const inputField = screen.getByPlaceholderText(
153+
'Ask MongoDB Assistant a question'
154+
) as HTMLTextAreaElement;
130155

131156
userEvent.type(inputField, 'Test message');
132157
expect(inputField.value).to.equal('Test message');
133158

134-
userEvent.click(screen.getByTestId('assistant-chat-send-button'));
159+
userEvent.click(screen.getByLabelText('Send message'));
135160
expect(inputField.value).to.equal('');
136161
});
137162

138163
it('trims whitespace from input before sending', function () {
139164
const { chat } = renderWithChat([]);
140165

141-
const inputField = screen.getByTestId('assistant-chat-input');
166+
const inputField = screen.getByPlaceholderText(
167+
'Ask MongoDB Assistant a question'
168+
);
142169

143170
userEvent.type(inputField, ' What is sharding? ');
144-
userEvent.click(screen.getByTestId('assistant-chat-send-button'));
171+
userEvent.click(screen.getByLabelText('Send message'));
145172

146173
expect(chat.sendMessage.calledWith({ text: 'What is sharding?' })).to.be
147174
.true;
@@ -150,8 +177,10 @@ describe.skip('AssistantChat', function () {
150177
it('does not call sendMessage when input is empty or whitespace-only', function () {
151178
const { chat } = renderWithChat([]);
152179

153-
const inputField = screen.getByTestId('assistant-chat-input');
154-
const chatForm = screen.getByTestId('assistant-chat-form');
180+
const inputField = screen.getByPlaceholderText(
181+
'Ask MongoDB Assistant a question'
182+
);
183+
const chatForm = screen.getByTestId('assistant-chat-input');
155184

156185
// Test empty input
157186
userEvent.click(chatForm);
@@ -169,16 +198,12 @@ describe.skip('AssistantChat', function () {
169198
const userMessage = screen.getByTestId('assistant-message-user');
170199
const assistantMessage = screen.getByTestId('assistant-message-assistant');
171200

172-
// User messages should have different background color than assistant messages
201+
// User messages should have different class names than assistant messages
173202
expect(userMessage).to.exist;
174203
expect(assistantMessage).to.exist;
175204

176-
const userStyle = window.getComputedStyle(userMessage);
177-
const assistantStyle = window.getComputedStyle(assistantMessage);
178-
179-
expect(userStyle.backgroundColor).to.not.equal(
180-
assistantStyle.backgroundColor
181-
);
205+
// Check that they have different class names (indicating different styling)
206+
expect(userMessage.className).to.not.equal(assistantMessage.className);
182207
});
183208

184209
it('handles messages with multiple text parts', function () {

packages/compass-assistant/src/assistant-chat.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
LgChatMessage,
99
LgChatMessageFeed,
1010
LgChatInputBar,
11+
spacing,
12+
css,
1113
} from '@mongodb-js/compass-components';
1214

1315
const { ChatWindow } = LgChatChatWindow;
@@ -20,6 +22,20 @@ interface AssistantChatProps {
2022
chat: Chat<AssistantMessage>;
2123
}
2224

25+
// TODO(COMPASS-9751): These are temporary patches to make the Assistant chat take the entire
26+
// width and height of the drawer since Leafygreen doesn't support this yet.
27+
const assistantChatFixesStyles = css({
28+
// Negative margin to patch the padding of the drawer.
29+
margin: -spacing[400],
30+
'> div, > div > div, > div > div > div, > div > div > div > div': {
31+
height: '100%',
32+
},
33+
});
34+
const messageFeedFixesStyles = css({ height: '100%' });
35+
const chatWindowFixesStyles = css({
36+
height: '100%',
37+
});
38+
2339
export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
2440
chat,
2541
}) => {
@@ -42,19 +58,30 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
4258

4359
const handleMessageSend = useCallback(
4460
(messageBody: string) => {
45-
void sendMessage({ text: messageBody });
61+
const trimmedMessageBody = messageBody.trim();
62+
if (trimmedMessageBody) {
63+
void sendMessage({ text: trimmedMessageBody });
64+
}
4665
},
4766
[sendMessage]
4867
);
4968

5069
return (
51-
<div data-testid="assistant-chat" style={{ height: '100%', width: '100%' }}>
70+
<div
71+
data-testid="assistant-chat"
72+
className={assistantChatFixesStyles}
73+
style={{ height: '100%', width: '100%' }}
74+
>
5275
<LeafyGreenChatProvider variant={Variant.Compact}>
53-
<ChatWindow title="MongoDB Assistant">
54-
<MessageFeed data-testid="assistant-chat-messages">
76+
<ChatWindow title="MongoDB Assistant" className={chatWindowFixesStyles}>
77+
<MessageFeed
78+
data-testid="assistant-chat-messages"
79+
className={messageFeedFixesStyles}
80+
>
5581
{lgMessages.map((messageFields) => (
5682
<Message
5783
key={messageFields.id}
84+
sourceType="markdown"
5885
{...messageFields}
5986
data-testid={`assistant-message-${messageFields.id}`}
6087
/>

packages/compass-assistant/src/compass-assistant-provider.spec.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ describe('AssistantProvider', function () {
8484
);
8585
});
8686

87-
// TODO: some internal logic in lg-chat breaks all these tests, re-enable the tests
88-
describe.skip('with existing chat instance', function () {
87+
describe('with existing chat instance', function () {
8988
before(function () {
9089
// TODO(COMPASS-9618): skip in electron runtime for now, drawer has issues rendering
9190
if ((process as any).type === 'renderer') {
@@ -118,7 +117,7 @@ describe('AssistantProvider', function () {
118117
);
119118

120119
expect(screen.getByTestId('assistant-message-2')).to.exist;
121-
expect(screen.getByTestId('assistant-message-2')).to.have.text(
120+
expect(screen.getByTestId('assistant-message-2')).to.contain.text(
122121
'Test assistant message'
123122
);
124123
});
@@ -138,8 +137,10 @@ describe('AssistantProvider', function () {
138137

139138
await renderOpenAssistantDrawer(mockChat);
140139

141-
const input = screen.getByTestId('assistant-chat-input');
142-
const sendButton = screen.getByTestId('assistant-chat-send-button');
140+
const input = screen.getByPlaceholderText(
141+
'Ask MongoDB Assistant a question'
142+
);
143+
const sendButton = screen.getByLabelText('Send message');
143144

144145
userEvent.type(input, 'Hello assistant');
145146
userEvent.click(sendButton);
@@ -176,10 +177,10 @@ describe('AssistantProvider', function () {
176177
await renderOpenAssistantDrawer(mockChat);
177178

178179
userEvent.type(
179-
screen.getByTestId('assistant-chat-input'),
180+
screen.getByPlaceholderText('Ask MongoDB Assistant a question'),
180181
'Hello assistant!'
181182
);
182-
userEvent.click(screen.getByTestId('assistant-chat-send-button'));
183+
userEvent.click(screen.getByLabelText('Send message'));
183184

184185
expect(sendMessageSpy.calledOnce).to.be.true;
185186
expect(sendMessageSpy.firstCall.args[0]).to.deep.include({

0 commit comments

Comments
 (0)