Skip to content

Commit dc92e06

Browse files
lerouxbCopilot
andauthored
chore: fix assistant flake (#7447)
* use the same clipboard pattern we use elsewhere * clickVisible all the things while at it * Update packages/compass-e2e-tests/tests/assistant.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * wait for the correct text * account for the fact that text streams --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent a771ad9 commit dc92e06

File tree

1 file changed

+83
-53
lines changed

1 file changed

+83
-53
lines changed

packages/compass-e2e-tests/tests/assistant.test.ts

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from 'chai';
22

3+
import clipboard from 'clipboardy';
34
import type { CompassBrowser } from '../helpers/compass-browser';
45
import { startTelemetryServer } from '../helpers/telemetry';
56
import type { Telemetry } from '../helpers/telemetry';
@@ -17,6 +18,13 @@ import { startMockAssistantServer } from '../helpers/assistant-service';
1718
import type { MockAssistantResponse } from '../helpers/assistant-service';
1819
import { isTestingWeb } from '../helpers/test-runner-context';
1920

21+
import { context } from '../helpers/test-runner-context';
22+
23+
type Message = {
24+
text: string;
25+
role: 'assistant' | 'user';
26+
};
27+
2028
describe('MongoDB Assistant', function () {
2129
let compass: Compass;
2230
let browser: CompassBrowser;
@@ -68,8 +76,7 @@ describe('MongoDB Assistant', function () {
6876
const chatInput = browser.$(Selectors.AssistantChatInputTextArea);
6977
await chatInput.waitForDisplayed();
7078
await chatInput.setValue(text);
71-
const submitButton = browser.$(Selectors.AssistantChatSubmitButton);
72-
await submitButton.click();
79+
await browser.clickVisible(Selectors.AssistantChatSubmitButton);
7380

7481
switch (expectedResult) {
7582
case 'success':
@@ -179,13 +186,6 @@ describe('MongoDB Assistant', function () {
179186
});
180187

181188
describe('drawer visibility', function () {
182-
before(function () {
183-
skipForWeb(
184-
this,
185-
'E2E testing for assistant drawer visibility on compass-web is not yet implemented'
186-
);
187-
});
188-
189189
it('shows the assistant drawer button when AI features are enabled', async function () {
190190
await setAIFeatures(true);
191191

@@ -195,6 +195,12 @@ describe('MongoDB Assistant', function () {
195195
});
196196

197197
it('does not show the assistant drawer button when AI features are disabled', async function () {
198+
// we cannot opt back out on web because it is stored server-side
199+
skipForWeb(
200+
this,
201+
'E2E testing for assistant drawer visibility on compass-web is not yet implemented'
202+
);
203+
198204
await setAIFeatures(false);
199205

200206
const drawerButton = browser.$(Selectors.AssistantDrawerButton);
@@ -219,6 +225,7 @@ describe('MongoDB Assistant', function () {
219225
});
220226

221227
describe('before opt-in', function () {
228+
// we cannot opt back out on web because it is stored server-side
222229
before(async function () {
223230
skipForWeb(
224231
this,
@@ -259,9 +266,7 @@ describe('MongoDB Assistant', function () {
259266
await optInModal.waitForDisplayed();
260267
expect(await optInModal.isDisplayed()).to.be.true;
261268

262-
const declineLink = browser.$(Selectors.AIOptInModalDeclineLink);
263-
await declineLink.waitForDisplayed();
264-
await declineLink.click();
269+
await browser.clickVisible(Selectors.AIOptInModalDeclineLink);
265270

266271
await optInModal.waitForDisplayed({ reverse: true });
267272

@@ -275,9 +280,7 @@ describe('MongoDB Assistant', function () {
275280
await optInModal.waitForDisplayed();
276281
expect(await optInModal.isDisplayed()).to.be.true;
277282

278-
const declineLink = browser.$(Selectors.AIOptInModalDeclineLink);
279-
await declineLink.waitForDisplayed();
280-
await declineLink.click();
283+
await browser.clickVisible(Selectors.AIOptInModalDeclineLink);
281284

282285
await optInModal.waitForDisplayed({ reverse: true });
283286

@@ -288,6 +291,7 @@ describe('MongoDB Assistant', function () {
288291

289292
describe('opting in', function () {
290293
before(async function () {
294+
// we cannot opt back out on web because it is stored server-side
291295
skipForWeb(
292296
this,
293297
'E2E testing for opt-in on compass-web is not yet implemented'
@@ -303,16 +307,14 @@ describe('MongoDB Assistant', function () {
303307
await optInModal.waitForDisplayed();
304308
expect(await optInModal.isDisplayed()).to.be.true;
305309

306-
const acceptButton = browser.$(Selectors.AIOptInModalAcceptButton);
307-
await acceptButton.waitForClickable();
308-
await acceptButton.click();
310+
await browser.clickVisible(Selectors.AIOptInModalAcceptButton);
309311

310312
await optInModal.waitForDisplayed({ reverse: true });
311313

312314
const chatInput = browser.$(Selectors.AssistantChatInputTextArea);
313315
expect(await chatInput.getValue()).to.equal('');
314316

315-
expect(await getDisplayedMessages(browser)).to.deep.equal([
317+
await waitForMessages(browser, [
316318
{ text: testMessage, role: 'user' },
317319
{ text: testResponse, role: 'assistant' },
318320
]);
@@ -335,7 +337,7 @@ describe('MongoDB Assistant', function () {
335337
await sendMessage(testMessage);
336338
await sendMessage(testMessage);
337339

338-
expect(await getDisplayedMessages(browser)).to.deep.equal([
340+
await waitForMessages(browser, [
339341
{ text: testMessage, role: 'user' },
340342
{ text: testResponse, role: 'assistant' },
341343
{ text: testMessage, role: 'user' },
@@ -344,7 +346,7 @@ describe('MongoDB Assistant', function () {
344346

345347
await clearChat(browser);
346348

347-
expect(await getDisplayedMessages(browser)).to.deep.equal([]);
349+
await waitForMessages(browser, []);
348350
});
349351
});
350352

@@ -363,7 +365,7 @@ describe('MongoDB Assistant', function () {
363365
},
364366
});
365367

366-
expect(await getDisplayedMessages(browser)).to.deep.equal([
368+
await waitForMessages(browser, [
367369
{ text: testMessage, role: 'user' },
368370
{ text: testResponse, role: 'assistant' },
369371
{ text: 'This is a different message', role: 'user' },
@@ -372,28 +374,37 @@ describe('MongoDB Assistant', function () {
372374
});
373375

374376
it('can copy assistant message to clipboard', async function () {
375-
skipForWeb(
376-
this,
377-
'Accessing the clipboard text is not available in compass-web so this test is not meaningful'
378-
);
377+
if (context.disableClipboardUsage) {
378+
this.skip();
379+
}
380+
379381
await sendMessage(testMessage);
380382

383+
// sanity check
384+
await browser.waitUntil(async () => {
385+
const messages = await getDisplayedMessages(browser);
386+
return messages[1].text === testResponse;
387+
});
388+
381389
const messageElements = await browser
382390
.$$(Selectors.AssistantChatMessage)
383391
.getElements();
384392

385393
const assistantMessage = messageElements[1];
386394

387-
const copyButton = assistantMessage.$('[aria-label="Copy message"]');
388-
await copyButton.waitForDisplayed();
389-
await copyButton.click();
395+
await browser.clickVisible(
396+
assistantMessage.$('[aria-label="Copy message"]')
397+
);
390398

391399
await browser.waitUntil(async () => {
392-
return (
393-
(await browser.execute(() => {
394-
return navigator.clipboard.readText();
395-
})) === testResponse
396-
);
400+
const text = await clipboard.read();
401+
402+
const isValid = text === testResponse;
403+
if (!isValid) {
404+
console.log(text);
405+
}
406+
407+
return isValid;
397408
});
398409
});
399410

@@ -443,15 +454,9 @@ describe('MongoDB Assistant', function () {
443454
it('opens assistant with explain plan prompt when clicking "Interpret for me"', async function () {
444455
await useExplainPlanEntryPoint(browser);
445456

446-
const confirmButton = browser.$('button*=Confirm');
447-
await confirmButton.waitForDisplayed();
448-
await confirmButton.click();
457+
await browser.clickVisible('button*=Confirm');
449458

450-
await browser.waitUntil(async () => {
451-
return (await getDisplayedMessages(browser)).length === 2;
452-
});
453-
454-
expect(await getDisplayedMessages(browser)).deep.equal([
459+
await waitForMessages(browser, [
455460
{
456461
text: 'Interpret this explain plan output for me.',
457462
role: 'user',
@@ -472,9 +477,7 @@ describe('MongoDB Assistant', function () {
472477
);
473478

474479
// Click Cancel button
475-
const cancelButton = browser.$('button*=Cancel');
476-
await cancelButton.waitForDisplayed();
477-
await cancelButton.click();
480+
await browser.clickVisible('button*=Cancel');
478481

479482
// Wait a bit to ensure no request is sent
480483
await browser.pause(300);
@@ -485,6 +488,7 @@ describe('MongoDB Assistant', function () {
485488
expect(await chatMessages.getText()).to.include(
486489
'Please confirm your request'
487490
);
491+
488492
expect(await chatMessages.getText()).to.include('Request cancelled');
489493

490494
// Verify no assistant request was made
@@ -509,8 +513,7 @@ describe('MongoDB Assistant', function () {
509513
browser.$(Selectors.ConnectionToastErrorDebugButton)
510514
);
511515

512-
const messages = await getDisplayedMessages(browser);
513-
expect(messages).deep.equal([
516+
await waitForMessages(browser, [
514517
{
515518
text: 'Diagnose why my Compass connection is failing and help me debug it.',
516519
role: 'user',
@@ -535,23 +538,24 @@ async function openAssistantDrawer(browser: CompassBrowser) {
535538
async function clearChat(browser: CompassBrowser) {
536539
const clearChatButton = browser.$(Selectors.AssistantClearChatButton);
537540
if (await clearChatButton.isDisplayed()) {
538-
await clearChatButton.click();
539-
const confirmButton = browser.$(
541+
await browser.clickVisible(clearChatButton);
542+
await browser.clickVisible(
540543
Selectors.AssistantConfirmClearChatModalConfirmButton
541544
);
542-
await confirmButton.waitForClickable();
543-
await confirmButton.click();
544545
}
545546
}
546547

547-
async function getDisplayedMessages(browser: CompassBrowser) {
548+
async function getDisplayedMessages(
549+
browser: CompassBrowser
550+
): Promise<Message[]> {
548551
await browser.$(Selectors.AssistantChatMessages).waitForDisplayed();
549552

550553
const messageElements = await browser
551554
.$$(Selectors.AssistantChatMessage)
552555
.getElements();
553556

554-
const displayedMessages = [];
557+
const displayedMessages: Message[] = [];
558+
555559
for (const messageElement of messageElements) {
556560
const textElements = await messageElement.$$('p').getElements();
557561
const isAssistantMessage =
@@ -572,6 +576,32 @@ async function getDisplayedMessages(browser: CompassBrowser) {
572576
return displayedMessages;
573577
}
574578

579+
async function waitForMessages(
580+
browser: CompassBrowser,
581+
expectedMessages: Message[]
582+
) {
583+
let lastDisplayedMessages: Message[] = [];
584+
585+
try {
586+
await browser.waitUntil(async () => {
587+
// the text streams so the message may not be complete immediately
588+
try {
589+
lastDisplayedMessages = await getDisplayedMessages(browser);
590+
expect(lastDisplayedMessages).deep.equal(expectedMessages);
591+
} catch {
592+
return false;
593+
}
594+
return true;
595+
});
596+
} catch {
597+
console.log(
598+
'Last displayed messages:',
599+
JSON.stringify(lastDisplayedMessages)
600+
);
601+
throw new Error('Expected messages not found');
602+
}
603+
}
604+
575605
async function useExplainPlanEntryPoint(browser: CompassBrowser) {
576606
await browser.clickVisible(Selectors.AggregationExplainButton);
577607

0 commit comments

Comments
 (0)