Skip to content

Commit d1ae476

Browse files
HusneShabbirHusneShabbir
andauthored
chore(lightspeed): add e2e for stop conversation (#2720)
* test(lightspeed): add Stop conversation e2e and query delay mock Cover stopping an in-progress reply and prompt restoration. Extend devMode with delayed /v1/query mock and adjust fixtures and Playwright config. Made-with: Cursor * test(lightspeed): POM helpers for Stop flow and restore default Playwright projects Add chat composer locators and assertions on LightspeedPage. Refactor Stop e2e to use sendMessage(..., false) and shared helpers. Revert playwright.config to channel chrome to match origin/main. Made-with: Cursor --------- Co-authored-by: HusneShabbir <husneshabbir447@gmail.com>
1 parent b130cbc commit d1ae476

4 files changed

Lines changed: 98 additions & 14 deletions

File tree

workspaces/lightspeed/packages/app-legacy/e2e-tests/fixtures/responses.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ export const models = [
3838
},
3939
];
4040

41-
export const defaultConversation = {
42-
conversation_id: '1348e758-15ed-483a-bca5-b8702bbc79fe',
43-
};
44-
4541
export const conversations = [
4642
{
4743
conversation_id: '1348e758-15ed-483a-bca5-b8702bbc79fe',
@@ -56,11 +52,7 @@ export const conversations = [
5652
];
5753

5854
export const moreConversations = [
59-
{
60-
conversation_id: '1348e758-15ed-483a-bca5-b8702bbc79fe',
61-
topic_summary: 'Conversation 1',
62-
last_message_timestamp: createdAt,
63-
},
55+
conversations[0],
6456
{
6557
conversation_id: '1348e758-15ed-483a-bca5-b8702bbc79fb',
6658
topic_summary: 'New Conversation',
@@ -125,6 +117,9 @@ export const demoChatContent = [
125117

126118
export const botResponse = `This is a placeholder message`;
127119

120+
/** SSE `start.request_id` in {@link generateQueryResponse}. */
121+
const mockStreamRequestId = '0e3c4cd7-2817-4c34-91a2-6944550364df';
122+
128123
export const generateQueryResponse = (conversationId: string) => {
129124
const tokens = botResponse.match(/(\s+|[^\s]+)/g) || [];
130125

@@ -136,7 +131,10 @@ export const generateQueryResponse = (conversationId: string) => {
136131

137132
events.push({
138133
event: 'start',
139-
data: { conversation_id: conversationId },
134+
data: {
135+
conversation_id: conversationId,
136+
request_id: mockStreamRequestId,
137+
},
140138
});
141139

142140
tokens.forEach((token, index) => {

workspaces/lightspeed/packages/app-legacy/e2e-tests/lightspeed.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ import {
4343
expectChatbotControlsVisible,
4444
verifyDisplayModeMenuOptions,
4545
expectChatInputAreaVisible,
46+
expectChatInputValue,
47+
expectChatStopButtonVisible,
4648
expectEmptyChatHistory,
4749
expectConversationArea,
50+
chatStopButton,
51+
waitForChatMessageLoadingHidden,
4852
} from './pages/LightspeedPage';
4953
import {
5054
uploadFiles,
@@ -107,6 +111,7 @@ import {
107111
mockFeedbackStatus,
108112
mockModels,
109113
mockQuery,
114+
mockQueryWithResponseDelay,
110115
mockShields,
111116
} from './utils/devMode';
112117
import {
@@ -443,6 +448,22 @@ test.describe('Lightspeed tests', () => {
443448
await expect(botMessage).toContainText(assistantResponse);
444449
});
445450

451+
test('Stop ends in-progress reply and restores the prompt in the input', async () => {
452+
const stopFlowPrompt = 'Stop button restores prompt in input';
453+
454+
await mockQueryWithResponseDelay(
455+
sharedPage,
456+
stopFlowPrompt,
457+
conversations,
458+
5_000,
459+
);
460+
await sendMessage(stopFlowPrompt, sharedPage, translations, false);
461+
await expectChatStopButtonVisible(sharedPage);
462+
await chatStopButton(sharedPage).click();
463+
await expectChatInputValue(sharedPage, translations, stopFlowPrompt);
464+
await waitForChatMessageLoadingHidden(sharedPage);
465+
});
466+
446467
test.describe('Chat Management', () => {
447468
const testChatName = 'Test Rename';
448469

workspaces/lightspeed/packages/app-legacy/e2e-tests/pages/LightspeedPage.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Page, expect } from '@playwright/test';
17+
import { Page, expect, type Locator } from '@playwright/test';
1818
import { LightspeedMessages, evaluateMessage } from '../utils/translations';
1919

2020
export type DisplayMode = 'Overlay' | 'Dock to window' | 'Fullscreen';
@@ -87,13 +87,52 @@ export async function verifyDisplayModeMenuOptions(
8787
`);
8888
}
8989

90+
/** Chat composer message field (matches sendMessage in testHelper). */
91+
export function chatMessageTextbox(page: Page, t: LightspeedMessages): Locator {
92+
return page.getByRole('textbox', { name: t['chatbox.message.placeholder'] });
93+
}
94+
95+
export function chatSendButton(page: Page): Locator {
96+
return page.getByRole('button', { name: 'Send' });
97+
}
98+
99+
export function chatStopButton(page: Page): Locator {
100+
return page.getByRole('button', { name: 'Stop' });
101+
}
102+
103+
export function chatMessageLoading(page: Page): Locator {
104+
return page.locator('.pf-chatbot__message-loading');
105+
}
106+
107+
export async function expectChatStopButtonVisible(
108+
page: Page,
109+
options?: { timeout?: number },
110+
) {
111+
await expect(chatStopButton(page)).toBeVisible({
112+
timeout: options?.timeout ?? 10_000,
113+
});
114+
}
115+
116+
export async function expectChatInputValue(
117+
page: Page,
118+
t: LightspeedMessages,
119+
value: string,
120+
) {
121+
await expect(chatMessageTextbox(page, t)).toHaveValue(value);
122+
}
123+
124+
export async function waitForChatMessageLoadingHidden(
125+
page: Page,
126+
timeout = 7_000,
127+
) {
128+
await chatMessageLoading(page).waitFor({ state: 'hidden', timeout });
129+
}
130+
90131
export async function expectChatInputAreaVisible(
91132
page: Page,
92133
t: LightspeedMessages,
93134
) {
94-
await expect(
95-
page.getByRole('textbox', { name: t['chatbox.message.placeholder'] }),
96-
).toBeVisible();
135+
await expect(chatMessageTextbox(page, t)).toBeVisible();
97136
}
98137

99138
export async function expectEmptyChatHistory(

workspaces/lightspeed/packages/app-legacy/e2e-tests/utils/devMode.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,32 @@ export async function mockQuery(
7272
});
7373
}
7474

75+
/** Delays the mock response so Stop stays visible during the wait. */
76+
export async function mockQueryWithResponseDelay(
77+
page: Page,
78+
query: string,
79+
conversations: any[],
80+
delayMs: number,
81+
) {
82+
await page.unroute(`${modelBaseUrl}/v1/query`);
83+
await page.route(`${modelBaseUrl}/v1/query`, async route => {
84+
await new Promise<void>(resolve => {
85+
setTimeout(resolve, delayMs);
86+
});
87+
const payload = route.request().postDataJSON();
88+
89+
if (payload.query === query) {
90+
conversations[1].conversation_id = payload.conversation_id;
91+
}
92+
const body = generateQueryResponse(
93+
payload.query === query
94+
? conversations[1].conversation_id
95+
: conversations[0].conversation_id,
96+
);
97+
await route.fulfill({ body });
98+
});
99+
}
100+
75101
export async function mockFeedbackStatus(page: Page, enabled = true) {
76102
await page.route(`${modelBaseUrl}/v1/feedback/status`, async route => {
77103
await route.fulfill({

0 commit comments

Comments
 (0)