sass-references/angular-material/material/list/testing/list-harness-base.ts

182 lines
6.6 KiB
TypeScript

/**
* @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,
HarnessPredicate,
parallel,
} from '@angular/cdk/testing';
import {DividerHarnessFilters, MatDividerHarness} from '@angular/material/divider/testing';
import {BaseListItemHarnessFilters, SubheaderHarnessFilters} from './list-harness-filters';
import {MatSubheaderHarness} from './list-item-harness-base';
/** Represents a section of a list falling under a specific header. */
export interface ListSection<I> {
/** The heading for this list section. `undefined` if there is no heading. */
heading?: string;
/** The items in this list section. */
items: I[];
}
/**
* Shared behavior among the harnesses for the various `MatList` flavors.
* @template T A constructor type for a list item harness type used by this list harness.
* @template C The list item harness type that `T` constructs.
* @template F The filter type used filter list item harness of type `C`.
* @docs-private
*/
export abstract class MatListHarnessBase<
T extends ComponentHarnessConstructor<C> & {with: (options?: F) => HarnessPredicate<C>},
C extends ComponentHarness,
F extends BaseListItemHarnessFilters,
> extends ComponentHarness {
protected _itemHarness: T;
/**
* Gets a list of harnesses representing the items in this list.
* @param filters Optional filters used to narrow which harnesses are included
* @return The list of items matching the given filters.
*/
async getItems(filters?: F): Promise<C[]> {
return this.locatorForAll(this._itemHarness.with(filters))();
}
/**
* Gets a list of `ListSection` representing the list items grouped by subheaders. If the list has
* no subheaders it is represented as a single `ListSection` with an undefined `heading` property.
* @param filters Optional filters used to narrow which list item harnesses are included
* @return The list of items matching the given filters, grouped into sections by subheader.
*/
async getItemsGroupedBySubheader(filters?: F): Promise<ListSection<C>[]> {
type Section = {items: C[]; heading?: Promise<string>};
const listSections: Section[] = [];
let currentSection: Section = {items: []};
const itemsAndSubheaders = await this.getItemsWithSubheadersAndDividers({
item: filters,
divider: false,
});
for (const itemOrSubheader of itemsAndSubheaders) {
if (itemOrSubheader instanceof MatSubheaderHarness) {
if (currentSection.heading !== undefined || currentSection.items.length) {
listSections.push(currentSection);
}
currentSection = {heading: itemOrSubheader.getText(), items: []};
} else {
currentSection.items.push(itemOrSubheader);
}
}
if (
currentSection.heading !== undefined ||
currentSection.items.length ||
!listSections.length
) {
listSections.push(currentSection);
}
// Concurrently wait for all sections to resolve their heading if present.
return parallel(() =>
listSections.map(async s => ({items: s.items, heading: await s.heading})),
);
}
/**
* Gets a list of sub-lists representing the list items grouped by dividers. If the list has no
* dividers it is represented as a list with a single sub-list.
* @param filters Optional filters used to narrow which list item harnesses are included
* @return The list of items matching the given filters, grouped into sub-lists by divider.
*/
async getItemsGroupedByDividers(filters?: F): Promise<C[][]> {
const listSections: C[][] = [[]];
const itemsAndDividers = await this.getItemsWithSubheadersAndDividers({
item: filters,
subheader: false,
});
for (const itemOrDivider of itemsAndDividers) {
if (itemOrDivider instanceof MatDividerHarness) {
listSections.push([]);
} else {
listSections[listSections.length - 1].push(itemOrDivider);
}
}
return listSections;
}
/**
* Gets a list of harnesses representing all of the items, subheaders, and dividers
* (in the order they appear in the list). Use `instanceof` to check which type of harness a given
* item is.
* @param filters Optional filters used to narrow which list items, subheaders, and dividers are
* included. A value of `false` for the `item`, `subheader`, or `divider` properties indicates
* that the respective harness type should be omitted completely.
* @return The list of harnesses representing the items, subheaders, and dividers matching the
* given filters.
*/
getItemsWithSubheadersAndDividers(filters: {
item: false;
subheader: false;
divider: false;
}): Promise<[]>;
getItemsWithSubheadersAndDividers(filters: {
item?: F | false;
subheader: false;
divider: false;
}): Promise<C[]>;
getItemsWithSubheadersAndDividers(filters: {
item: false;
subheader?: SubheaderHarnessFilters | false;
divider: false;
}): Promise<MatSubheaderHarness[]>;
getItemsWithSubheadersAndDividers(filters: {
item: false;
subheader: false;
divider?: DividerHarnessFilters | false;
}): Promise<MatDividerHarness[]>;
getItemsWithSubheadersAndDividers(filters: {
item?: F | false;
subheader?: SubheaderHarnessFilters | false;
divider: false;
}): Promise<(C | MatSubheaderHarness)[]>;
getItemsWithSubheadersAndDividers(filters: {
item?: F | false;
subheader: false;
divider?: false | DividerHarnessFilters;
}): Promise<(C | MatDividerHarness)[]>;
getItemsWithSubheadersAndDividers(filters: {
item: false;
subheader?: false | SubheaderHarnessFilters;
divider?: false | DividerHarnessFilters;
}): Promise<(MatSubheaderHarness | MatDividerHarness)[]>;
getItemsWithSubheadersAndDividers(filters?: {
item?: F | false;
subheader?: SubheaderHarnessFilters | false;
divider?: DividerHarnessFilters | false;
}): Promise<(C | MatSubheaderHarness | MatDividerHarness)[]>;
async getItemsWithSubheadersAndDividers(
filters: {
item?: F | false;
subheader?: SubheaderHarnessFilters | false;
divider?: DividerHarnessFilters | false;
} = {},
): Promise<(C | MatSubheaderHarness | MatDividerHarness)[]> {
const query = [];
if (filters.item !== false) {
query.push(this._itemHarness.with(filters.item || ({} as F)));
}
if (filters.subheader !== false) {
query.push(MatSubheaderHarness.with(filters.subheader));
}
if (filters.divider !== false) {
query.push(MatDividerHarness.with(filters.divider));
}
return this.locatorForAll(...query)();
}
}