From 63afee08e696a698aad577691080d22d664b7747 Mon Sep 17 00:00:00 2001 From: Cheng-Hsuan Tsai Date: Mon, 4 May 2026 06:23:54 +0000 Subject: [PATCH 1/2] feat(aria/combobox): add test harnesses --- .../aria/simple-combobox/testing/index.api.md | 47 ++++ src/aria/config.bzl | 1 + src/aria/simple-combobox/testing/BUILD.bazel | 43 ++++ src/aria/simple-combobox/testing/index.ts | 9 + .../simple-combobox/testing/public-api.ts | 10 + .../simple-combobox-harness-filters.ts | 19 ++ .../testing/simple-combobox-harness.spec.ts | 200 ++++++++++++++++++ .../testing/simple-combobox-harness.ts | 153 ++++++++++++++ 8 files changed, 482 insertions(+) create mode 100644 goldens/aria/simple-combobox/testing/index.api.md create mode 100644 src/aria/simple-combobox/testing/BUILD.bazel create mode 100644 src/aria/simple-combobox/testing/index.ts create mode 100644 src/aria/simple-combobox/testing/public-api.ts create mode 100644 src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts create mode 100644 src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts create mode 100644 src/aria/simple-combobox/testing/simple-combobox-harness.ts diff --git a/goldens/aria/simple-combobox/testing/index.api.md b/goldens/aria/simple-combobox/testing/index.api.md new file mode 100644 index 000000000000..0bf5e239ac1e --- /dev/null +++ b/goldens/aria/simple-combobox/testing/index.api.md @@ -0,0 +1,47 @@ +## API Report File for "@angular/aria_simple-combobox_testing" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BaseHarnessFilters } from '@angular/cdk/testing'; +import { ComponentHarness } from '@angular/cdk/testing'; +import { ComponentHarnessConstructor } from '@angular/cdk/testing'; +import { ContentContainerComponentHarness } from '@angular/cdk/testing'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { HarnessPredicate } from '@angular/cdk/testing'; + +// @public +export class SimpleComboboxHarness extends ContentContainerComponentHarness { + blur(): Promise; + close(): Promise; + focus(): Promise; + getPlaceholder(): Promise; + getPopupLoader(): Promise; + getPopupWidget(type: ComponentHarnessConstructor & { + with: (options?: { + selector?: string; + }) => HarnessPredicate; + }): Promise; + protected getRootHarnessLoader(): Promise; + getValue(): Promise; + // (undocumented) + static hostSelector: string; + isDisabled(): Promise; + isFocused(): Promise; + isOpen(): Promise; + open(): Promise; + setValue(value: string): Promise; + static with(options?: SimpleComboboxHarnessFilters): HarnessPredicate; +} + +// @public +export interface SimpleComboboxHarnessFilters extends BaseHarnessFilters { + disabled?: boolean; + placeholder?: string | RegExp; + value?: string | RegExp; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/src/aria/config.bzl b/src/aria/config.bzl index 0e0578591b51..480c93fad6d5 100644 --- a/src/aria/config.bzl +++ b/src/aria/config.bzl @@ -10,6 +10,7 @@ ARIA_ENTRYPOINTS = [ "menu", "menu/testing", "simple-combobox", + "simple-combobox/testing", "tabs", "tabs/testing", "toolbar", diff --git a/src/aria/simple-combobox/testing/BUILD.bazel b/src/aria/simple-combobox/testing/BUILD.bazel new file mode 100644 index 000000000000..38540ebe2f98 --- /dev/null +++ b/src/aria/simple-combobox/testing/BUILD.bazel @@ -0,0 +1,43 @@ +load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite", "ts_project") + +package(default_visibility = ["//visibility:public"]) + +ts_project( + name = "testing", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), + deps = [ + "//:node_modules/@angular/core", + "//src/cdk/testing", + ], +) + +filegroup( + name = "source-files", + srcs = glob(["**/*.ts"]), +) + +ng_project( + name = "unit_tests_lib", + testonly = True, + srcs = glob(["**/*.spec.ts"]), + deps = [ + ":testing", + "//:node_modules/@angular/core", + "//src/aria/listbox", + "//src/aria/listbox/testing", + "//src/aria/simple-combobox", + "//src/cdk/overlay", + "//src/cdk/testing", + "//src/cdk/testing/testbed", + ], +) + +ng_web_test_suite( + name = "unit_tests", + deps = [ + ":unit_tests_lib", + ], +) diff --git a/src/aria/simple-combobox/testing/index.ts b/src/aria/simple-combobox/testing/index.ts new file mode 100644 index 000000000000..52b3c7a5156f --- /dev/null +++ b/src/aria/simple-combobox/testing/index.ts @@ -0,0 +1,9 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export * from './public-api'; diff --git a/src/aria/simple-combobox/testing/public-api.ts b/src/aria/simple-combobox/testing/public-api.ts new file mode 100644 index 000000000000..fc6f93d56c23 --- /dev/null +++ b/src/aria/simple-combobox/testing/public-api.ts @@ -0,0 +1,10 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export * from './simple-combobox-harness'; +export * from './simple-combobox-harness-filters'; diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts b/src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts new file mode 100644 index 000000000000..0d375735797e --- /dev/null +++ b/src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {BaseHarnessFilters} from '@angular/cdk/testing'; + +/** A set of criteria that can be used to filter a list of `SimpleComboboxHarness` instances. */ +export interface SimpleComboboxHarnessFilters extends BaseHarnessFilters { + /** Only find instances whose placeholder matches the given value. */ + placeholder?: string | RegExp; + /** Only find instances whose value matches the given value. */ + value?: string | RegExp; + /** Only find instances with the given disabled state. */ + disabled?: boolean; +} diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts b/src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts new file mode 100644 index 000000000000..904837d2d4fa --- /dev/null +++ b/src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts @@ -0,0 +1,200 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Component, signal} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {HarnessLoader} from '@angular/cdk/testing'; +import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; +import {Combobox, ComboboxPopup, ComboboxWidget} from '../index'; +import {Listbox, Option} from '../../listbox'; +import {ListboxHarness, ListboxOptionHarness} from '../../listbox/testing/listbox-harness'; +import {SimpleComboboxHarness} from './simple-combobox-harness'; +import {OverlayModule} from '@angular/cdk/overlay'; + +describe('SimpleComboboxHarness', () => { + let fixture: ComponentFixture; + let loader: HarnessLoader; + + function setupTest(component: any) { + fixture = TestBed.createComponent(component); + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + } + + describe('Basic usage', () => { + beforeEach(() => setupTest(SimpleComboboxTestApp)); + + it('should load combobox harness', async () => { + await expectAsync(loader.getHarness(SimpleComboboxHarness)).toBeResolved(); + }); + + it('should get and set values', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + await combobox.setValue('California'); + fixture.detectChanges(); + + expect(await combobox.getValue()).toBe('California'); + }); + + it('should correctly report disabled state', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + expect(await combobox.isDisabled()).toBeFalse(); + + fixture.componentInstance.disabled.set(true); + fixture.detectChanges(); + + expect(await combobox.isDisabled()).toBeTrue(); + }); + + it('should open and close the popup', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + expect(await combobox.isOpen()).toBeFalse(); + + await combobox.open(); + fixture.detectChanges(); + expect(await combobox.isOpen()).toBeTrue(); + + await combobox.close(); + fixture.detectChanges(); + expect(await combobox.isOpen()).toBeFalse(); + }); + + it('should allow loading nested harnesses within the popup content via unified container API', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + await combobox.open(); + fixture.detectChanges(); + + // We access the main widget harness using getPopupWidget. + const listbox = await combobox.getPopupWidget(ListboxHarness); + const options = await listbox.getOptions(); + expect(options.length).toBe(3); + }); + + it('should fail to resolve nested items when closed', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + // Popup isn't open yet, so getPopupWidget should fail. + await expectAsync(combobox.getPopupWidget(ListboxHarness)).toBeRejectedWithError( + /Cannot retrieve popup content because the combobox is closed/, + ); + }); + + it('should support getting explicit popup loader for descendant matching', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + await combobox.open(); + fixture.detectChanges(); + + const popupLoader = await combobox.getPopupLoader(); + // We are testing that the loader works for finding actual children (Options). + const option = await popupLoader.getHarness(ListboxOptionHarness); + expect(option).toBeDefined(); + }); + + it('should support focusing and blurring', async () => { + const combobox = await loader.getHarness(SimpleComboboxHarness); + await combobox.focus(); + expect(await combobox.isFocused()).toBeTrue(); + + await combobox.blur(); + expect(await combobox.isFocused()).toBeFalse(); + }); + }); + + describe('Overlay and Popover integrations', () => { + it('should find and resolve harnesses nested inside standard CdkOverlay', async () => { + setupTest(SimpleComboboxOverlayTestApp); + const combobox = await loader.getHarness(SimpleComboboxHarness); + + await combobox.open(); + fixture.detectChanges(); + + // Should find listbox inside the dynamically attached cdk overlay root container + const listbox = await combobox.getPopupWidget(ListboxHarness); + expect(listbox).toBeDefined(); + expect((await listbox.getOptions()).length).toBe(2); + }); + + it('should resolve nested harnesses when using Native Popover API', async () => { + setupTest(SimpleComboboxNativePopoverTestApp); + const combobox = await loader.getHarness(SimpleComboboxHarness); + + await combobox.open(); + fixture.detectChanges(); + + const listbox = await combobox.getPopupWidget(ListboxHarness); + expect(listbox).toBeDefined(); + expect((await listbox.getOptions()).length).toBe(2); + }); + }); +}); + +@Component({ + template: ` +
+ + + +
+
California
+
Washington
+
Oregon
+
+
+
+ `, + imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option], +}) +class SimpleComboboxTestApp { + disabled = signal(false); +} + +@Component({ + template: ` +
+ +
+ + + +
+
A
+
B
+
+
+
+ `, + imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option, OverlayModule], +}) +class SimpleComboboxOverlayTestApp { + popupExpanded = signal(false); +} + +@Component({ + template: ` +
+ +
+ + + +
+
A
+
B
+
+
+
+ `, + imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option, OverlayModule], +}) +class SimpleComboboxNativePopoverTestApp { + popupExpanded = signal(false); +} diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness.ts b/src/aria/simple-combobox/testing/simple-combobox-harness.ts new file mode 100644 index 000000000000..5ffaf7abcbe5 --- /dev/null +++ b/src/aria/simple-combobox/testing/simple-combobox-harness.ts @@ -0,0 +1,153 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + ComponentHarness, + ComponentHarnessConstructor, + ContentContainerComponentHarness, + HarnessLoader, + HarnessPredicate, + TestKey, +} from '@angular/cdk/testing'; +import {SimpleComboboxHarnessFilters} from './simple-combobox-harness-filters'; + +/** Harness for interacting with a standard `ngCombobox` input element in tests. */ +export class SimpleComboboxHarness extends ContentContainerComponentHarness { + static hostSelector = '[ngCombobox]'; + + /** + * Gets a `HarnessPredicate` that can be used to search for a combobox with specific attributes. + * @param options Options for filtering which combobox instances are considered a match. + * @return a `HarnessPredicate` configured with the given options. + */ + static with(options: SimpleComboboxHarnessFilters = {}): HarnessPredicate { + return new HarnessPredicate(SimpleComboboxHarness, options) + .addOption('placeholder', options.placeholder, async (harness, placeholder) => + HarnessPredicate.stringMatches(await harness.getPlaceholder(), placeholder), + ) + .addOption('value', options.value, async (harness, value) => + HarnessPredicate.stringMatches(await harness.getValue(), value), + ) + .addOption( + 'disabled', + options.disabled, + async (harness, disabled) => (await harness.isDisabled()) === disabled, + ); + } + + /** + * Gets the component harness for the active widget contained inside the popup. + * Use this when you need to access the harness of the widget itself (e.g., `ListboxHarness`), + * rather than querying items within it. + * @param type The harness type to locate. Must implement standard static `.with()` method. + */ + async getPopupWidget( + type: ComponentHarnessConstructor & { + with: (options?: {selector?: string}) => HarnessPredicate; + }, + ): Promise { + const host = await this.host(); + const controlsId = await host.getAttribute('aria-controls'); + if (!controlsId) { + throw new Error( + 'Cannot retrieve popup content because the combobox is closed or not associated with a popup controls ID.', + ); + } + return this.documentRootLocatorFactory().locatorFor(type.with({selector: `#${controlsId}`}))(); + } + + /** + * Gets a harness loader scoped to the content inside the popup container. + * Note that lookups performed by this loader will only find descendants of the popup container. + */ + async getPopupLoader(): Promise { + return this.getRootHarnessLoader(); + } + + /** Overrides root loader to automatically resolve queries nested inside the associated popup. */ + protected override async getRootHarnessLoader(): Promise { + const host = await this.host(); + const controlsId = await host.getAttribute('aria-controls'); + if (!controlsId) { + throw new Error( + 'Cannot retrieve popup content because the combobox is closed or not associated with a popup controls ID.', + ); + } + const documentRoot = await this.documentRootLocatorFactory().rootHarnessLoader(); + // Locate the widget by ID, which was assigned by ngComboboxWidget and linked via aria-controls. + return documentRoot.getChildLoader(`#${controlsId}`); + } + + /** Whether the combobox is expanded (popup is open). */ + async isOpen(): Promise { + const host = await this.host(); + return (await host.getAttribute('aria-expanded')) === 'true'; + } + + /** Whether the combobox is disabled. */ + async isDisabled(): Promise { + const host = await this.host(); + return (await host.getAttribute('aria-disabled')) === 'true'; + } + + /** Gets the current value string of the combobox input. */ + async getValue(): Promise { + const host = await this.host(); + return host.getProperty('value'); + } + + /** Sets the value of the combobox input. */ + async setValue(value: string): Promise { + const host = await this.host(); + await host.clear(); + if (value) { + await host.sendKeys(value); + } + // Trigger simulated standard input pipeline. + await host.dispatchEvent('input'); + } + + /** Gets the placeholder text of the combobox. */ + async getPlaceholder(): Promise { + const host = await this.host(); + return host.getAttribute('placeholder'); + } + + /** Opens the combobox popup if it is currently closed. */ + async open(): Promise { + if (!(await this.isOpen())) { + const host = await this.host(); + await host.focus(); + await host.sendKeys(TestKey.DOWN_ARROW); + } + } + + /** Closes the combobox popup if it is currently open. */ + async close(): Promise { + if (await this.isOpen()) { + const host = await this.host(); + await host.focus(); + await host.sendKeys(TestKey.ESCAPE); + } + } + + /** Focuses the combobox. */ + async focus(): Promise { + return (await this.host()).focus(); + } + + /** Blurs the combobox. */ + async blur(): Promise { + return (await this.host()).blur(); + } + + /** Whether the combobox has focus. */ + async isFocused(): Promise { + return (await this.host()).isFocused(); + } +} From d4b53ef0c8bb067cd956c173b77280cf81b3b1b1 Mon Sep 17 00:00:00 2001 From: Cheng-Hsuan Tsai Date: Mon, 4 May 2026 07:15:02 +0000 Subject: [PATCH 2/2] fixup! feat(aria/combobox): add test harnesses --- .../aria/simple-combobox/testing/index.api.md | 6 ++-- ...filters.ts => combobox-harness-filters.ts} | 4 +-- ...rness.spec.ts => combobox-harness.spec.ts} | 36 +++++++++---------- ...ombobox-harness.ts => combobox-harness.ts} | 10 +++--- .../simple-combobox/testing/public-api.ts | 4 +-- 5 files changed, 29 insertions(+), 31 deletions(-) rename src/aria/simple-combobox/testing/{simple-combobox-harness-filters.ts => combobox-harness-filters.ts} (75%) rename src/aria/simple-combobox/testing/{simple-combobox-harness.spec.ts => combobox-harness.spec.ts} (84%) rename src/aria/simple-combobox/testing/{simple-combobox-harness.ts => combobox-harness.ts} (92%) diff --git a/goldens/aria/simple-combobox/testing/index.api.md b/goldens/aria/simple-combobox/testing/index.api.md index 0bf5e239ac1e..a9b87fd9d748 100644 --- a/goldens/aria/simple-combobox/testing/index.api.md +++ b/goldens/aria/simple-combobox/testing/index.api.md @@ -12,7 +12,7 @@ import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessPredicate } from '@angular/cdk/testing'; // @public -export class SimpleComboboxHarness extends ContentContainerComponentHarness { +export class ComboboxHarness extends ContentContainerComponentHarness { blur(): Promise; close(): Promise; focus(): Promise; @@ -32,11 +32,11 @@ export class SimpleComboboxHarness extends ContentContainerComponentHarness { isOpen(): Promise; open(): Promise; setValue(value: string): Promise; - static with(options?: SimpleComboboxHarnessFilters): HarnessPredicate; + static with(options?: ComboboxHarnessFilters): HarnessPredicate; } // @public -export interface SimpleComboboxHarnessFilters extends BaseHarnessFilters { +export interface ComboboxHarnessFilters extends BaseHarnessFilters { disabled?: boolean; placeholder?: string | RegExp; value?: string | RegExp; diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts b/src/aria/simple-combobox/testing/combobox-harness-filters.ts similarity index 75% rename from src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts rename to src/aria/simple-combobox/testing/combobox-harness-filters.ts index 0d375735797e..22013f276d3d 100644 --- a/src/aria/simple-combobox/testing/simple-combobox-harness-filters.ts +++ b/src/aria/simple-combobox/testing/combobox-harness-filters.ts @@ -8,8 +8,8 @@ import {BaseHarnessFilters} from '@angular/cdk/testing'; -/** A set of criteria that can be used to filter a list of `SimpleComboboxHarness` instances. */ -export interface SimpleComboboxHarnessFilters extends BaseHarnessFilters { +/** A set of criteria that can be used to filter a list of `ComboboxHarness` instances. */ +export interface ComboboxHarnessFilters extends BaseHarnessFilters { /** Only find instances whose placeholder matches the given value. */ placeholder?: string | RegExp; /** Only find instances whose value matches the given value. */ diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts b/src/aria/simple-combobox/testing/combobox-harness.spec.ts similarity index 84% rename from src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts rename to src/aria/simple-combobox/testing/combobox-harness.spec.ts index 904837d2d4fa..8b4ae5351d1a 100644 --- a/src/aria/simple-combobox/testing/simple-combobox-harness.spec.ts +++ b/src/aria/simple-combobox/testing/combobox-harness.spec.ts @@ -13,10 +13,10 @@ import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Combobox, ComboboxPopup, ComboboxWidget} from '../index'; import {Listbox, Option} from '../../listbox'; import {ListboxHarness, ListboxOptionHarness} from '../../listbox/testing/listbox-harness'; -import {SimpleComboboxHarness} from './simple-combobox-harness'; +import {ComboboxHarness} from './combobox-harness'; import {OverlayModule} from '@angular/cdk/overlay'; -describe('SimpleComboboxHarness', () => { +describe('ComboboxHarness', () => { let fixture: ComponentFixture; let loader: HarnessLoader; @@ -27,14 +27,14 @@ describe('SimpleComboboxHarness', () => { } describe('Basic usage', () => { - beforeEach(() => setupTest(SimpleComboboxTestApp)); + beforeEach(() => setupTest(ComboboxTestApp)); it('should load combobox harness', async () => { - await expectAsync(loader.getHarness(SimpleComboboxHarness)).toBeResolved(); + await expectAsync(loader.getHarness(ComboboxHarness)).toBeResolved(); }); it('should get and set values', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.setValue('California'); fixture.detectChanges(); @@ -42,7 +42,7 @@ describe('SimpleComboboxHarness', () => { }); it('should correctly report disabled state', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); expect(await combobox.isDisabled()).toBeFalse(); fixture.componentInstance.disabled.set(true); @@ -52,7 +52,7 @@ describe('SimpleComboboxHarness', () => { }); it('should open and close the popup', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); expect(await combobox.isOpen()).toBeFalse(); await combobox.open(); @@ -65,7 +65,7 @@ describe('SimpleComboboxHarness', () => { }); it('should allow loading nested harnesses within the popup content via unified container API', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.open(); fixture.detectChanges(); @@ -76,7 +76,7 @@ describe('SimpleComboboxHarness', () => { }); it('should fail to resolve nested items when closed', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); // Popup isn't open yet, so getPopupWidget should fail. await expectAsync(combobox.getPopupWidget(ListboxHarness)).toBeRejectedWithError( /Cannot retrieve popup content because the combobox is closed/, @@ -84,7 +84,7 @@ describe('SimpleComboboxHarness', () => { }); it('should support getting explicit popup loader for descendant matching', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.open(); fixture.detectChanges(); @@ -95,7 +95,7 @@ describe('SimpleComboboxHarness', () => { }); it('should support focusing and blurring', async () => { - const combobox = await loader.getHarness(SimpleComboboxHarness); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.focus(); expect(await combobox.isFocused()).toBeTrue(); @@ -106,8 +106,8 @@ describe('SimpleComboboxHarness', () => { describe('Overlay and Popover integrations', () => { it('should find and resolve harnesses nested inside standard CdkOverlay', async () => { - setupTest(SimpleComboboxOverlayTestApp); - const combobox = await loader.getHarness(SimpleComboboxHarness); + setupTest(ComboboxOverlayTestApp); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.open(); fixture.detectChanges(); @@ -119,8 +119,8 @@ describe('SimpleComboboxHarness', () => { }); it('should resolve nested harnesses when using Native Popover API', async () => { - setupTest(SimpleComboboxNativePopoverTestApp); - const combobox = await loader.getHarness(SimpleComboboxHarness); + setupTest(ComboboxNativePopoverTestApp); + const combobox = await loader.getHarness(ComboboxHarness); await combobox.open(); fixture.detectChanges(); @@ -153,7 +153,7 @@ describe('SimpleComboboxHarness', () => { `, imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option], }) -class SimpleComboboxTestApp { +class ComboboxTestApp { disabled = signal(false); } @@ -174,7 +174,7 @@ class SimpleComboboxTestApp { `, imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option, OverlayModule], }) -class SimpleComboboxOverlayTestApp { +class ComboboxOverlayTestApp { popupExpanded = signal(false); } @@ -195,6 +195,6 @@ class SimpleComboboxOverlayTestApp { `, imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option, OverlayModule], }) -class SimpleComboboxNativePopoverTestApp { +class ComboboxNativePopoverTestApp { popupExpanded = signal(false); } diff --git a/src/aria/simple-combobox/testing/simple-combobox-harness.ts b/src/aria/simple-combobox/testing/combobox-harness.ts similarity index 92% rename from src/aria/simple-combobox/testing/simple-combobox-harness.ts rename to src/aria/simple-combobox/testing/combobox-harness.ts index 5ffaf7abcbe5..c13a53b69634 100644 --- a/src/aria/simple-combobox/testing/simple-combobox-harness.ts +++ b/src/aria/simple-combobox/testing/combobox-harness.ts @@ -14,10 +14,10 @@ import { HarnessPredicate, TestKey, } from '@angular/cdk/testing'; -import {SimpleComboboxHarnessFilters} from './simple-combobox-harness-filters'; +import {ComboboxHarnessFilters} from './combobox-harness-filters'; /** Harness for interacting with a standard `ngCombobox` input element in tests. */ -export class SimpleComboboxHarness extends ContentContainerComponentHarness { +export class ComboboxHarness extends ContentContainerComponentHarness { static hostSelector = '[ngCombobox]'; /** @@ -25,8 +25,8 @@ export class SimpleComboboxHarness extends ContentContainerComponentHarness { * @param options Options for filtering which combobox instances are considered a match. * @return a `HarnessPredicate` configured with the given options. */ - static with(options: SimpleComboboxHarnessFilters = {}): HarnessPredicate { - return new HarnessPredicate(SimpleComboboxHarness, options) + static with(options: ComboboxHarnessFilters = {}): HarnessPredicate { + return new HarnessPredicate(ComboboxHarness, options) .addOption('placeholder', options.placeholder, async (harness, placeholder) => HarnessPredicate.stringMatches(await harness.getPlaceholder(), placeholder), ) @@ -108,8 +108,6 @@ export class SimpleComboboxHarness extends ContentContainerComponentHarness { if (value) { await host.sendKeys(value); } - // Trigger simulated standard input pipeline. - await host.dispatchEvent('input'); } /** Gets the placeholder text of the combobox. */ diff --git a/src/aria/simple-combobox/testing/public-api.ts b/src/aria/simple-combobox/testing/public-api.ts index fc6f93d56c23..46b2e5953146 100644 --- a/src/aria/simple-combobox/testing/public-api.ts +++ b/src/aria/simple-combobox/testing/public-api.ts @@ -6,5 +6,5 @@ * found in the LICENSE file at https://angular.dev/license */ -export * from './simple-combobox-harness'; -export * from './simple-combobox-harness-filters'; +export * from './combobox-harness'; +export * from './combobox-harness-filters';