Skip to content

Commit e78e2fe

Browse files
committed
fix(ppi): improve widget accessibility
1 parent e12b5f8 commit e78e2fe

2 files changed

Lines changed: 39 additions & 27 deletions

File tree

‎src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/ppi-widget/ppi-widget.component.html‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@
4444
</div>
4545
}
4646
@case ('success') {
47-
<div class="ppi-widget">
48-
<span
49-
>{{ view.data?.submittedPercentage }}% of peers at your target grade have submitted</span
50-
>
51-
</div>
47+
<div
48+
class="ppi-widget"
49+
role="group"
50+
aria-label="Peer submission progress"
51+
>
52+
<span
53+
>{{ view.data?.submittedPercentage }}% of peers at your target grade have submitted</span
54+
>
55+
</div>
5256
}
5357
}

‎src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/ppi-widget/ppi-widget.component.spec.ts‎

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import {beforeEach, describe, expect, it, vi} from 'vitest';
2-
import {HttpErrorResponse} from '@angular/common/http';
3-
import {SimpleChange} from '@angular/core';
4-
import {ComponentFixture, TestBed} from '@angular/core/testing';
5-
import {MatButtonModule} from '@angular/material/button';
6-
import {MatIconModule} from '@angular/material/icon';
7-
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
8-
import {Observable, Subject, of, throwError} from 'rxjs';
9-
import {PeerProgressIndicator} from 'src/app/api/models/peer-progress-indicator';
10-
import {Task} from 'src/app/api/models/task';
11-
import {TaskDefinition} from 'src/app/api/models/task-definition';
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { HttpErrorResponse } from '@angular/common/http';
3+
import { SimpleChange } from '@angular/core';
4+
import { ComponentFixture, TestBed } from '@angular/core/testing';
5+
import { MatButtonModule } from '@angular/material/button';
6+
import { MatIconModule } from '@angular/material/icon';
7+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
8+
import { Observable, Subject, of, throwError } from 'rxjs';
9+
import { PeerProgressIndicator } from 'src/app/api/models/peer-progress-indicator';
10+
import { Task } from 'src/app/api/models/task';
11+
import { TaskDefinition } from 'src/app/api/models/task-definition';
1212
import {
1313
DISABLED_STATE,
1414
NORMAL_STATE,
@@ -17,24 +17,24 @@ import {
1717
UNAVAILABLE_STATE,
1818
ZERO_PERCENT_STATE,
1919
} from 'src/app/api/services/mock';
20-
import {PeerProgressIndicatorService} from 'src/app/api/services/peer-progress-indicator.service';
21-
import {PpiWidgetComponent} from './ppi-widget.component';
20+
import { PeerProgressIndicatorService } from 'src/app/api/services/peer-progress-indicator.service';
21+
import { PpiWidgetComponent } from './ppi-widget.component';
2222

2323
describe('PpiWidgetComponent', () => {
2424
let component: PpiWidgetComponent;
2525
let fixture: ComponentFixture<PpiWidgetComponent>;
2626
let getIndicator: ReturnType<typeof vi.fn>;
2727

28-
const mockTask = {project: {id: 7, unit: {id: 1}, targetGrade: 2}} as unknown as Task;
29-
const mockTaskDef = {id: 99} as unknown as TaskDefinition;
28+
const mockTask = { project: { id: 7, unit: { id: 1 }, targetGrade: 2 } } as unknown as Task;
29+
const mockTaskDef = { id: 99 } as unknown as TaskDefinition;
3030

3131
beforeEach(async () => {
3232
getIndicator = vi.fn();
3333

3434
await TestBed.configureTestingModule({
3535
declarations: [PpiWidgetComponent],
3636
imports: [MatIconModule, MatProgressSpinnerModule, MatButtonModule],
37-
providers: [{provide: PeerProgressIndicatorService, useValue: {getIndicator}}],
37+
providers: [{ provide: PeerProgressIndicatorService, useValue: { getIndicator } }],
3838
}).compileComponents();
3939

4040
fixture = TestBed.createComponent(PpiWidgetComponent);
@@ -45,7 +45,7 @@ describe('PpiWidgetComponent', () => {
4545

4646
function load(response$: Observable<PeerProgressIndicator>) {
4747
getIndicator.mockReturnValue(response$);
48-
component.ngOnChanges({task: new SimpleChange(null, mockTask, true)});
48+
component.ngOnChanges({ task: new SimpleChange(null, mockTask, true) });
4949
fixture.detectChanges();
5050
}
5151

@@ -61,6 +61,14 @@ describe('PpiWidgetComponent', () => {
6161
expect(fixture.nativeElement.textContent).toContain('42%');
6262
});
6363

64+
it('provides an accessible name for the peer progress widget', () => {
65+
load(of(NORMAL_STATE));
66+
67+
const widget = fixture.nativeElement.querySelector('.ppi-widget');
68+
expect(widget.getAttribute('role')).toBe('group');
69+
expect(widget.getAttribute('aria-label')).toBe('Peer submission progress');
70+
});
71+
6472
it('shows a rounded zero as data rather than unavailable', () => {
6573
load(of(ZERO_PERCENT_STATE));
6674
expect(component.view.state).toBe('no-data');
@@ -101,7 +109,7 @@ describe('PpiWidgetComponent', () => {
101109
const subject: Subject<PeerProgressIndicator> = new Subject();
102110
getIndicator.mockReturnValue(subject.asObservable());
103111

104-
component.ngOnChanges({task: new SimpleChange(null, mockTask, true)});
112+
component.ngOnChanges({ task: new SimpleChange(null, mockTask, true) });
105113
expect(component.view.state).toBe('loading');
106114

107115
subject.next(NORMAL_STATE);
@@ -114,13 +122,13 @@ describe('PpiWidgetComponent', () => {
114122
const subject: Subject<PeerProgressIndicator> = new Subject();
115123
getIndicator.mockReturnValue(subject.asObservable());
116124

117-
component.ngOnChanges({task: new SimpleChange(null, mockTask, true)});
125+
component.ngOnChanges({ task: new SimpleChange(null, mockTask, true) });
118126
expect(component.view.state).toBe('loading');
119127

120128
subject.error(
121129
new HttpErrorResponse({
122130
status,
123-
error: {error: 'Peer progress is unavailable for this project or task.'},
131+
error: { error: 'Peer progress is unavailable for this project or task.' },
124132
}),
125133
);
126134
fixture.detectChanges();
@@ -151,8 +159,8 @@ describe('PpiWidgetComponent', () => {
151159
.mockReturnValueOnce(first.asObservable())
152160
.mockReturnValueOnce(second.asObservable());
153161

154-
component.ngOnChanges({task: new SimpleChange(null, mockTask, true)});
155-
component.ngOnChanges({task: new SimpleChange(null, mockTask, true)});
162+
component.ngOnChanges({ task: new SimpleChange(null, mockTask, true) });
163+
component.ngOnChanges({ task: new SimpleChange(null, mockTask, true) });
156164

157165
first.next(NORMAL_STATE);
158166
expect(component.view.state).toBe('loading');

0 commit comments

Comments
 (0)