Skip to content

Commit a49508b

Browse files
authored
feat(aria/toolbar): add test harnesses (#33068)
Sets up test harnesses for the Aria toolbar.
1 parent 30f2239 commit a49508b

File tree

11 files changed

+414
-0
lines changed

11 files changed

+414
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
## API Report File for "@angular/aria_toolbar_testing"
2+
3+
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4+
5+
```ts
6+
7+
import { BaseHarnessFilters } from '@angular/cdk/testing';
8+
import { ComponentHarness } from '@angular/cdk/testing';
9+
import { ContentContainerComponentHarness } from '@angular/cdk/testing';
10+
import { HarnessPredicate } from '@angular/cdk/testing';
11+
12+
// @public
13+
export class ToolbarHarness extends ComponentHarness {
14+
getOrientation(): Promise<'vertical' | 'horizontal'>;
15+
getWidgetGroups(filters?: ToolbarWidgetGroupHarnessFilters): Promise<ToolbarWidgetGroupHarness[]>;
16+
getWidgets(filters?: ToolbarWidgetHarnessFilters): Promise<ToolbarWidgetHarness[]>;
17+
// (undocumented)
18+
static hostSelector: string;
19+
isDisabled(): Promise<boolean>;
20+
static with(options?: ToolbarHarnessFilters): HarnessPredicate<ToolbarHarness>;
21+
}
22+
23+
// @public
24+
export interface ToolbarHarnessFilters extends BaseHarnessFilters {
25+
}
26+
27+
// @public
28+
export class ToolbarWidgetGroupHarness extends ComponentHarness {
29+
getWidgets(filters?: ToolbarWidgetHarnessFilters): Promise<ToolbarWidgetHarness[]>;
30+
// (undocumented)
31+
static hostSelector: string;
32+
static with(options?: ToolbarWidgetGroupHarnessFilters): HarnessPredicate<ToolbarWidgetGroupHarness>;
33+
}
34+
35+
// @public
36+
export interface ToolbarWidgetGroupHarnessFilters extends BaseHarnessFilters {
37+
}
38+
39+
// @public
40+
export class ToolbarWidgetHarness extends ContentContainerComponentHarness<string> {
41+
click(): Promise<void>;
42+
getText(): Promise<string>;
43+
// (undocumented)
44+
static hostSelector: string;
45+
isActive(): Promise<boolean>;
46+
isDisabled(): Promise<boolean>;
47+
static with(options?: ToolbarWidgetHarnessFilters): HarnessPredicate<ToolbarWidgetHarness>;
48+
}
49+
50+
// @public
51+
export interface ToolbarWidgetHarnessFilters extends BaseHarnessFilters {
52+
active?: boolean;
53+
text?: string | RegExp;
54+
}
55+
56+
// (No @packageDocumentation comment for this package)
57+
58+
```

src/aria/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ARIA_ENTRYPOINTS = [
77
"menu",
88
"tabs",
99
"toolbar",
10+
"toolbar/testing",
1011
"tree",
1112
"tree/testing",
1213
"private",
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite", "ts_project")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ts_project(
6+
name = "testing",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
deps = [
12+
"//src/aria/toolbar",
13+
"//src/cdk/testing",
14+
],
15+
)
16+
17+
filegroup(
18+
name = "source-files",
19+
srcs = glob(["**/*.ts"]),
20+
)
21+
22+
ng_project(
23+
name = "unit_tests_lib",
24+
testonly = True,
25+
srcs = glob(["**/*.spec.ts"]),
26+
deps = [
27+
":testing",
28+
"//:node_modules/@angular/core",
29+
"//src/aria/toolbar",
30+
"//src/cdk/testing",
31+
"//src/cdk/testing/private",
32+
"//src/cdk/testing/testbed",
33+
],
34+
)
35+
36+
ng_web_test_suite(
37+
name = "unit_tests",
38+
deps = [":unit_tests_lib"],
39+
)

src/aria/toolbar/testing/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
export * from './public-api';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
export * from './toolbar-widget-harness';
10+
export * from './toolbar-widget-group-harness';
11+
export * from './toolbar-harness';
12+
export * from './toolbar-harness-filters';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {BaseHarnessFilters} from '@angular/cdk/testing';
10+
11+
/** A set of criteria that can be used to filter a list of Aria toolbar instances. */
12+
export interface ToolbarHarnessFilters extends BaseHarnessFilters {}
13+
14+
/** A set of criteria that can be used to filter a list of Aria toolbar widget group instances. */
15+
export interface ToolbarWidgetGroupHarnessFilters extends BaseHarnessFilters {}
16+
17+
/** A set of criteria that can be used to filter a list of Aria toolbar widgets. */
18+
export interface ToolbarWidgetHarnessFilters extends BaseHarnessFilters {
19+
/** Text that the widget should match. */
20+
text?: string | RegExp;
21+
22+
/** Active state that the widget should match. */
23+
active?: boolean;
24+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import {Component, signal} from '@angular/core';
2+
import {ComponentFixture, TestBed} from '@angular/core/testing';
3+
import {HarnessLoader, parallel} from '@angular/cdk/testing';
4+
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
5+
import {Toolbar} from '../toolbar';
6+
import {ToolbarWidget} from '../toolbar-widget';
7+
import {ToolbarWidgetGroup} from '../toolbar-widget-group';
8+
import {ToolbarHarness} from './toolbar-harness';
9+
import {ToolbarWidgetGroupHarness} from './toolbar-widget-group-harness';
10+
import {ToolbarWidgetHarness} from './toolbar-widget-harness';
11+
12+
describe('ToolbarHarness', () => {
13+
let fixture: ComponentFixture<ToolbarHarnessTest>;
14+
let loader: HarnessLoader;
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ToolbarHarnessTest);
18+
fixture.detectChanges();
19+
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
20+
});
21+
22+
it('should be able to load toolbar harnesses', async () => {
23+
const harnesses = await loader.getAllHarnesses(ToolbarHarness);
24+
expect(harnesses.length).toBe(1);
25+
});
26+
27+
it('should be able to load toolbar widget group harnesses', async () => {
28+
const harnesses = await loader.getAllHarnesses(ToolbarWidgetGroupHarness);
29+
expect(harnesses.length).toBe(2);
30+
});
31+
32+
it('should be able to load toolbar widget harnesses', async () => {
33+
const harnesses = await loader.getAllHarnesses(ToolbarWidgetHarness);
34+
expect(harnesses.length).toBe(8);
35+
});
36+
37+
it('should be able to get the widgets in a toolbar', async () => {
38+
const toolbar = await loader.getHarness(ToolbarHarness);
39+
const widgets = await toolbar.getWidgets();
40+
expect(widgets.length).toBe(8);
41+
});
42+
43+
it('should be able to get the widget groups in a toolbar', async () => {
44+
const toolbar = await loader.getHarness(ToolbarHarness);
45+
const groups = await toolbar.getWidgetGroups();
46+
expect(groups.length).toBe(2);
47+
});
48+
49+
it('should be able to get the toolbar orientation', async () => {
50+
const toolbar = await loader.getHarness(ToolbarHarness);
51+
expect(await toolbar.getOrientation()).toBe('horizontal');
52+
53+
fixture.componentInstance.orientation.set('vertical');
54+
expect(await toolbar.getOrientation()).toBe('vertical');
55+
});
56+
57+
it('should be able to get whether the toolbar is disabled', async () => {
58+
const toolbar = await loader.getHarness(ToolbarHarness);
59+
expect(await toolbar.isDisabled()).toBe(false);
60+
61+
fixture.componentInstance.toolbarDisabled.set(true);
62+
expect(await toolbar.isDisabled()).toBe(true);
63+
});
64+
65+
it('should be able to get the widgets in a widget group', async () => {
66+
const group = await loader.getHarness(ToolbarWidgetGroupHarness);
67+
const widgets = await group.getWidgets();
68+
expect(widgets.length).toBe(3);
69+
});
70+
71+
it('should be able to load a widget harness by text', async () => {
72+
const harnesses = await loader.getAllHarnesses(ToolbarWidgetHarness.with({text: /^Align/}));
73+
expect(harnesses.length).toBe(3);
74+
expect(await parallel(() => harnesses.map(harness => harness.getText()))).toEqual([
75+
'Align left',
76+
'Align center',
77+
'Align right',
78+
]);
79+
});
80+
81+
it('should be able to toggle the active state of a widget', async () => {
82+
const widget = await loader.getHarness(ToolbarWidgetHarness.with({text: 'Align left'}));
83+
expect(await widget.isActive()).toBe(false);
84+
85+
await widget.click();
86+
expect(await widget.isActive()).toBe(true);
87+
});
88+
89+
it('should be able to get whether a widget is disabled', async () => {
90+
const widget = await loader.getHarness(ToolbarWidgetHarness.with({text: 'Undo'}));
91+
expect(await widget.isDisabled()).toBe(false);
92+
93+
fixture.componentInstance.undoDisabled.set(true);
94+
expect(await widget.isDisabled()).toBe(true);
95+
});
96+
});
97+
98+
@Component({
99+
template: `
100+
<div ngToolbar [orientation]="orientation()" [disabled]="toolbarDisabled()">
101+
<button ngToolbarWidget value="undo" [disabled]="undoDisabled()">Undo</button>
102+
<button ngToolbarWidget value="redo">Redo</button>
103+
104+
<div ngToolbarWidgetGroup>
105+
<button ngToolbarWidget value="bold">Bold</button>
106+
<button ngToolbarWidget value="italic">Italic</button>
107+
<button ngToolbarWidget value="underlined">Underlined</button>
108+
</div>
109+
110+
<div ngToolbarWidgetGroup>
111+
<button ngToolbarWidget value="aling-left">Align left</button>
112+
<button ngToolbarWidget value="aling-center">Align center</button>
113+
<button ngToolbarWidget value="aling-right">Align right</button>
114+
</div>
115+
</div>
116+
`,
117+
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
118+
})
119+
class ToolbarHarnessTest {
120+
orientation = signal<'vertical' | 'horizontal'>('horizontal');
121+
toolbarDisabled = signal(false);
122+
undoDisabled = signal(false);
123+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {
11+
ToolbarHarnessFilters,
12+
ToolbarWidgetHarnessFilters,
13+
ToolbarWidgetGroupHarnessFilters,
14+
} from './toolbar-harness-filters';
15+
import {ToolbarWidgetHarness} from './toolbar-widget-harness';
16+
import {ToolbarWidgetGroupHarness} from './toolbar-widget-group-harness';
17+
18+
/** Harness for interacting with an Aria toolbar in tests. */
19+
export class ToolbarHarness extends ComponentHarness {
20+
static hostSelector = '[ngToolbar]';
21+
22+
/**
23+
* Gets a `HarnessPredicate` that can be used to search for a `ToolbarHarness`
24+
* that meets certain criteria.
25+
* @param options Options for filtering which dialog instances are considered a match.
26+
* @return a `HarnessPredicate` configured with the given options.
27+
*/
28+
static with(options: ToolbarHarnessFilters = {}): HarnessPredicate<ToolbarHarness> {
29+
return new HarnessPredicate(ToolbarHarness, options);
30+
}
31+
32+
/** Gets all widgets in the toolbar. */
33+
async getWidgets(filters: ToolbarWidgetHarnessFilters = {}): Promise<ToolbarWidgetHarness[]> {
34+
return await this.locatorForAll(ToolbarWidgetHarness.with(filters))();
35+
}
36+
37+
/** Gets all widget groups in the toolbar. */
38+
async getWidgetGroups(
39+
filters: ToolbarWidgetGroupHarnessFilters = {},
40+
): Promise<ToolbarWidgetGroupHarness[]> {
41+
return await this.locatorForAll(ToolbarWidgetGroupHarness.with(filters))();
42+
}
43+
44+
/** Gets whether the toolbar is disabled. */
45+
async isDisabled(): Promise<boolean> {
46+
const host = await this.host();
47+
return (await host.getAttribute('aria-disabled')) === 'true';
48+
}
49+
50+
/** Gets the orientation of the toolbar. */
51+
async getOrientation(): Promise<'vertical' | 'horizontal'> {
52+
const host = await this.host();
53+
return (await host.getAttribute('aria-orientation')) as 'vertical' | 'horizontal';
54+
}
55+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
10+
import {
11+
ToolbarWidgetHarnessFilters,
12+
ToolbarWidgetGroupHarnessFilters,
13+
} from './toolbar-harness-filters';
14+
import {ToolbarWidgetHarness} from './toolbar-widget-harness';
15+
16+
/** Harness for interacting with an Aria toolbar widget group in tests. */
17+
export class ToolbarWidgetGroupHarness extends ComponentHarness {
18+
static hostSelector = '[ngToolbarWidgetGroup]';
19+
20+
/**
21+
* Gets a `HarnessPredicate` that can be used to search for a `ToolbarWidgetGroupHarness`
22+
* that meets certain criteria.
23+
* @param options Options for filtering which dialog instances are considered a match.
24+
* @return a `HarnessPredicate` configured with the given options.
25+
*/
26+
static with(
27+
options: ToolbarWidgetGroupHarnessFilters = {},
28+
): HarnessPredicate<ToolbarWidgetGroupHarness> {
29+
return new HarnessPredicate(ToolbarWidgetGroupHarness, options);
30+
}
31+
32+
/** Gets all widgets in the group. */
33+
async getWidgets(filters: ToolbarWidgetHarnessFilters = {}): Promise<ToolbarWidgetHarness[]> {
34+
return await this.locatorForAll(ToolbarWidgetHarness.with(filters))();
35+
}
36+
}

0 commit comments

Comments
 (0)