mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-04 01:44:44 -06:00
add chat response tests, discover and fix a11y issues (#286622)
This commit is contained in:
parent
1d64e1e1d0
commit
2f87e3fa5d
@ -351,10 +351,10 @@ export class Button extends Disposable implements IButton {
|
||||
set checked(value: boolean) {
|
||||
if (value) {
|
||||
this._element.classList.add('checked');
|
||||
this._element.setAttribute('aria-checked', 'true');
|
||||
this._element.setAttribute('aria-pressed', 'true');
|
||||
} else {
|
||||
this._element.classList.remove('checked');
|
||||
this._element.setAttribute('aria-checked', 'false');
|
||||
this._element.setAttribute('aria-pressed', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -237,11 +237,11 @@ export class CompositeBarActionViewItem extends BaseActionViewItem {
|
||||
this.container.classList.add('icon');
|
||||
}
|
||||
|
||||
// Use 'tab' inside tablist, 'button' for popup items outside tablist
|
||||
const role = this.options.isTabList || !this.options.hasPopup ? 'tab' : 'button';
|
||||
this.container.setAttribute('role', role);
|
||||
if (this.options.hasPopup) {
|
||||
this.container.setAttribute('role', 'button');
|
||||
this.container.setAttribute('aria-haspopup', 'true');
|
||||
} else {
|
||||
this.container.setAttribute('role', 'tab');
|
||||
}
|
||||
|
||||
// Try hard to prevent keyboard only focus feedback when using mouse
|
||||
@ -479,7 +479,7 @@ export class CompositeOverflowActivityActionViewItem extends CompositeBarActionV
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
) {
|
||||
super(action, { icon: true, colors, hasPopup: true, hoverOptions }, () => true, themeService, hoverService, configurationService, keybindingService);
|
||||
super(action, { icon: true, colors, hasPopup: true, hoverOptions, isTabList: true }, () => true, themeService, hoverService, configurationService, keybindingService);
|
||||
}
|
||||
|
||||
showMenu(): void {
|
||||
|
||||
@ -749,7 +749,7 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem {
|
||||
// Create dropdown action (empty label prevents default tooltip - we have our own hover)
|
||||
const dropdownAction = toAction({
|
||||
id: 'agentStatus.sparkle.dropdown',
|
||||
label: '',
|
||||
label: localize('agentStatus.sparkle.dropdown', "More Actions"),
|
||||
run() { }
|
||||
});
|
||||
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Application, Logger } from '../../../../automation';
|
||||
import { Application, Logger, Quality } from '../../../../automation';
|
||||
import { installAllHandlers } from '../../utils';
|
||||
|
||||
export function setup(logger: Logger, opts: { web?: boolean }) {
|
||||
describe.skip('Accessibility', function () {
|
||||
export function setup(logger: Logger, opts: { web?: boolean }, quality: Quality) {
|
||||
describe('Accessibility', function () {
|
||||
|
||||
// Increase timeout for accessibility scans
|
||||
this.timeout(30 * 1000);
|
||||
this.timeout(2 * 60 * 1000);
|
||||
|
||||
// Retry tests to minimize flakiness
|
||||
this.retries(2);
|
||||
@ -38,7 +38,9 @@ export function setup(logger: Logger, opts: { web?: boolean }) {
|
||||
// Monaco lists use aria-multiselectable on role="list" and aria-setsize/aria-posinset/aria-selected on role="dialog" rows
|
||||
// These violations appear intermittently when notification lists or other dynamic lists are visible
|
||||
// Note: patterns match against HTML string, not CSS selectors, so no leading dots
|
||||
'aria-allowed-attr': ['monaco-list', 'monaco-list-row']
|
||||
'aria-allowed-attr': ['monaco-list', 'monaco-list-row'],
|
||||
// Monaco lists may temporarily contain dialog children during extension activation errors
|
||||
'aria-required-children': ['monaco-list']
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -69,7 +71,7 @@ export function setup(logger: Logger, opts: { web?: boolean }) {
|
||||
});
|
||||
|
||||
// Chat is not available in web mode
|
||||
if (!opts.web) {
|
||||
if (quality !== Quality.Dev && quality !== Quality.OSS && !opts.web) {
|
||||
describe('Chat', function () {
|
||||
|
||||
it('chat panel has no accessibility violations', async function () {
|
||||
@ -87,6 +89,79 @@ export function setup(logger: Logger, opts: { web?: boolean }) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Chat response test requires gallery service which is only available in non-Dev/OSS builds
|
||||
it('chat response has no accessibility violations', async function () {
|
||||
// Disable retries for this test - it modifies settings and retries cause issues
|
||||
this.retries(0);
|
||||
// Extend timeout for this test since AI responses can take a while
|
||||
this.timeout(3 * 60 * 1000);
|
||||
|
||||
// Enable anonymous chat access
|
||||
await app.workbench.settingsEditor.addUserSetting('chat.allowAnonymousAccess', 'true');
|
||||
|
||||
// Open chat panel
|
||||
await app.workbench.quickaccess.runCommand('workbench.action.chat.open');
|
||||
|
||||
// Wait for chat view to be visible
|
||||
await app.workbench.chat.waitForChatView();
|
||||
|
||||
// Send a simple message
|
||||
await app.workbench.chat.sendMessage('Create a simple hello.txt file with the text "Hello World"');
|
||||
|
||||
// Wait for the response to complete (1500 retries ~= 150 seconds at 100ms per retry)
|
||||
await app.workbench.chat.waitForResponse(1500);
|
||||
|
||||
// Run accessibility check on the chat panel with the response
|
||||
await app.code.driver.assertNoAccessibilityViolations({
|
||||
selector: 'div[id="workbench.panel.chat"]',
|
||||
excludeRules: {
|
||||
// Links in chat welcome view show underline on hover/focus which axe-core static analysis cannot detect
|
||||
'link-in-text-block': ['command:workbench.action.chat.generateInstructions'],
|
||||
// Monaco lists use aria-multiselectable on role="list" and aria-selected on role="listitem"
|
||||
// These are used intentionally for selection semantics even though technically not spec-compliant
|
||||
'aria-allowed-attr': ['monaco-list', 'monaco-list-row'],
|
||||
// Some icon buttons have empty aria-label during rendering
|
||||
'aria-command-name': ['codicon-plus']
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('chat terminal tool response has no accessibility violations', async function () {
|
||||
// Disable retries for this test
|
||||
this.retries(0);
|
||||
// Extend timeout for this test since AI responses can take a while
|
||||
this.timeout(3 * 60 * 1000);
|
||||
|
||||
// Enable auto-approve for tools so terminal commands run automatically
|
||||
await app.workbench.settingsEditor.addUserSetting('chat.tools.global.autoApprove', 'true');
|
||||
|
||||
// Open chat panel
|
||||
await app.workbench.quickaccess.runCommand('workbench.action.chat.open');
|
||||
|
||||
// Wait for chat view to be visible
|
||||
await app.workbench.chat.waitForChatView();
|
||||
|
||||
// Send a terminal command request
|
||||
await app.workbench.chat.sendMessage('Run ls in the terminal');
|
||||
|
||||
// Wait for the response to complete (1500 retries ~= 150 seconds at 100ms per retry)
|
||||
await app.workbench.chat.waitForResponse(1500);
|
||||
|
||||
// Run accessibility check on the chat panel with the response
|
||||
await app.code.driver.assertNoAccessibilityViolations({
|
||||
selector: 'div[id="workbench.panel.chat"]',
|
||||
excludeRules: {
|
||||
// Links in chat welcome view show underline on hover/focus which axe-core static analysis cannot detect
|
||||
'link-in-text-block': ['command:workbench.action.chat.generateInstructions'],
|
||||
// Monaco lists use aria-multiselectable on role="list" and aria-selected on role="listitem"
|
||||
// These are used intentionally for selection semantics even though technically not spec-compliant
|
||||
'aria-allowed-attr': ['monaco-list', 'monaco-list-row'],
|
||||
// Some icon buttons have empty aria-label during rendering
|
||||
'aria-command-name': ['codicon-plus']
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -408,5 +408,5 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
|
||||
if (!opts.web && !opts.remote) { setupLaunchTests(logger); }
|
||||
if (!opts.web) { setupChatTests(logger); }
|
||||
if (!opts.web && quality === Quality.Insiders) { setupChatAnonymousTests(logger); }
|
||||
setupAccessibilityTests(logger, opts);
|
||||
setupAccessibilityTests(logger, opts, quality);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user