diff --git a/src/material-experimental/mdc-snack-bar/testing/BUILD.bazel b/src/material-experimental/mdc-snack-bar/testing/BUILD.bazel index 2a12838778ab..2dad80c10df0 100644 --- a/src/material-experimental/mdc-snack-bar/testing/BUILD.bazel +++ b/src/material-experimental/mdc-snack-bar/testing/BUILD.bazel @@ -24,8 +24,11 @@ ng_test_library( srcs = glob(["**/*.spec.ts"]), deps = [ ":testing", + "//src/cdk/testing", + "//src/cdk/testing/testbed", "//src/material-experimental/mdc-snack-bar", "//src/material/snack-bar/testing:harness_tests_lib", + "@npm//@angular/platform-browser", ], ) diff --git a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts index b9235851c9d5..7da2d2344f25 100644 --- a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts +++ b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts @@ -1,7 +1,88 @@ -import {MatSnackBarModule, MatSnackBar} from '@angular/material-experimental/mdc-snack-bar'; +import { + MatSnackBar, + MatSnackBarConfig, + MatSnackBarModule +} from '@angular/material-experimental/mdc-snack-bar'; import {runHarnessTests} from '@angular/material/snack-bar/testing/shared.spec'; import {MatSnackBarHarness} from './snack-bar-harness'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {HarnessLoader} from '@angular/cdk/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; +import {Component, TemplateRef, ViewChild} from '@angular/core'; describe('MDC-based MatSnackBarHarness', () => { runHarnessTests(MatSnackBarModule, MatSnackBar, MatSnackBarHarness as any); }); + +describe('MDC-based MatSnackBarHarness (MDC only behavior)', () => { + let fixture: ComponentFixture; + let loader: HarnessLoader; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MatSnackBarModule, NoopAnimationsModule], + declarations: [SnackbarHarnessTest], + }).compileComponents(); + + fixture = TestBed.createComponent(SnackbarHarnessTest); + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.documentRootLoader(fixture); + }); + + it('should be able to get message of a snack-bar with custom content', async () => { + fixture.componentInstance.openCustom(); + let snackBar = await loader.getHarness(MatSnackBarHarness); + expect(await snackBar.getMessage()).toBe('My custom snack-bar.'); + + fixture.componentInstance.openCustomWithAction(); + snackBar = await loader.getHarness(MatSnackBarHarness); + expect(await snackBar.getMessage()).toBe('My custom snack-bar with action.'); + }); + + it('should fail to get action description of a snack-bar with no action', async () => { + fixture.componentInstance.openCustom(); + const snackBar = await loader.getHarness(MatSnackBarHarness); + await expectAsync(snackBar.getActionDescription()).toBeRejectedWithError(/without an action/); + }); + + it('should be able to get action description of a snack-bar with an action', async () => { + fixture.componentInstance.openCustomWithAction(); + const snackBar = await loader.getHarness(MatSnackBarHarness); + expect(await snackBar.getActionDescription()).toBe('Ok'); + }); + + it('should be able to check whether a snack-bar with custom content has an action', async () => { + fixture.componentInstance.openCustom(); + let snackBar = await loader.getHarness(MatSnackBarHarness); + expect(await snackBar.hasAction()).toBe(false); + + fixture.componentInstance.openCustomWithAction(); + snackBar = await loader.getHarness(MatSnackBarHarness); + expect(await snackBar.hasAction()).toBe(true); + }); +}); + +@Component({ + template: ` + My custom snack-bar. + + My custom snack-bar with action. +
+
+ ` +}) +class SnackbarHarnessTest { + @ViewChild('custom') customTmpl: TemplateRef; + @ViewChild('customWithAction') customWithActionTmpl: TemplateRef; + + constructor(public snackBar: MatSnackBar) {} + + openCustom(config?: MatSnackBarConfig) { + return this.snackBar.openFromTemplate(this.customTmpl, config); + } + + openCustomWithAction(config?: MatSnackBarConfig) { + return this.snackBar.openFromTemplate(this.customWithActionTmpl, config); + } +} diff --git a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.ts b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.ts index 0d77fab29160..dcb25c1c1c58 100644 --- a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.ts +++ b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.ts @@ -21,9 +21,8 @@ export class MatSnackBarHarness extends BaseMatSnackBarHarness { // notified when it's done. /** The selector for the host element of a `MatSnackBar` instance. */ static override hostSelector = '.mat-mdc-snack-bar-container:not([mat-exit])'; - protected override _messageSelector = '.mat-mdc-simple-snack-bar .mat-mdc-snack-bar-label'; - protected override _simpleSnackBarSelector = '.mat-mdc-simple-snack-bar'; - protected override _actionButtonSelector = '.mat-mdc-simple-snack-bar .mat-mdc-snack-bar-action'; + protected override _messageSelector = '.mdc-snackbar__label'; + protected override _actionButtonSelector = '.mat-mdc-snack-bar-action'; /** * Gets a `HarnessPredicate` that can be used to search for a `MatSnackBarHarness` that meets @@ -35,4 +34,6 @@ export class MatSnackBarHarness extends BaseMatSnackBarHarness { options: SnackBarHarnessFilters = {}): HarnessPredicate { return new HarnessPredicate(MatSnackBarHarness, options); } + + protected override async _assertContentAnnotated() {} } diff --git a/src/material/snack-bar/testing/BUILD.bazel b/src/material/snack-bar/testing/BUILD.bazel index ead25593b3ab..ae5a72c49e25 100644 --- a/src/material/snack-bar/testing/BUILD.bazel +++ b/src/material/snack-bar/testing/BUILD.bazel @@ -42,7 +42,10 @@ ng_test_library( deps = [ ":harness_tests_lib", ":testing", + "//src/cdk/testing", + "//src/cdk/testing/testbed", "//src/material/snack-bar", + "@npm//@angular/platform-browser", ], ) diff --git a/src/material/snack-bar/testing/shared.spec.ts b/src/material/snack-bar/testing/shared.spec.ts index 2b6a4299ff96..34c18ac60811 100644 --- a/src/material/snack-bar/testing/shared.spec.ts +++ b/src/material/snack-bar/testing/shared.spec.ts @@ -91,24 +91,12 @@ export function runHarnessTests( fixture.componentInstance.openSimple('Subscribed to newsletter.'); let snackBar = await loader.getHarness(snackBarHarness); expect(await snackBar.getMessage()).toBe('Subscribed to newsletter.'); - - // For snack-bar's with custom template, the message cannot be - // retrieved. We expect an error to be thrown. - fixture.componentInstance.openCustom(); - snackBar = await loader.getHarness(snackBarHarness); - await expectAsync(snackBar.getMessage()).toBeRejectedWithError(/custom content/); }); it('should be able to get action description of simple snack-bar', async () => { fixture.componentInstance.openSimple('Hello', 'Unsubscribe'); let snackBar = await loader.getHarness(snackBarHarness); expect(await snackBar.getActionDescription()).toBe('Unsubscribe'); - - // For snack-bar's with custom template, the action description - // cannot be retrieved. We expect an error to be thrown. - fixture.componentInstance.openCustom(); - snackBar = await loader.getHarness(snackBarHarness); - await expectAsync(snackBar.getActionDescription()).toBeRejectedWithError(/custom content/); }); it('should be able to check whether simple snack-bar has action', async () => { @@ -119,12 +107,6 @@ export function runHarnessTests( fixture.componentInstance.openSimple('No action'); snackBar = await loader.getHarness(snackBarHarness); expect(await snackBar.hasAction()).toBe(false); - - // For snack-bar's with custom template, the action cannot - // be found. We expect an error to be thrown. - fixture.componentInstance.openCustom(); - snackBar = await loader.getHarness(snackBarHarness); - await expectAsync(snackBar.hasAction()).toBeRejectedWithError(/custom content/); }); it('should be able to dismiss simple snack-bar with action', async () => { @@ -143,7 +125,7 @@ export function runHarnessTests( fixture.componentInstance.openSimple('No action'); snackBar = await loader.getHarness(snackBarHarness); - await expectAsync(snackBar.dismissWithAction()).toBeRejectedWithError(/without action/); + await expectAsync(snackBar.dismissWithAction()).toBeRejectedWithError(/without an action/); }); @Component({ diff --git a/src/material/snack-bar/testing/snack-bar-harness.spec.ts b/src/material/snack-bar/testing/snack-bar-harness.spec.ts index 9eb1bf771d90..827a35594d51 100644 --- a/src/material/snack-bar/testing/snack-bar-harness.spec.ts +++ b/src/material/snack-bar/testing/snack-bar-harness.spec.ts @@ -1,7 +1,59 @@ -import {MatSnackBarModule, MatSnackBar} from '@angular/material/snack-bar'; +import {MatSnackBar, MatSnackBarConfig, MatSnackBarModule} from '@angular/material/snack-bar'; import {runHarnessTests} from '@angular/material/snack-bar/testing/shared.spec'; import {MatSnackBarHarness} from './snack-bar-harness'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {HarnessLoader} from '@angular/cdk/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; +import {Component, TemplateRef, ViewChild} from '@angular/core'; describe('Non-MDC-based MatSnackBarHarness', () => { runHarnessTests(MatSnackBarModule, MatSnackBar, MatSnackBarHarness); }); + +describe('Non-MDC-based MatSnackBarHarness (non-MDC only behavior)', () => { + let fixture: ComponentFixture; + let loader: HarnessLoader; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MatSnackBarModule, NoopAnimationsModule], + declarations: [SnackbarHarnessTest], + }).compileComponents(); + + fixture = TestBed.createComponent(SnackbarHarnessTest); + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.documentRootLoader(fixture); + }); + + it('should fail to get message of a snack-bar with custom content', async () => { + fixture.componentInstance.openCustom(); + const snackBar = await loader.getHarness(MatSnackBarHarness); + await expectAsync(snackBar.getMessage()).toBeRejectedWithError(/custom content/); + }); + + it('should fail to get action description of a snack-bar with custom content', async () => { + fixture.componentInstance.openCustom(); + const snackBar = await loader.getHarness(MatSnackBarHarness); + await expectAsync(snackBar.getActionDescription()).toBeRejectedWithError(/custom content/); + }); + + it('should fail to check whether a snack-bar with custom content has an action', async () => { + fixture.componentInstance.openCustom(); + const snackBar = await loader.getHarness(MatSnackBarHarness); + await expectAsync(snackBar.hasAction()).toBeRejectedWithError(/custom content/); + }); +}); + +@Component({ + template: `My custom snack-bar.` +}) +class SnackbarHarnessTest { + @ViewChild(TemplateRef) customTmpl: TemplateRef; + + constructor(public snackBar: MatSnackBar) {} + + openCustom(config?: MatSnackBarConfig) { + return this.snackBar.openFromTemplate(this.customTmpl, config); + } +} diff --git a/src/material/snack-bar/testing/snack-bar-harness.ts b/src/material/snack-bar/testing/snack-bar-harness.ts index ad2de0c6a940..9a21e51a3fa5 100644 --- a/src/material/snack-bar/testing/snack-bar-harness.ts +++ b/src/material/snack-bar/testing/snack-bar-harness.ts @@ -17,9 +17,8 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness /** The selector for the host element of a `MatSnackBar` instance. */ static hostSelector = '.mat-snack-bar-container'; protected _messageSelector = '.mat-simple-snackbar > span'; - protected _simpleSnackBarSelector = '.mat-simple-snackbar'; protected _actionButtonSelector = '.mat-simple-snackbar-action > button'; - private _simpleSnackBarLiveRegion = this.locatorFor('[aria-live]'); + private _snackBarLiveRegion = this.locatorFor('[aria-live]'); /** * Gets a `HarnessPredicate` that can be used to search for a `MatSnackBarHarness` that meets @@ -46,7 +45,7 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness * determined based on the ARIA politeness specified in the snack-bar config. */ async getAriaLive(): Promise { - return (await this._simpleSnackBarLiveRegion()) + return (await this._snackBarLiveRegion()) .getAttribute('aria-live') as Promise; } @@ -54,8 +53,8 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness * Whether the snack-bar has an action. Method cannot be used for snack-bar's with custom content. */ async hasAction(): Promise { - await this._assertSimpleSnackBar(); - return (await this._getSimpleSnackBarActionButton()) !== null; + await this._assertContentAnnotated(); + return (await this._getActionButton()) !== null; } /** @@ -63,8 +62,8 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness * with custom content. */ async getActionDescription(): Promise { - await this._assertSimpleSnackBarWithAction(); - return (await this._getSimpleSnackBarActionButton())!.text(); + await this._assertHasAction(); + return (await this._getActionButton())!.text(); } @@ -73,15 +72,15 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness * without action or with custom content. */ async dismissWithAction(): Promise { - await this._assertSimpleSnackBarWithAction(); - await (await this._getSimpleSnackBarActionButton())!.click(); + await this._assertHasAction(); + await (await this._getActionButton())!.click(); } /** * Gets the message of the snack-bar. Method cannot be used for snack-bar's with custom content. */ async getMessage(): Promise { - await this._assertSimpleSnackBar(); + await this._assertContentAnnotated(); return (await this.locatorFor(this._messageSelector)()).text(); } @@ -102,33 +101,33 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness } /** - * Asserts that the current snack-bar does not use custom content. Promise rejects if - * custom content is used. + * Asserts that the current snack-bar has annotated content. Promise reject + * if content is not annotated. */ - private async _assertSimpleSnackBar(): Promise { + protected async _assertContentAnnotated(): Promise { if (!await this._isSimpleSnackBar()) { throw Error('Method cannot be used for snack-bar with custom content.'); } } /** - * Asserts that the current snack-bar does not use custom content and has - * an action defined. Otherwise the promise will reject. + * Asserts that the current snack-bar has an action defined. Otherwise the + * promise will reject. */ - private async _assertSimpleSnackBarWithAction(): Promise { - await this._assertSimpleSnackBar(); + protected async _assertHasAction(): Promise { + await this._assertContentAnnotated(); if (!await this.hasAction()) { - throw Error('Method cannot be used for standard snack-bar without action.'); + throw Error('Method cannot be used for a snack-bar without an action.'); } } /** Whether the snack-bar is using the default content template. */ private async _isSimpleSnackBar(): Promise { - return await this.locatorForOptional(this._simpleSnackBarSelector)() !== null; + return await this.locatorForOptional('.mat-simple-snackbar')() !== null; } /** Gets the simple snack bar action button. */ - private async _getSimpleSnackBarActionButton() { + private async _getActionButton() { return this.locatorForOptional(this._actionButtonSelector)(); } } diff --git a/tools/public_api_guard/material/snack-bar-testing.md b/tools/public_api_guard/material/snack-bar-testing.md index 613d65a72a99..5f321d6f9a62 100644 --- a/tools/public_api_guard/material/snack-bar-testing.md +++ b/tools/public_api_guard/material/snack-bar-testing.md @@ -13,6 +13,8 @@ import { HarnessPredicate } from '@angular/cdk/testing'; export class MatSnackBarHarness extends ContentContainerComponentHarness { // (undocumented) protected _actionButtonSelector: string; + protected _assertContentAnnotated(): Promise; + protected _assertHasAction(): Promise; dismissWithAction(): Promise; getActionDescription(): Promise; getAriaLive(): Promise; @@ -24,8 +26,6 @@ export class MatSnackBarHarness extends ContentContainerComponentHarness isDismissed(): Promise; // (undocumented) protected _messageSelector: string; - // (undocumented) - protected _simpleSnackBarSelector: string; static with(options?: SnackBarHarnessFilters): HarnessPredicate; }