-
-
Notifications
You must be signed in to change notification settings - Fork 805
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
test: components/progress-bar components/progress-ring #562
Changes from all commits
f163929
eee97d7
34447a3
449f5e6
c4cbc89
9a19cc2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { expect, fixture, html } from '@open-wc/testing'; | ||
|
||
import '../../../dist/shoelace.js'; | ||
import type SlProgressBar from './progress-bar'; | ||
|
||
describe('<sl-progress-bar>', () => { | ||
let el: SlProgressBar; | ||
|
||
describe('when provided just a value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressBar>(html`<sl-progress-bar value="25"></sl-progress-bar>`); | ||
}); | ||
|
||
it('should render a component that does not pass accessibility test.', async () => { | ||
await expect(el).not.to.be.accessible(); | ||
}); | ||
}); | ||
|
||
describe('when provided a title, and value parameter', async () => { | ||
let base: HTMLDivElement; | ||
let indicator: HTMLDivElement; | ||
|
||
before(async () => { | ||
el = await fixture<SlProgressBar>( | ||
html`<sl-progress-bar title="Titled Progress Ring" value="25"></sl-progress-bar>` | ||
); | ||
base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; | ||
indicator = el.shadowRoot?.querySelector('[part="indicator"]') as HTMLDivElement; | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
|
||
it('uses the value parameter on the base, as aria-valuenow', async () => { | ||
expect(base).attribute('aria-valuenow', '25'); | ||
}); | ||
|
||
it('appends a % to the value, and uses it as the the value parameter to determine the width on the "indicator" part', async () => { | ||
expect(indicator).attribute('style', 'width:25%;'); | ||
}); | ||
}); | ||
|
||
describe('when provided an indeterminate parameter', async () => { | ||
let base: HTMLDivElement; | ||
|
||
before(async () => { | ||
el = await fixture<SlProgressBar>( | ||
html`<sl-progress-bar title="Titled Progress Ring" indeterminate></sl-progress-bar>` | ||
); | ||
base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
|
||
it('should append a progress-bar--indeterminate class to the "base" part.', async () => { | ||
expect(base.classList.value.trim()).to.eq('progress-bar progress-bar--indeterminate'); | ||
}); | ||
}); | ||
|
||
describe('when provided a ariaLabel, and value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressBar>( | ||
html`<sl-progress-bar ariaLabel="Labelled Progress Ring" value="25"></sl-progress-bar>` | ||
); | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
}); | ||
|
||
describe('when provided a ariaLabelledBy, and value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressBar>( | ||
html` | ||
<label id="labelledby">Progress Ring Label</label> | ||
<sl-progress-bar ariaLabelledBy="labelledby" value="25"></sl-progress-bar> | ||
` | ||
); | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import { LitElement, html } from 'lit'; | ||
import { customElement, property } from 'lit/decorators.js'; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
import { classMap } from 'lit/directives/class-map.js'; | ||
import { styleMap } from 'lit/directives/style-map.js'; | ||
import styles from './progress-bar.styles'; | ||
|
@@ -29,6 +30,15 @@ export default class SlProgressBar extends LitElement { | |
/** When true, percentage is ignored, the label is hidden, and the progress bar is drawn in an indeterminate state. */ | ||
@property({ type: Boolean, reflect: true }) indeterminate = false; | ||
|
||
/** When set, will place a hoverable title on the progress bar. */ | ||
@property() title: string; | ||
|
||
/** When set, will place a label on the progress bar. */ | ||
@property() ariaLabel: string; | ||
|
||
/** When set, will place a labelledby on the progress bar. */ | ||
@property() ariaLabelledBy: string; | ||
|
||
render() { | ||
return html` | ||
<div | ||
|
@@ -38,9 +48,12 @@ export default class SlProgressBar extends LitElement { | |
'progress-bar--indeterminate': this.indeterminate | ||
})} | ||
role="progressbar" | ||
title=${ifDefined(this.title)} | ||
aria-label=${ifDefined(this.ariaLabel)} | ||
aria-labelledby=${ifDefined(this.ariaLabelledBy)} | ||
aria-valuemin="0" | ||
aria-valuemax="100" | ||
aria-valuenow="${this.indeterminate ? '' : this.value}" | ||
aria-valuenow="${this.indeterminate ? 0 : this.value}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While the progress-bar is indeterminate, I suspect that it's closest to "0". We require a value other that '' for it to pass AXE. |
||
> | ||
<div part="indicator" class="progress-bar__indicator" style=${styleMap({ width: this.value + '%' })}> | ||
${!this.indeterminate | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { expect, fixture, html } from '@open-wc/testing'; | ||
|
||
import '../../../dist/shoelace.js'; | ||
import type SlProgressRing from './progress-ring'; | ||
|
||
describe('<sl-progress-ring>', () => { | ||
let el: SlProgressRing; | ||
|
||
describe('when provided just a value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressRing>(html`<sl-progress-ring value="25"></sl-progress-ring>`); | ||
}); | ||
|
||
it('should render a component that does not pass accessibility test.', async () => { | ||
await expect(el).not.to.be.accessible(); | ||
}); | ||
}); | ||
|
||
describe('when provided a title, and value parameter', async () => { | ||
let base: HTMLDivElement; | ||
|
||
before(async () => { | ||
el = await fixture<SlProgressRing>( | ||
html`<sl-progress-ring title="Titled Progress Ring" value="25"></sl-progress-ring>` | ||
); | ||
base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
|
||
it('uses the value parameter on the base, as aria-valuenow', async () => { | ||
expect(base).attribute('aria-valuenow', '25'); | ||
}); | ||
|
||
it('translates the value parameter to a percentage, and uses translation on the base, as percentage css variable', async () => { | ||
expect(base).attribute('style', '--percentage: 0.25'); | ||
}); | ||
}); | ||
|
||
describe('when provided a ariaLabel, and value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressRing>( | ||
html`<sl-progress-ring ariaLabel="Labelled Progress Ring" value="25"></sl-progress-ring>` | ||
); | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
}); | ||
|
||
describe('when provided a ariaLabelledBy, and value parameter', async () => { | ||
before(async () => { | ||
el = await fixture<SlProgressRing>( | ||
html` | ||
<label id="labelledby">Progress Ring Label</label> | ||
<sl-progress-ring ariaLabelledBy="labelledby" value="25"></sl-progress-ring> | ||
` | ||
); | ||
}); | ||
|
||
it('should render a component that passes accessibility test.', async () => { | ||
await expect(el).to.be.accessible(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import { LitElement, html } from 'lit'; | ||
import { customElement, property, query, state } from 'lit/decorators.js'; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
import styles from './progress-ring.styles'; | ||
|
||
/** | ||
|
@@ -27,6 +28,15 @@ export default class SlProgressRing extends LitElement { | |
/** The current progress, 0 to 100. */ | ||
@property({ type: Number, reflect: true }) value = 0; | ||
|
||
/** When set, will place a hoverable title on the progress ring. */ | ||
@property() title: string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will technically put a |
||
|
||
/** When set, will place a label on the progress ring. */ | ||
@property() ariaLabel: string; | ||
|
||
/** When set, will place a labelledby on the progress ring. */ | ||
@property() ariaLabelledBy: string; | ||
|
||
updated(changedProps: Map<string, any>) { | ||
super.updated(changedProps); | ||
|
||
|
@@ -50,6 +60,9 @@ export default class SlProgressRing extends LitElement { | |
part="base" | ||
class="progress-ring" | ||
role="progressbar" | ||
title=${ifDefined(this.title)} | ||
aria-label=${ifDefined(this.ariaLabel)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far I've avoided using aria-like attributes as part of Shoelace's API. In some components, you'll see |
||
aria-labelledby=${ifDefined(this.ariaLabelledBy)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this will work since the property is defined on the host (light DOM) and the aria attribute is on the base part (shadow DOM). One way to make this "just work" is to remove the base part and make the If that sounds like a good idea, let me know and I'll merge this and make those updates. 😄 |
||
aria-valuemin="0" | ||
aria-valuemax="100" | ||
aria-valuenow="${this.value}" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default progress isn't accessible, should this be reflected in the documentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For others reading, the test fails with:
Would using a localized term such as "Progress" be a good default? Seems better than nothing. Then the user can choose to customize it with something more specific, e.g. "File upload progress".