From 255f66b3b377862962eb81b95afe332b9656f344 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Thu, 13 Aug 2020 22:46:52 +0200 Subject: [PATCH] feat(material-experimental/mdc-card): add test harness Sets up a test harness for the MDC-based `mat-card`. Also makes some changes to the shared tests since they were hardcoded to the non-MDC selectors. --- src/material-experimental/config.bzl | 1 + .../mdc-card/testing/BUILD.bazel | 61 +++++++++++++++++++ .../mdc-card/testing/card-harness-filters.ts | 19 ++++++ .../mdc-card/testing/card-harness.e2e.spec.ts | 37 +++++++++++ .../mdc-card/testing/card-harness.spec.ts | 12 ++++ .../mdc-card/testing/card-harness.ts | 59 ++++++++++++++++++ .../mdc-card/testing/index.ts | 9 +++ .../mdc-card/testing/public-api.ts | 10 +++ .../card/testing/card-harness.spec.ts | 9 ++- src/material/card/testing/shared.spec.ts | 12 ++-- 10 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 src/material-experimental/mdc-card/testing/BUILD.bazel create mode 100644 src/material-experimental/mdc-card/testing/card-harness-filters.ts create mode 100644 src/material-experimental/mdc-card/testing/card-harness.e2e.spec.ts create mode 100644 src/material-experimental/mdc-card/testing/card-harness.spec.ts create mode 100644 src/material-experimental/mdc-card/testing/card-harness.ts create mode 100644 src/material-experimental/mdc-card/testing/index.ts create mode 100644 src/material-experimental/mdc-card/testing/public-api.ts diff --git a/src/material-experimental/config.bzl b/src/material-experimental/config.bzl index 13796e01be13..28fa56b3b9ae 100644 --- a/src/material-experimental/config.bzl +++ b/src/material-experimental/config.bzl @@ -4,6 +4,7 @@ entryPoints = [ "mdc-button", "mdc-button/testing", "mdc-card", + "mdc-card/testing", "mdc-checkbox", "mdc-checkbox/testing", "mdc-chips", diff --git a/src/material-experimental/mdc-card/testing/BUILD.bazel b/src/material-experimental/mdc-card/testing/BUILD.bazel new file mode 100644 index 000000000000..5850419e105d --- /dev/null +++ b/src/material-experimental/mdc-card/testing/BUILD.bazel @@ -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", + ], +) diff --git a/src/material-experimental/mdc-card/testing/card-harness-filters.ts b/src/material-experimental/mdc-card/testing/card-harness-filters.ts new file mode 100644 index 000000000000..30a9cfb5471e --- /dev/null +++ b/src/material-experimental/mdc-card/testing/card-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.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; +} diff --git a/src/material-experimental/mdc-card/testing/card-harness.e2e.spec.ts b/src/material-experimental/mdc-card/testing/card-harness.e2e.spec.ts new file mode 100644 index 000000000000..b41dd262282e --- /dev/null +++ b/src/material-experimental/mdc-card/testing/card-harness.e2e.spec.ts @@ -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'); + }); +}); diff --git a/src/material-experimental/mdc-card/testing/card-harness.spec.ts b/src/material-experimental/mdc-card/testing/card-harness.spec.ts new file mode 100644 index 000000000000..81a2def5e8e6 --- /dev/null +++ b/src/material-experimental/mdc-card/testing/card-harness.spec.ts @@ -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 + }); +}); diff --git a/src/material-experimental/mdc-card/testing/card-harness.ts b/src/material-experimental/mdc-card/testing/card-harness.ts new file mode 100644 index 000000000000..ae8672762de4 --- /dev/null +++ b/src/material-experimental/mdc-card/testing/card-harness.ts @@ -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 { + /** 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 { + 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 { + return (await this.host()).text(); + } + + /** Gets the cards's title text. */ + async getTitleText(): Promise { + return (await this._title())?.text() ?? ''; + } + + /** Gets the cards's subtitle text. */ + async getSubtitleText(): Promise { + return (await this._subtitle())?.text() ?? ''; + } +} diff --git a/src/material-experimental/mdc-card/testing/index.ts b/src/material-experimental/mdc-card/testing/index.ts new file mode 100644 index 000000000000..676ca90f1ffa --- /dev/null +++ b/src/material-experimental/mdc-card/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.io/license + */ + +export * from './public-api'; diff --git a/src/material-experimental/mdc-card/testing/public-api.ts b/src/material-experimental/mdc-card/testing/public-api.ts new file mode 100644 index 000000000000..6a511923ac0d --- /dev/null +++ b/src/material-experimental/mdc-card/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.io/license + */ + +export * from './card-harness'; +export * from './card-harness-filters'; diff --git a/src/material/card/testing/card-harness.spec.ts b/src/material/card/testing/card-harness.spec.ts index 4e4f95bfb87b..3fab24fa462d 100644 --- a/src/material/card/testing/card-harness.spec.ts +++ b/src/material/card/testing/card-harness.spec.ts @@ -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 + }); }); diff --git a/src/material/card/testing/shared.spec.ts b/src/material/card/testing/shared.spec.ts index 954a0eb68ec5..c8bd6f95170f 100644 --- a/src/material/card/testing/shared.spec.ts +++ b/src/material/card/testing/shared.spec.ts @@ -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; let loader: HarnessLoader; @@ -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); });