Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cdk/a11y): not detecting fake mousedown on firefox #23493

Merged
merged 1 commit into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/cdk/a11y/fake-event-detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
export function isFakeMousedownFromScreenReader(event: MouseEvent): boolean {
// Some screen readers will dispatch a fake `mousedown` event when pressing enter or space on
// a clickable element. We can distinguish these events when both `offsetX` and `offsetY` are
// zero. Note that there's an edge case where the user could click the 0x0 spot of the screen
// themselves, but that is unlikely to contain interaction elements. Historically we used to
// check `event.buttons === 0`, however that no longer works on recent versions of NVDA.
return event.offsetX === 0 && event.offsetY === 0;
// zero or `event.buttons` is zero, depending on the browser:
// - `event.buttons` works on Firefox, but fails on Chrome.
// - `offsetX` and `offsetY` work on Chrome, but fail on Firefox.
// Note that there's an edge case where the user could click the 0x0 spot of the
// screen themselves, but that is unlikely to contain interactive elements.
return event.buttons === 0 || (event.offsetX === 0 && event.offsetY === 0);
}

/** Gets whether an event could be a faked `touchstart` event dispatched by a screen reader. */
Expand Down
22 changes: 21 additions & 1 deletion src/cdk/a11y/focus-monitor/focus-monitor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ describe('FocusMonitor', () => {
expect(changeHandler).toHaveBeenCalledWith('program');
}));

it('should detect fake mousedown from a screen reader', fakeAsync(() => {
it('should detect fake mousedown from a screen reader on Chrome', fakeAsync(() => {
// Simulate focus via a fake mousedown from a screen reader.
dispatchMouseEvent(buttonElement, 'mousedown');
const event = createMouseEvent('mousedown');
Expand All @@ -167,6 +167,26 @@ describe('FocusMonitor', () => {
expect(changeHandler).toHaveBeenCalledWith('keyboard');
}));

it('should detect fake mousedown from a screen reader on Firefox', fakeAsync(() => {
// Simulate focus via a fake mousedown from a screen reader.
dispatchMouseEvent(buttonElement, 'mousedown');
const event = createMouseEvent('mousedown');
Object.defineProperties(event, {buttons: {get: () => 0}});
dispatchEvent(buttonElement, event);

buttonElement.focus();
fixture.detectChanges();
flush();

expect(buttonElement.classList.length)
.withContext('button should have exactly 2 focus classes').toBe(2);
expect(buttonElement.classList.contains('cdk-focused'))
.withContext('button should have cdk-focused class').toBe(true);
expect(buttonElement.classList.contains('cdk-keyboard-focused'))
.withContext('button should have cdk-keyboard-focused class').toBe(true);
expect(changeHandler).toHaveBeenCalledWith('keyboard');
}));

it('focusVia keyboard should simulate keyboard focus', fakeAsync(() => {
focusMonitor.focusVia(buttonElement, 'keyboard');
flush();
Expand Down
13 changes: 12 additions & 1 deletion src/cdk/a11y/input-modality/input-modality-detector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ describe('InputModalityDetector', () => {
expect(emitted).toEqual(['keyboard', 'mouse', 'touch', 'keyboard']);
});

it('should detect fake screen reader mouse events as keyboard input modality', () => {
it('should detect fake screen reader mouse events as keyboard input modality on Chrome', () => {
setupTest();

// Create a fake screen-reader mouse event.
Expand All @@ -144,6 +144,17 @@ describe('InputModalityDetector', () => {
expect(detector.mostRecentModality).toBe('keyboard');
});

it('should detect fake screen reader mouse events as keyboard input modality on Firefox', () => {
setupTest();

// Create a fake screen-reader mouse event.
const event = createMouseEvent('mousedown');
Object.defineProperties(event, {buttons: {get: () => 0}});
dispatchEvent(document, event);

expect(detector.mostRecentModality).toBe('keyboard');
});

it('should detect fake screen reader touch events as keyboard input modality', () => {
setupTest();

Expand Down