Skip to content

feat(cdk/testing): add methods getOptionalHarness and hasHarness #24355

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

Merged
merged 1 commit into from
Feb 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/cdk/testing/component-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,31 @@ export interface HarnessLoader {
*/
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;

/**
* Searches for an instance of the component corresponding to the given harness type under the
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If multiple
* matching components are found, a harness for the first one is returned. If no matching
* component is found, null is returned.
* @param query A query for a harness to create
* @return An instance of the given harness type (or null if not found).
*/
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;

/**
* Searches for all instances of the component corresponding to the given harness type under the
* `HarnessLoader`'s root element, and returns a list `ComponentHarness` for each instance.
* @param query A query for a harness to create
* @return A list instances of the given harness type.
*/
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]>;

/**
* Searches for an instance of the component corresponding to the given harness type under the
* `HarnessLoader`'s root element, and returns a boolean indicating if any were found.
* @param query A query for a harness to create
* @return A boolean indicating if an instance was found.
*/
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
}

/**
Expand Down Expand Up @@ -403,10 +421,18 @@ export abstract class ContentContainerComponentHarness<S extends string = string
return (await this.getRootHarnessLoader()).getHarness(query);
}

async getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null> {
return (await this.getRootHarnessLoader()).getHarnessOrNull(query);
}

async getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]> {
return (await this.getRootHarnessLoader()).getAllHarnesses(query);
}

async hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean> {
return (await this.getRootHarnessLoader()).hasHarness(query);
}

/**
* Gets the root harness loader from which to start
* searching for content contained by this harness.
Expand Down
10 changes: 10 additions & 0 deletions src/cdk/testing/harness-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,21 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
return this.locatorFor(query)();
}

// Implemented as part of the `HarnessLoader` interface.
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null> {
return this.locatorForOptional(query)();
}

// Implemented as part of the `HarnessLoader` interface.
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]> {
return this.locatorForAll(query)();
}

// Implemented as part of the `HarnessLoader` interface.
async hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean> {
return (await this.locatorForOptional(query)()) !== null;
}

// Implemented as part of the `HarnessLoader` interface.
async getChildLoader(selector: string): Promise<HarnessLoader> {
return this.createEnvironment(
Expand Down
18 changes: 18 additions & 0 deletions src/cdk/testing/tests/cross-environment.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,28 @@ export function crossEnvironmentSpecs(
}
});

it('should get first matching component for optional harness', async () => {
const harness = await loader.getHarnessOrNull(SubComponentHarness);
expect(harness).not.toBeNull();
expect(await (await harness!.title()).text()).toBe('List of test tools');
});

it('should get null if no matching component found for optional harness', async () => {
const countersLoader = await loader.getChildLoader('.counters');
const harness = await countersLoader.getHarnessOrNull(SubComponentHarness);
expect(harness).toBeNull();
});

it('should get all matching components for all harnesses', async () => {
const harnesses = await loader.getAllHarnesses(SubComponentHarness);
expect(harnesses.length).toBe(4);
});

it('should check if harness is found', async () => {
const countersLoader = await loader.getChildLoader('.counters');
expect(await loader.hasHarness(SubComponentHarness)).toBe(true);
expect(await countersLoader.hasHarness(SubComponentHarness)).toBe(false);
});
});

describe('ComponentHarness', () => {
Expand Down
10 changes: 10 additions & 0 deletions tools/public_api_guard/cdk/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ export abstract class ContentContainerComponentHarness<S extends string = string
getChildLoader(selector: S): Promise<HarnessLoader>;
// (undocumented)
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
// (undocumented)
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
protected getRootHarnessLoader(): Promise<HarnessLoader>;
// (undocumented)
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
}

// @public
Expand Down Expand Up @@ -103,12 +107,16 @@ export abstract class HarnessEnvironment<E> implements HarnessLoader, LocatorFac
// (undocumented)
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
// (undocumented)
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
// (undocumented)
harnessLoaderFor(selector: string): Promise<HarnessLoader>;
// (undocumented)
harnessLoaderForAll(selector: string): Promise<HarnessLoader[]>;
// (undocumented)
harnessLoaderForOptional(selector: string): Promise<HarnessLoader | null>;
// (undocumented)
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
// (undocumented)
locatorFor<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>>;
// (undocumented)
locatorForAll<T extends (HarnessQuery<any> | string)[]>(...queries: T): AsyncFactoryFn<LocatorFnResult<T>[]>;
Expand All @@ -131,6 +139,8 @@ export interface HarnessLoader {
getAllHarnesses<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T[]>;
getChildLoader(selector: string): Promise<HarnessLoader>;
getHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T>;
getHarnessOrNull<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<T | null>;
hasHarness<T extends ComponentHarness>(query: HarnessQuery<T>): Promise<boolean>;
}

// @public
Expand Down