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/snack-bar): add test harness for snack-bar #17127

Merged
merged 2 commits into from
Sep 18, 2019
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
7 changes: 2 additions & 5 deletions src/cdk/private/testing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ts_library")
load("//tools:defaults.bzl", "ng_test_library")

ts_library(
ng_test_library(
name = "testing",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
module_name = "@angular/cdk/private/testing",
deps = [
"@npm//@angular/core",
],
)
22 changes: 22 additions & 0 deletions src/cdk/private/testing/expect-async-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @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
*/

/**
* Expects the asynchronous function to throw an error that matches
* the specified expectation.
*/
export async function expectAsyncError(fn: () => Promise<any>, expectation: RegExp) {
let error: string|null = null;
try {
await fn();
} catch (e) {
error = e.toString();
}
expect(error).not.toBe(null);
expect(error!).toMatch(expectation, 'Expected error to be thrown.');
}
1 change: 1 addition & 0 deletions src/cdk/private/testing/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/

export * from './expect-async-error';
export * from './wrapped-error-message';
export * from './mock-ng-zone';
47 changes: 47 additions & 0 deletions src/material/snack-bar/testing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ng_module", "ng_test_library", "ng_web_test_suite")

ng_module(
name = "testing",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
module_name = "@angular/material/snack-bar/testing",
deps = [
"//src/cdk/testing",
],
)

ng_test_library(
name = "harness_tests_lib",
srcs = ["shared.spec.ts"],
deps = [
":testing",
"//src/cdk/overlay",
"//src/cdk/private/testing",
"//src/cdk/testing",
"//src/cdk/testing/testbed",
"//src/material/snack-bar",
"@npm//@angular/platform-browser",
],
)

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

ng_web_test_suite(
name = "unit_tests",
deps = [":unit_tests_lib"],
)
9 changes: 9 additions & 0 deletions src/material/snack-bar/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/snack-bar/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 './snack-bar-harness';
export * from './snack-bar-harness-filters';
160 changes: 160 additions & 0 deletions src/material/snack-bar/testing/shared.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import {OverlayContainer} from '@angular/cdk/overlay';
import {expectAsyncError} from '@angular/cdk/private/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {Component, TemplateRef, ViewChild} from '@angular/core';
import {ComponentFixture, inject, TestBed} from '@angular/core/testing';
import {MatSnackBar, MatSnackBarConfig, MatSnackBarModule} from '@angular/material/snack-bar';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MatSnackBarHarness} from './snack-bar-harness';

/**
* Function that can be used to run the shared snack-bar harness tests for either
* the non-MDC or MDC based snack-bar harness.
*/
export function runHarnessTests(
snackBarModule: typeof MatSnackBarModule,
snackBarHarness: typeof MatSnackBarHarness) {
let fixture: ComponentFixture<SnackbarHarnessTest>;
let loader: HarnessLoader;
let overlayContainer: OverlayContainer;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [snackBarModule, NoopAnimationsModule],
declarations: [SnackbarHarnessTest],
}).compileComponents();

fixture = TestBed.createComponent(SnackbarHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
inject([OverlayContainer], (oc: OverlayContainer) => {
overlayContainer = oc;
})();
});

afterEach(() => {
// Angular won't call this for us so we need to do it ourselves to avoid leaks.
overlayContainer.ngOnDestroy();
overlayContainer = null!;
});

it('should load harness for simple snack-bar', async () => {
const snackBarRef = fixture.componentInstance.openSimple('Hello!', '');
let snackBars = await loader.getAllHarnesses(snackBarHarness);

expect(snackBars.length).toBe(1);

snackBarRef.dismiss();
snackBars = await loader.getAllHarnesses(snackBarHarness);
expect(snackBars.length).toBe(0);
});

it('should load harness for custom snack-bar', async () => {
const snackBarRef = fixture.componentInstance.openCustom();
let snackBars = await loader.getAllHarnesses(snackBarHarness);

expect(snackBars.length).toBe(1);

snackBarRef.dismiss();
snackBars = await loader.getAllHarnesses(snackBarHarness);
expect(snackBars.length).toBe(0);
});

it('should load snack-bar harness by selector', async () => {
fixture.componentInstance.openSimple('Hello!', '', {panelClass: 'my-snack-bar'});
const snackBars = await loader.getAllHarnesses(snackBarHarness.with({
selector: '.my-snack-bar'
}));
expect(snackBars.length).toBe(1);
});

it('should be able to get role of snack-bar', async () => {
fixture.componentInstance.openCustom();
let snackBar = await loader.getHarness(snackBarHarness);
expect(await snackBar.getRole()).toBe('alert');

fixture.componentInstance.openCustom({politeness: 'polite'});
snackBar = await loader.getHarness(snackBarHarness);
expect(await snackBar.getRole()).toBe('status');

fixture.componentInstance.openCustom({politeness: 'off'});
snackBar = await loader.getHarness(snackBarHarness);
expect(await snackBar.getRole()).toBe(null);
});

it('should be able to get message of simple snack-bar', async () => {
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 expectAsyncError(() => snackBar.getMessage(), /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 expectAsyncError(() => snackBar.getActionDescription(), /custom content/);
});

it('should be able to check whether simple snack-bar has action', async () => {
fixture.componentInstance.openSimple('With action', 'Unsubscribe');
let snackBar = await loader.getHarness(snackBarHarness);
expect(await snackBar.hasAction()).toBe(true);

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 expectAsyncError(() => snackBar.hasAction(), /custom content/);
});

it('should be able to dismiss simple snack-bar with action', async () => {
const snackBarRef = fixture.componentInstance.openSimple('With action', 'Unsubscribe');
let snackBar = await loader.getHarness(snackBarHarness);
let actionCount = 0;
snackBarRef.onAction().subscribe(() => actionCount++);

await snackBar.dismissWithAction();
expect(actionCount).toBe(1);

fixture.componentInstance.openSimple('No action');
snackBar = await loader.getHarness(snackBarHarness);
await expectAsyncError(() => snackBar.dismissWithAction(), /without action/);
});
}

@Component({
template: `
<ng-template>
My custom snack-bar.
</ng-template>
`
})
class SnackbarHarnessTest {
@ViewChild(TemplateRef, {static: false}) customTmpl: TemplateRef<any>;

constructor(readonly snackBar: MatSnackBar) {}

openSimple(message: string, action = '', config?: MatSnackBarConfig) {
return this.snackBar.open(message, action, config);
}

openCustom(config?: MatSnackBarConfig) {
return this.snackBar.openFromTemplate(this.customTmpl, config);
}
}
11 changes: 11 additions & 0 deletions src/material/snack-bar/testing/snack-bar-harness-filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @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';

export interface SnackBarHarnessFilters extends BaseHarnessFilters {}
7 changes: 7 additions & 0 deletions src/material/snack-bar/testing/snack-bar-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {runHarnessTests} from '@angular/material/snack-bar/testing/shared.spec';
import {MatSnackBarHarness} from './snack-bar-harness';

describe('Non-MDC-based MatSnackBarHarness', () => {
runHarnessTests(MatSnackBarModule, MatSnackBarHarness);
});
Loading