mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 20:13:32 +01:00
Add smoke test for anonymous chat access (#291953)
* Initial plan * Add smoke test for anonymous chat access Co-authored-by: bpasero <900690+bpasero@users.noreply.github.com> * fix * . * . * . * . * . * . * . --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bpasero <900690+bpasero@users.noreply.github.com> Co-authored-by: Benjamin Pasero <benjamin.pasero@microsoft.com>
This commit is contained in:
@@ -4,15 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Code } from './code';
|
||||
import { Notification } from './notification';
|
||||
|
||||
const CHAT_VIEW = 'div[id="workbench.panel.chat"]';
|
||||
const CHAT_EDITOR = `${CHAT_VIEW} .monaco-editor[role="code"]`;
|
||||
const CHAT_EDITOR_FOCUSED = `${CHAT_VIEW} .monaco-editor.focused[role="code"]`;
|
||||
const CHAT_RESPONSE = `${CHAT_VIEW} .interactive-item-container.interactive-response`;
|
||||
const CHAT_RESPONSE_COMPLETE = `${CHAT_RESPONSE}:not(.chat-response-loading)`;
|
||||
const CHAT_FOOTER_DETAILS = `${CHAT_VIEW} .chat-footer-details`;
|
||||
|
||||
export class Chat {
|
||||
|
||||
constructor(private code: Code, private notification: Notification) { }
|
||||
constructor(private code: Code) { }
|
||||
|
||||
private get chatInputSelector(): string {
|
||||
return `${CHAT_EDITOR} ${!this.code.editContextEnabled ? 'textarea' : '.native-edit-context'}`;
|
||||
@@ -27,9 +29,6 @@ export class Chat {
|
||||
}
|
||||
|
||||
async sendMessage(message: string): Promise<void> {
|
||||
if (await this.notification.isNotificationVisible()) {
|
||||
throw new Error('Notification is visible');
|
||||
}
|
||||
// Click on the chat input to focus it
|
||||
await this.code.waitAndClick(CHAT_EDITOR);
|
||||
|
||||
@@ -44,4 +43,22 @@ export class Chat {
|
||||
// Submit the message
|
||||
await this.code.dispatchKeybinding('enter', () => Promise.resolve());
|
||||
}
|
||||
|
||||
async waitForResponse(retryCount?: number): Promise<void> {
|
||||
|
||||
// First wait for a response element to appear
|
||||
await this.code.waitForElement(CHAT_RESPONSE, undefined, retryCount);
|
||||
|
||||
// Then wait for it to complete (not loading)
|
||||
await this.code.waitForElement(CHAT_RESPONSE_COMPLETE, undefined, retryCount);
|
||||
}
|
||||
|
||||
async waitForModelInFooter(modelName: string): Promise<void> {
|
||||
await this.code.waitForElements(CHAT_FOOTER_DETAILS, false, el => {
|
||||
return el.some(el => {
|
||||
const text = el && typeof el.textContent === 'string' ? el.textContent : '';
|
||||
return !!text && text.includes(modelName);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,4 @@ export * from './localization';
|
||||
export * from './workbench';
|
||||
export * from './task';
|
||||
export * from './chat';
|
||||
export * from './notification';
|
||||
export { getDevElectronPath, getBuildElectronPath, getBuildVersion } from './electron';
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Code } from './code';
|
||||
|
||||
const NOTIFICATION_TOAST = '.notification-toast';
|
||||
|
||||
export class Notification {
|
||||
|
||||
constructor(private code: Code) { }
|
||||
|
||||
async isNotificationVisible(): Promise<boolean> {
|
||||
try {
|
||||
await this.code.waitForElement(NOTIFICATION_TOAST, undefined, 1);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import { Notebook } from './notebook';
|
||||
import { Localization } from './localization';
|
||||
import { Task } from './task';
|
||||
import { Chat } from './chat';
|
||||
import { Notification } from './notification';
|
||||
|
||||
export interface Commands {
|
||||
runCommand(command: string, options?: { exactLabelMatch?: boolean }): Promise<any>;
|
||||
@@ -50,7 +49,6 @@ export class Workbench {
|
||||
readonly localization: Localization;
|
||||
readonly task: Task;
|
||||
readonly chat: Chat;
|
||||
readonly notification: Notification;
|
||||
|
||||
constructor(code: Code) {
|
||||
this.editors = new Editors(code);
|
||||
@@ -71,7 +69,6 @@ export class Workbench {
|
||||
this.notebook = new Notebook(this.quickaccess, this.quickinput, code);
|
||||
this.localization = new Localization(code);
|
||||
this.task = new Task(code, this.editor, this.editors, this.quickaccess, this.quickinput, this.terminal);
|
||||
this.notification = new Notification(code);
|
||||
this.chat = new Chat(code, this.notification);
|
||||
this.chat = new Chat(code);
|
||||
}
|
||||
}
|
||||
|
||||
37
test/smoke/src/areas/chat/chatAnonymous.test.ts
Normal file
37
test/smoke/src/areas/chat/chatAnonymous.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Application, Logger } from '../../../../automation';
|
||||
import { installAllHandlers } from '../../utils';
|
||||
|
||||
export function setup(logger: Logger) {
|
||||
describe('Chat Anonymous', () => {
|
||||
|
||||
// Shared before/after handling
|
||||
installAllHandlers(logger);
|
||||
|
||||
it('can send a chat message with anonymous access', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
// Enable anonymous access
|
||||
await app.workbench.settingsEditor.addUserSetting('chat.allowAnonymousAccess', 'true');
|
||||
|
||||
// Open chat view
|
||||
await app.workbench.quickaccess.runCommand('workbench.action.chat.open');
|
||||
|
||||
// Wait for chat view to be visible
|
||||
await app.workbench.chat.waitForChatView();
|
||||
|
||||
// Send a message
|
||||
await app.workbench.chat.sendMessage('Hello');
|
||||
|
||||
// Wait for a response to complete
|
||||
await app.workbench.chat.waitForResponse();
|
||||
|
||||
// Wait for model name to appear in footer
|
||||
await app.workbench.chat.waitForModelInFooter('GPT-5 mini');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import { setup as setupLaunchTests } from './areas/workbench/launch.test';
|
||||
import { setup as setupTerminalTests } from './areas/terminal/terminal.test';
|
||||
import { setup as setupTaskTests } from './areas/task/task.test';
|
||||
import { setup as setupChatTests } from './areas/chat/chat.test';
|
||||
import { setup as setupChatAnonymousTests } from './areas/chat/chatAnonymous.test';
|
||||
import { setup as setupAccessibilityTests } from './areas/accessibility/accessibility.test';
|
||||
|
||||
const rootPath = path.join(__dirname, '..', '..', '..');
|
||||
@@ -406,5 +407,6 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
|
||||
if (!opts.web && !opts.remote && quality !== Quality.Dev && quality !== Quality.OSS) { setupLocalizationTests(logger); }
|
||||
if (!opts.web && !opts.remote) { setupLaunchTests(logger); }
|
||||
if (!opts.web) { setupChatTests(logger); }
|
||||
if (!opts.web && quality === Quality.Insiders) { setupChatAnonymousTests(logger); }
|
||||
setupAccessibilityTests(logger, opts);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user