Skip to content

ci: update remote browsers we test against #19961

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

Merged
merged 3 commits into from
Jul 21, 2020
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
159 changes: 49 additions & 110 deletions src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Platform} from '@angular/cdk/platform';
import {PLATFORM_ID} from '@angular/core';
import {inject} from '@angular/core/testing';
import {InteractivityChecker, IsFocusableConfig} from './interactivity-checker';

Expand All @@ -7,11 +8,11 @@ describe('InteractivityChecker', () => {
let testContainerElement: HTMLElement;
let checker: InteractivityChecker;

beforeEach(inject([Platform, InteractivityChecker], (p: Platform, i: InteractivityChecker) => {
beforeEach(inject([PLATFORM_ID], (platformId: Object) => {
testContainerElement = document.createElement('div');
document.body.appendChild(testContainerElement);
platform = p;
checker = i;
platform = new Platform(platformId);
checker = new InteractivityChecker(platform);
}));

afterEach(() => {
Expand Down Expand Up @@ -253,45 +254,48 @@ describe('InteractivityChecker', () => {

describe('isTabbable', () => {

it('should respect the tabindex for video elements with controls', () => {
// Do not run for Blink, Firefox and iOS because those treat video elements
// with controls different and are covered in other tests.
if (platform.BLINK || platform.FIREFOX || platform.IOS) {
return;
}

const video = createFromTemplate('<video controls>', true);

expect(checker.isTabbable(video)).toBe(true);
// Some tests should not run inside of iOS browsers, because those only allow specific
// elements to be tabbable and cause the tests to always fail.
describe('for non-iOS browsers', () => {
let shouldSkip: boolean;

video.tabIndex = -1;
beforeEach(() => {
shouldSkip = platform.IOS;
});

expect(checker.isTabbable(video)).toBe(false);
});
it('should by default treat video elements with controls as tabbable', () => {
if (shouldSkip) {
return;
}

it('should always mark video elements with controls as tabbable (BLINK & FIREFOX)', () => {
// Only run this spec for Blink and Firefox, because those always treat video
// elements with controls as tabbable.
if (!platform.BLINK && !platform.FIREFOX) {
return;
}
const video = createFromTemplate('<video controls>', true);
expect(checker.isTabbable(video)).toBe(true);
});

const video = createFromTemplate('<video controls>', true);
it('should respect the tabindex for video elements with controls', () => {
if (shouldSkip) {
return;
}

expect(checker.isTabbable(video)).toBe(true);
const video = createFromTemplate('<video controls>', true);
expect(checker.isTabbable(video)).toBe(true);

video.tabIndex = -1;
video.tabIndex = -1;
expect(checker.isTabbable(video)).toBe(false);
});

expect(checker.isTabbable(video)).toBe(true);
});
// Firefox always makes video elements (regardless of the controls) as tabbable, unless
// explicitly opted-out by setting the tabindex.
it('should by default treat video elements without controls as tabbable in firefox', () => {
if (!platform.FIREFOX) {
return;
}

// Some tests should not run inside of iOS browsers, because those only allow specific
// elements to be tabbable and cause the tests to always fail.
describe('for non-iOS browsers', () => {
let shouldSkip: boolean;
const video = createFromTemplate('<video>', true);
expect(checker.isTabbable(video)).toBe(true);

beforeEach(() => {
shouldSkip = platform.IOS;
video.tabIndex = -1;
expect(checker.isTabbable(video)).toBe(false);
});

it('should mark form controls and anchors without tabindex attribute as tabbable', () => {
Expand Down Expand Up @@ -424,39 +428,25 @@ describe('InteractivityChecker', () => {
}
});

it('should always mark audio elements without controls as not tabbable', () => {
it('should detect audio elements with controls as tabbable', () => {
if (!shouldSkip) {
const audio = createFromTemplate('<audio>', true);

const audio = createFromTemplate('<audio controls>', true);
expect(checker.isTabbable(audio)).toBe(true);
audio.tabIndex = -1;
expect(checker.isTabbable(audio)).toBe(false);
}
});

});

describe('for Blink and Webkit browsers', () => {
let shouldSkip: boolean;

beforeEach(() => {
shouldSkip = !platform.BLINK && !platform.WEBKIT;
});
it('should always detect audio elements without controls as non-tabbable', () => {
if (!shouldSkip) {
const audio = createFromTemplate('<audio>', true);
expect(checker.isTabbable(audio)).toBe(false);

it('should not mark elements inside of object frames as tabbable', () => {
if (shouldSkip) {
return;
// Setting a `tabindex` has no effect. The audio element is expected
// to be still not tabbable.
audio.tabIndex = 0;
expect(checker.isTabbable(audio)).toBe(false);
}

const objectEl = createFromTemplate('<object>', true) as HTMLObjectElement;
const button = createFromTemplate('<button tabindex="0">Not Tabbable</button>');

appendElements([objectEl]);

// This creates an empty contentDocument for the frame element.
objectEl.type = 'text/html';
objectEl.contentDocument!.body.appendChild(button);

expect(checker.isTabbable(objectEl)).toBe(false);
expect(checker.isTabbable(button)).toBe(false);
});

it('should not mark elements inside of invisible frames as tabbable', () => {
Expand All @@ -482,57 +472,6 @@ describe('InteractivityChecker', () => {
expect(checker.isTabbable(objectEl)).toBe(false);
}
});

});

describe('for Blink browsers', () => {
let shouldSkip: boolean;

beforeEach(() => {
shouldSkip = !platform.BLINK;
});

it('should always mark audio elements with controls as tabbable', () => {
if (shouldSkip) {
return;
}

const audio = createFromTemplate('<audio controls>', true);

expect(checker.isTabbable(audio)).toBe(true);

audio.tabIndex = -1;

// The audio element will be still tabbable because Blink always
// considers them as tabbable.
expect(checker.isTabbable(audio)).toBe(true);
});

});

describe('for Internet Explorer', () => {
let shouldSkip: boolean;

beforeEach(() => {
shouldSkip = !platform.TRIDENT;
});

it('should never mark video elements without controls as tabbable', () => {
if (shouldSkip) {
return;
}

// In Internet Explorer video elements without controls are never tabbable.
const video = createFromTemplate('<video>', true);

expect(checker.isTabbable(video)).toBe(false);

video.tabIndex = 0;

expect(checker.isTabbable(video)).toBe(false);

});

});

describe('for iOS browsers', () => {
Expand Down
60 changes: 29 additions & 31 deletions src/cdk/a11y/interactivity-checker/interactivity-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,15 @@ export class InteractivityChecker {
const frameElement = getFrameElement(getWindow(element));

if (frameElement) {
const frameType = frameElement && frameElement.nodeName.toLowerCase();

// Frame elements inherit their tabindex onto all child elements.
if (getTabIndexValue(frameElement) === -1) {
return false;
}

// Webkit and Blink consider anything inside of an <object> element as non-tabbable.
if ((this._platform.BLINK || this._platform.WEBKIT) && frameType === 'object') {
// Browsers disable tabbing to an element inside of an invisible frame.
if (!this.isVisible(frameElement)) {
return false;
}

// Webkit and Blink disable tabbing to an element inside of an invisible frame.
if ((this._platform.BLINK || this._platform.WEBKIT) && !this.isVisible(frameElement)) {
return false;
}

}

let nodeName = element.nodeName.toLowerCase();
Expand All @@ -98,40 +90,46 @@ export class InteractivityChecker {
return tabIndexValue !== -1;
}

if (nodeName === 'iframe') {
// The frames may be tabbable depending on content, but it's not possibly to reliably
// investigate the content of the frames.
if (nodeName === 'iframe' || nodeName === 'object') {
// The frame or object's content may be tabbable depending on the content, but it's
// not possibly to reliably detect the content of the frames. We always consider such
// elements as non-tabbable.
return false;
}

// In iOS, the browser only considers some specific elements as tabbable.
if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) {
return false;
}

if (nodeName === 'audio') {
// Audio elements without controls enabled are never tabbable, regardless
// of the tabindex attribute explicitly being set.
if (!element.hasAttribute('controls')) {
// By default an <audio> element without the controls enabled is not tabbable.
return false;
} else if (this._platform.BLINK) {
// In Blink <audio controls> elements are always tabbable.
return true;
}
// Audio elements with controls are by default tabbable unless the
// tabindex attribute is set to `-1` explicitly.
return tabIndexValue !== -1;
}

if (nodeName === 'video') {
if (!element.hasAttribute('controls') && this._platform.TRIDENT) {
// In Trident a <video> element without the controls enabled is not tabbable.
// For all video elements, if the tabindex attribute is set to `-1`, the video
// is not tabbable. Note: We cannot rely on the default `HTMLElement.tabIndex`
// property as that one is set to `-1` in Chrome, Edge and Safari v13.1. The
// tabindex attribute is the source of truth here.
if (tabIndexValue === -1) {
return false;
} else if (this._platform.BLINK || this._platform.FIREFOX) {
// In Chrome and Firefox <video controls> elements are always tabbable.
}
// If the tabindex is explicitly set, and not `-1` (as per check before), the
// video element is always tabbable (regardless of whether it has controls or not).
if (tabIndexValue !== null) {
return true;
}
}

if (nodeName === 'object' && (this._platform.BLINK || this._platform.WEBKIT)) {
// In all Blink and WebKit based browsers <object> elements are never tabbable.
return false;
}

// In iOS the browser only considers some specific elements as tabbable.
if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) {
return false;
// Otherwise (when no explicit tabindex is set), a video is only tabbable if it
// has controls enabled. Firefox is special as videos are always tabbable regardless
// of whether there are controls or not.
return this._platform.FIREFOX || element.hasAttribute('controls');
}

return element.tabIndex >= 0;
Expand Down
17 changes: 11 additions & 6 deletions src/material-experimental/mdc-slider/slider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,12 @@ describe('MDC-based MatSlider', () => {
// pixel will be a tick.
const ticksPerTrackPercentage = (tickInterval * step);
// iOS evaluates the "background" expression for the ticks to the exact number,
// Firefox, Edge, Safari evaluate to a percentage value, and Chrome evaluates to
// a rounded five-digit decimal number.
// Firefox, Edge, Safari 12.1 evaluate to a percentage value. Chrome evaluates to
// a rounded five-digit decimal number and Safari 13.1 evaluates to a decimal
// representing the percentage.
const expectationRegex = new RegExp(
`(${sizeOfTick}|${ticksPerTrackPercentage}%|${sizeOfTick.toFixed(5)})`);
`(${sizeOfTick}|${ticksPerTrackPercentage}%|${sizeOfTick.toFixed(5)}|` +
`${ticksPerTrackPercentage / 100})`);
expect(ticksContainerElement.style.background)
.toMatch(expectationRegex);
});
Expand Down Expand Up @@ -1229,10 +1231,13 @@ function flushRequestAnimationFrame() {
tick(16);
}

// Disable animations and make the slider an even 100px, so that we get nice
// round values in tests.
// Disable animations and make the slider an even 100px, so that we get
// nice round values in tests.
const styles = `
.mat-mdc-slider { min-width: 100px !important; }
.mat-mdc-slider {
min-width: 100px !important;
width: 100px;
}
`;

@Component({
Expand Down
Loading