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): add autocomplete test harness #16620

Merged
merged 1 commit into from
Aug 29, 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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@

# Material experimental package
/src/material-experimental/* @jelbourn
/src/material-experimental/mdc-autocomplete/** @crisbeto
/src/material-experimental/mdc-button/** @andrewseguin
/src/material-experimental/mdc-card/** @mmalerba
/src/material-experimental/mdc-checkbox/** @mmalerba
Expand Down
99 changes: 99 additions & 0 deletions src/material-experimental/mdc-autocomplete/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package(default_visibility = ["//visibility:public"])

load("@io_bazel_rules_sass//:defs.bzl", "sass_binary", "sass_library")
load("//src/e2e-app:test_suite.bzl", "e2e_test_suite")
load("//tools:defaults.bzl", "ng_e2e_test_library", "ng_module", "ng_test_library", "ng_web_test_suite", "ts_library")

ng_module(
name = "mdc-autocomplete",
srcs = glob(
["**/*.ts"],
exclude = [
"**/*.spec.ts",
"harness/**",
],
),
assets = [
":autocomplete_scss",
] + glob(["**/*.html"]),
module_name = "@angular/material-experimental/mdc-autocomplete",
deps = [
"//src/material/core",
],
)

ts_library(
name = "harness",
srcs = glob(
["harness/**/*.ts"],
exclude = ["**/*.spec.ts"],
),
deps = [
"//src/cdk-experimental/testing",
"//src/cdk/coercion",
],
)

sass_library(
name = "mdc_autocomplete_scss_lib",
srcs = glob(["**/_*.scss"]),
deps = [
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
"//src/material/core:core_scss_lib",
],
)

sass_binary(
name = "autocomplete_scss",
src = "autocomplete.scss",
include_paths = [
"external/npm/node_modules",
],
deps = [
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
"//src/material/core:all_themes",
],
)

ng_test_library(
name = "autocomplete_tests_lib",
srcs = [
"harness/autocomplete-harness.spec.ts",
],
deps = [
":harness",
":mdc-autocomplete",
"//src/cdk-experimental/testing",
"//src/cdk-experimental/testing/testbed",
"//src/cdk/platform",
"//src/cdk/testing",
"//src/material/autocomplete",
"@npm//@angular/platform-browser",
],
)

ng_web_test_suite(
name = "unit_tests",
deps = [
":autocomplete_tests_lib",
"//src/material-experimental:mdc_require_config.js",
],
)

ng_e2e_test_library(
name = "e2e_test_sources",
srcs = glob(["**/*.e2e.spec.ts"]),
deps = [
"//src/cdk/private/testing/e2e",
],
)

e2e_test_suite(
name = "e2e_tests",
deps = [
":e2e_test_sources",
"//src/cdk/private/testing/e2e",
],
)
1 change: 1 addition & 0 deletions src/material-experimental/mdc-autocomplete/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- TODO -->
13 changes: 13 additions & 0 deletions src/material-experimental/mdc-autocomplete/_mdc-autocomplete.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@import '../mdc-helpers/mdc-helpers';

@mixin mat-autocomplete-theme-mdc($theme) {
@include mat-using-mdc-theme($theme) {
// TODO: implement MDC-based autocomplete.
}
}

@mixin mat-autocomplete-typography-mdc($config) {
@include mat-using-mdc-typography($config) {
// TODO: implement MDC-based autocomplete.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: copy tests from existing mat-autocomplete, update as necessary to fix.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: implement MDC-based autocomplete
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @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 type AutocompleteHarnessFilters = {
id?: string;
name?: string,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {HarnessLoader} from '@angular/cdk-experimental/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk-experimental/testing/testbed';
import {Component} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatAutocompleteModule as MatMdcAutocompleteModule} from '../index';
import {MatAutocompleteHarness} from './autocomplete-harness';
import {MatAutocompleteHarness as MatMdcAutocompleteHarness} from './mdc-autocomplete-harness';

let fixture: ComponentFixture<AutocompleteHarnessTest>;
let loader: HarnessLoader;
let harness: typeof MatAutocompleteHarness;

describe('MatAutocompleteHarness', () => {
describe('non-MDC-based', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatAutocompleteModule],
declarations: [AutocompleteHarnessTest],
}).compileComponents();

fixture = TestBed.createComponent(AutocompleteHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
harness = MatAutocompleteHarness;
});

runTests();
});

describe('MDC-based', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatMdcAutocompleteModule],
declarations: [AutocompleteHarnessTest],
}).compileComponents();

