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:
Copilot
2026-01-31 16:33:11 +00:00
committed by GitHub
parent d21910006a
commit b31c729a39
8 changed files with 74 additions and 33 deletions

View File

@@ -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);
});
});
}
}

View File

@@ -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';

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View 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');
});
});
}

View File

@@ -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);
});