Skip to content
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

feat(material-experimental/mdc-card): add test harness #20298

Merged
merged 1 commit into from
Aug 14, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/material-experimental/config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ entryPoints = [
"mdc-button",
"mdc-button/testing",
"mdc-card",
"mdc-card/testing",
"mdc-checkbox",
"mdc-checkbox/testing",
"mdc-chips",
Expand Down
61 changes: 61 additions & 0 deletions src/material-experimental/mdc-card/testing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
load("//src/e2e-app:test_suite.bzl", "e2e_test_suite")
load("//tools:defaults.bzl", "ng_e2e_test_library", "ng_test_library", "ng_web_test_suite", "ts_library")

package(default_visibility = ["//visibility:public"])

ts_library(
name = "testing",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
module_name = "@angular/material-experimental/mdc-card/testing",
deps = [
"//src/cdk/testing",
],
)

filegroup(
name = "source-files",
srcs = glob(["**/*.ts"]),
)

ng_test_library(
name = "unit_tests_lib",
srcs = glob(
["**/*.spec.ts"],
exclude = [
"**/*.e2e.spec.ts",
"shared.spec.ts",
],
),
deps = [
":testing",
"//src/material-experimental/mdc-card",
"//src/material/card/testing:harness_tests_lib",
],
)

ng_web_test_suite(
name = "unit_tests",
deps = [":unit_tests_lib"],
)

ng_e2e_test_library(
name = "e2e_test_sources",
srcs = glob(["**/*.e2e.spec.ts"]),
deps = [
"//src/cdk/testing",
"//src/cdk/testing/private/e2e",
"//src/cdk/testing/protractor",
"//src/material-experimental/mdc-card/testing",
],
)

e2e_test_suite(
name = "e2e_tests",
deps = [
":e2e_test_sources",
"//src/cdk/testing/private/e2e",
],
)
19 changes: 19 additions & 0 deletions src/material-experimental/mdc-card/testing/card-harness-filters.ts
Original file line number Diff line number Diff line change
@@ -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.io/license
*/

import {BaseHarnessFilters} from '@angular/cdk/testing';

/** A set of criteria that can be used to filter a list of `MatCardHarness` instances. */
export interface CardHarnessFilters extends BaseHarnessFilters {
/** Only find instances whose text matches the given value. */
text?: string | RegExp;
/** Only find instances whose title matches the given value. */
title?: string | RegExp;
/** Only find instances whose subtitle matches the given value. */
subtitle?: string | RegExp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {HarnessLoader} from '@angular/cdk/testing';
import {ProtractorHarnessEnvironment} from '@angular/cdk/testing/protractor';
import {MatCardHarness} from '@angular/material-experimental/mdc-card/testing/card-harness';
import {browser} from 'protractor';

describe('card harness', () => {
let loader: HarnessLoader;

beforeEach(async () => await browser.get('/mdc-card'));

beforeEach(() => {
loader = ProtractorHarnessEnvironment.loader();
});

it('should get card text', async () => {
const card = await loader.getHarness(MatCardHarness);
expect(await card.getText()).toBe([
'Shiba Inu',
'Dog Breed',
'The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from' +
' Japan. A small, agile dog that copes very well with mountainous terrain, the Shiba Inu' +
' was originally bred for hunting.',
'LIKE',
'SHARE'
].join('\n'));
});

it('should get title text', async () => {
const card = await loader.getHarness(MatCardHarness);
expect(await card.getTitleText()).toBe('Shiba Inu');
});

it('should get subtitle text', async () => {
const card = await loader.getHarness(MatCardHarness);
expect(await card.getSubtitleText()).toBe('Dog Breed');
});
});
12 changes: 12 additions & 0 deletions src/material-experimental/mdc-card/testing/card-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {MatCardModule} from '@angular/material-experimental/mdc-card';
import {runHarnessTests} from '@angular/material/card/testing/shared.spec';
import {MatCardHarness, MatCardSection} from './card-harness';

describe('MDC-based MatCardHarness', () => {
runHarnessTests(MatCardModule, MatCardHarness as any, {
header: MatCardSection.HEADER,
content: MatCardSection.CONTENT,
actions: MatCardSection.ACTIONS,
footer: MatCardSection.FOOTER
});
});
59 changes: 59 additions & 0 deletions src/material-experimental/mdc-card/testing/card-harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @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.io/license
*/

import {HarnessPredicate, ContentContainerComponentHarness} from '@angular/cdk/testing';
import {CardHarnessFilters} from './card-harness-filters';

/** Selectors for different sections of the mat-card that can container user content. */
export const enum MatCardSection {
HEADER = '.mat-mdc-card-header',
CONTENT = '.mat-mdc-card-content',
ACTIONS = '.mat-mdc-card-actions',
FOOTER = '.mat-mdc-card-footer'
}

/** Harness for interacting with an MDC-based mat-card in tests. */
export class MatCardHarness extends ContentContainerComponentHarness<MatCardSection> {
/** The selector for the host element of a `MatCard` instance. */
static hostSelector = '.mat-mdc-card';

/**
* Gets a `HarnessPredicate` that can be used to search for a `MatCardHarness` that meets
* certain criteria.
* @param options Options for filtering which card instances are considered a match.
* @return a `HarnessPredicate` configured with the given options.
*/
static with(options: CardHarnessFilters = {}): HarnessPredicate<MatCardHarness> {
return new HarnessPredicate(MatCardHarness, options)
.addOption('text', options.text,
(harness, text) => HarnessPredicate.stringMatches(harness.getText(), text))
.addOption('title', options.title,
(harness, title) => HarnessPredicate.stringMatches(harness.getTitleText(), title))
.addOption('subtitle', options.subtitle,
(harness, subtitle) =>
HarnessPredicate.stringMatches(harness.getSubtitleText(), subtitle));
}

private _title = this.locatorForOptional('.mat-mdc-card-title');
private _subtitle = this.locatorForOptional('.mat-mdc-card-subtitle');

/** Gets all of the card's content as text. */
async getText(): Promise<string> {
return (await this.host()).text();
}

/** Gets the cards's title text. */
async getTitleText(): Promise<string> {
return (await this._title())?.text() ?? '';
}

/** Gets the cards's subtitle text. */
async getSubtitleText(): Promise<string> {
return (await this._subtitle())?.text() ?? '';
}
}
9 changes: 9 additions & 0 deletions src/material-experimental/mdc-card/testing/index.ts
Original file line number Diff line number Diff line change
@@ -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.io/license
*/

export * from './public-api';
10 changes: 10 additions & 0 deletions src/material-experimental/mdc-card/testing/public-api.ts
Original file line number Diff line number Diff line change
@@ -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.io/license
*/

export * from './card-harness';
export * from './card-harness-filters';
9 changes: 7 additions & 2 deletions src/material/card/testing/card-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import {MatCardModule} from '@angular/material/card';
import {runHarnessTests} from '@angular/material/card/testing/shared.spec';
import {MatCardHarness} from './card-harness';
import {MatCardHarness, MatCardSection} from './card-harness';

describe('Non-MDC-based MatCardHarness', () => {
runHarnessTests(MatCardModule, MatCardHarness);
runHarnessTests(MatCardModule, MatCardHarness, {
header: MatCardSection.HEADER,
content: MatCardSection.CONTENT,
actions: MatCardSection.ACTIONS,
footer: MatCardSection.FOOTER
});
});
12 changes: 7 additions & 5 deletions src/material/card/testing/shared.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {MatCardHarness, MatCardSection} from '@angular/material/card/testing/car

/** Shared tests to run on both the original and MDC-based cards. */
export function runHarnessTests(
cardModule: typeof MatCardModule, cardHarness: typeof MatCardHarness) {
cardModule: typeof MatCardModule,
cardHarness: typeof MatCardHarness,
contentSelectors: {header: string, content: string, actions: string, footer: string}) {
let fixture: ComponentFixture<CardHarnessTest>;
let loader: HarnessLoader;

Expand Down Expand Up @@ -73,28 +75,28 @@ export function runHarnessTests(

it('should get a harness loader for the card header', async () => {
const card = await loader.getHarness(cardHarness.with({title: 'Shiba Inu'}));
const headerLoader = await card.getChildLoader(MatCardSection.HEADER);
const headerLoader = await card.getChildLoader(contentSelectors.header as MatCardSection);
const headerSubcomponents = await headerLoader?.getAllHarnesses(DummyHarness) ?? [];
expect(headerSubcomponents.length).toBe(2);
});

it('should get a harness loader for the card content', async () => {
const card = await loader.getHarness(cardHarness.with({title: 'Shiba Inu'}));
const contentLoader = await card.getChildLoader(MatCardSection.CONTENT);
const contentLoader = await card.getChildLoader(contentSelectors.content as MatCardSection);
const contentSubcomponents = await contentLoader?.getAllHarnesses(DummyHarness) ?? [];
expect(contentSubcomponents.length).toBe(1);
});

it('should get a harness loader for the card actions', async () => {
const card = await loader.getHarness(cardHarness.with({title: 'Shiba Inu'}));
const actionLoader = await card.getChildLoader(MatCardSection.ACTIONS);
const actionLoader = await card.getChildLoader(contentSelectors.actions as MatCardSection);
const actionSubcomponents = await actionLoader?.getAllHarnesses(DummyHarness) ?? [];
expect(actionSubcomponents.length).toBe(2);
});

it('should get a harness loader for the card footer', async () => {
const card = await loader.getHarness(cardHarness.with({title: 'Shiba Inu'}));
const footerLoader = await card.getChildLoader(MatCardSection.FOOTER);
const footerLoader = await card.getChildLoader(contentSelectors.footer as MatCardSection);
const footerSubcomponents = await footerLoader?.getAllHarnesses(DummyHarness) ?? [];
expect(footerSubcomponents.length).toBe(1);
});
Expand Down