fixture = TestBed.createComponent(AutocompleteHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
// Public APIs are the same as MatAutocompleteHarness, but cast
// is necessary because of different private fields.
harness = MatMdcAutocompleteHarness as any;
});

// TODO: enable after MDC autocomplete is implemented
// runTests();
});
});

/** Shared tests to run on both the original and MDC-based autocomplete. */
function runTests() {
it('should load all autocomplete harnesses', async () => {
const inputs = await loader.getAllHarnesses(harness);
expect(inputs.length).toBe(5);
});

it('should be able to get text inside the input', async () => {
const input = await loader.getHarness(harness.with({id: 'prefilled'}));
expect(await input.getText()).toBe('Prefilled value');
});

it('should get disabled state', async () => {
const enabled = await loader.getHarness(harness.with({id: 'plain'}));
const disabled = await loader.getHarness(harness.with({id: 'disabled'}));

expect(await enabled.isDisabled()).toBe(false);
expect(await disabled.isDisabled()).toBe(true);
});

it('should focus and blur an input', async () => {
const input = await loader.getHarness(harness.with({id: 'plain'}));
expect(getActiveElementId()).not.toBe('plain');
await input.focus();
expect(getActiveElementId()).toBe('plain');
await input.blur();
expect(getActiveElementId()).not.toBe('plain');
});

it('should be able to type in an input', async () => {
const input = await loader.getHarness(harness.with({id: 'plain'}));
await input.enterText('Hello there');
expect(await input.getText()).toBe('Hello there');
});

it('should be able to get the autocomplete panel', async () => {
const input = await loader.getHarness(harness.with({id: 'plain'}));
await input.focus();
expect(await input.getPanel()).toBeTruthy();
});

it('should be able to get the autocomplete panel options', async () => {
const input = await loader.getHarness(harness.with({id: 'plain'}));
await input.focus();
const options = await input.getOptions();

expect(options.length).toBe(11);
expect(await options[5].text()).toBe('New York');
});

it('should be able to get the autocomplete panel groups', async () => {
const input = await loader.getHarness(harness.with({id: 'grouped'}));
await input.focus();
const groups = await input.getOptionGroups();
const options = await input.getOptions();

expect(groups.length).toBe(3);
expect(options.length).toBe(11);
});

it('should be able to get the autocomplete panel', async () => {
// Focusing without any options will render the panel, but it'll be invisible.
fixture.componentInstance.states = [];
fixture.detectChanges();

const input = await loader.getHarness(harness.with({id: 'plain'}));
await input.focus();
expect(await input.isPanelVisible()).toBe(false);
});

it('should be able to get whether the autocomplete is open', async () => {
const input = await loader.getHarness(harness.with({id: 'plain'}));

expect(await input.isOpen()).toBe(false);
await input.focus();
expect(await input.isOpen()).toBe(true);
});

}

function getActiveElementId() {
return document.activeElement ? document.activeElement.id : '';
}

@Component({
template: `
<mat-autocomplete #autocomplete="matAutocomplete">
<mat-option *ngFor="let state of states" [value]="state.code">{{ state.name }}</mat-option>
</mat-autocomplete>

<mat-autocomplete #groupedAutocomplete="matAutocomplete">
<mat-optgroup *ngFor="let group of stateGroups" [label]="group.name">
<mat-option
*ngFor="let state of group.states"
[value]="state.code">{{ state.name }}</mat-option>
</mat-optgroup>
</mat-autocomplete>

<input id="plain" [matAutocomplete]="autocomplete">
<input id="disabled" disabled [matAutocomplete]="autocomplete">
<textarea id="textarea" [matAutocomplete]="autocomplete"></textarea>
<input id="prefilled" [matAutocomplete]="autocomplete" value="Prefilled value">
<input id="grouped" [matAutocomplete]="groupedAutocomplete">
`
})
class AutocompleteHarnessTest {
states = [
{code: 'AL', name: 'Alabama'},
{code: 'CA', name: 'California'},
{code: 'FL', name: 'Florida'},
{code: 'KS', name: 'Kansas'},
{code: 'MA', name: 'Massachusetts'},
{code: 'NY', name: 'New York'},
{code: 'OR', name: 'Oregon'},
{code: 'PA', name: 'Pennsylvania'},
{code: 'TN', name: 'Tennessee'},
{code: 'VA', name: 'Virginia'},
{code: 'WY', name: 'Wyoming'},
];

stateGroups = [
{
name: 'One',
states: this.states.slice(0, 3)
},
{
name: 'Two',
states: this.states.slice(3, 7)
},
{
name: 'Three',
states: this.states.slice(7)
}
];
}

Loading