Skip to content

Commit 02a3f3e

Browse files
crisbetommalerba
authored andcommitted
feat(material-experimental): add sidenav test harness (#16695)
Adds a test harness for the sidenav.
1 parent d579537 commit 02a3f3e

File tree

16 files changed

+375
-0
lines changed

16 files changed

+375
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
/src/material-experimental/mdc-radio/** @mmalerba
102102
/src/material-experimental/mdc-slide-toggle/** @crisbeto
103103
/src/material-experimental/mdc-tabs/** @crisbeto
104+
/src/material-experimental/mdc-sidenav/** @crisbeto
104105
/src/material-experimental/mdc-theming/** @mmalerba
105106
/src/material-experimental/mdc-typography/** @mmalerba
106107
/src/material-experimental/popover-edit/** @kseamon @andrewseguin
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary", "sass_library")
4+
load("//tools:defaults.bzl", "ng_e2e_test_library", "ng_module", "ng_test_library", "ng_web_test_suite", "ts_library")
5+
load("//src/e2e-app:test_suite.bzl", "e2e_test_suite")
6+
7+
ng_module(
8+
name = "mdc-sidenav",
9+
srcs = glob(
10+
["**/*.ts"],
11+
exclude = [
12+
"**/*.spec.ts",
13+
"harness/**",
14+
],
15+
),
16+
assets = [
17+
# TODO: include scss assets
18+
] + glob(["**/*.html"]),
19+
module_name = "@angular/material-experimental/mdc-sidenav",
20+
deps = [
21+
"//src/material/core",
22+
],
23+
)
24+
25+
ts_library(
26+
name = "harness",
27+
srcs = glob(
28+
["harness/**/*.ts"],
29+
exclude = ["**/*.spec.ts"],
30+
),
31+
deps = [
32+
"//src/cdk-experimental/testing",
33+
],
34+
)
35+
36+
sass_library(
37+
name = "mdc_sidenav_scss_lib",
38+
srcs = glob(["**/_*.scss"]),
39+
deps = [
40+
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
41+
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
42+
"//src/material/core:core_scss_lib",
43+
],
44+
)
45+
46+
sass_binary(
47+
name = "sidenav_scss",
48+
src = "sidenav.scss",
49+
include_paths = [
50+
"external/npm/node_modules",
51+
],
52+
deps = [
53+
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
54+
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
55+
"//src/material/core:all_themes",
56+
],
57+
)
58+
59+
ng_test_library(
60+
name = "sidenav_tests_lib",
61+
srcs = [
62+
"harness/sidenav-harness.spec.ts",
63+
],
64+
deps = [
65+
":harness",
66+
":mdc-sidenav",
67+
"//src/cdk-experimental/testing",
68+
"//src/cdk-experimental/testing/testbed",
69+
"//src/cdk/testing",
70+
"//src/material/sidenav",
71+
"@npm//@angular/platform-browser",
72+
],
73+
)
74+
75+
ng_web_test_suite(
76+
name = "unit_tests",
77+
deps = [
78+
":sidenav_tests_lib",
79+
"//src/material-experimental:mdc_require_config.js",
80+
],
81+
)
82+
83+
ng_e2e_test_library(
84+
name = "e2e_test_sources",
85+
srcs = glob(["**/*.e2e.spec.ts"]),
86+
deps = [
87+
"//src/cdk/private/testing/e2e",
88+
],
89+
)
90+
91+
e2e_test_suite(
92+
name = "e2e_tests",
93+
deps = [
94+
":e2e_test_sources",
95+
"//src/cdk/private/testing/e2e",
96+
],
97+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- TODO -->
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@import '../mdc-helpers/mdc-helpers';
2+
3+
@mixin mat-sidenav-theme-mdc($theme) {
4+
@include mat-using-mdc-theme($theme) {
5+
// TODO: implement MDC-based sidenav.
6+
}
7+
}
8+
9+
@mixin mat-sidenav-typography-mdc($config) {
10+
@include mat-using-mdc-typography($config) {
11+
// TODO: implement MDC-based sidenav.
12+
}
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness} from '@angular/cdk-experimental/testing';
10+
11+
12+
/**
13+
* Harness for interacting with a MDC-based mat-sidenav in tests.
14+
* @dynamic
15+
*/
16+
export class MatSidenavHarness extends ComponentHarness {
17+
// TODO: implement once MDC sidenav is done.
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export type SidenavHarnessFilters = {
10+
id?: string;
11+
};
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import {HarnessLoader} from '@angular/cdk-experimental/testing';
2+
import {TestbedHarnessEnvironment} from '@angular/cdk-experimental/testing/testbed';
3+
import {Component} from '@angular/core';
4+
import {ComponentFixture, TestBed} from '@angular/core/testing';
5+
import {MatSidenavModule} from '@angular/material/sidenav';
6+
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
7+
import {MatSidenavModule as MatMdcSidenavModule} from '../index';
8+
import {MatSidenavHarness} from './sidenav-harness';
9+
import {MatSidenavHarness as MatMdcSidenavHarness} from './mdc-sidenav-harness';
10+
11+
let fixture: ComponentFixture<SidenavHarnessTest>;
12+
let loader: HarnessLoader;
13+
let harness: typeof MatSidenavHarness;
14+
15+
describe('MatSidenavHarness', () => {
16+
describe('non-MDC-based', () => {
17+
beforeEach(async () => {
18+
await TestBed.configureTestingModule({
19+
imports: [MatSidenavModule, NoopAnimationsModule],
20+
declarations: [SidenavHarnessTest],
21+
}).compileComponents();
22+
23+
fixture = TestBed.createComponent(SidenavHarnessTest);
24+
fixture.detectChanges();
25+
loader = TestbedHarnessEnvironment.loader(fixture);
26+
harness = MatSidenavHarness;
27+
});
28+
29+
runTests();
30+
});
31+
32+
describe('MDC-based', () => {
33+
beforeEach(async () => {
34+
await TestBed.configureTestingModule({
35+
imports: [MatMdcSidenavModule, NoopAnimationsModule],
36+
declarations: [SidenavHarnessTest],
37+
}).compileComponents();
38+
39+
fixture = TestBed.createComponent(SidenavHarnessTest);
40+
fixture.detectChanges();
41+
loader = TestbedHarnessEnvironment.loader(fixture);
42+
// Public APIs are the same as MatSidenavHarness, but cast
43+
// is necessary because of different private fields.
44+
harness = MatMdcSidenavHarness as any;
45+
});
46+
47+
// TODO: enable after MDC sidenav is implemented
48+
// runTests();
49+
});
50+
});
51+
52+
/** Shared tests to run on both the original and MDC-based sidenav. */
53+
function runTests() {
54+
it('should load all sidenav harnesses', async () => {
55+
const sidenavs = await loader.getAllHarnesses(harness);
56+
expect(sidenavs.length).toBe(3);
57+
});
58+
59+
it('should be able to get whether the sidenav is open', async () => {
60+
const sidenavs = await loader.getAllHarnesses(harness);
61+
62+
expect(await sidenavs[0].isOpen()).toBe(false);
63+
expect(await sidenavs[1].isOpen()).toBe(false);
64+
expect(await sidenavs[2].isOpen()).toBe(true);
65+
66+
fixture.componentInstance.threeOpened = false;
67+
fixture.detectChanges();
68+
69+
expect(await sidenavs[0].isOpen()).toBe(false);
70+
expect(await sidenavs[1].isOpen()).toBe(false);
71+
expect(await sidenavs[2].isOpen()).toBe(false);
72+
});
73+
74+
it('should be able to get the position of a sidenav', async () => {
75+
const sidenavs = await loader.getAllHarnesses(harness);
76+
77+
expect(await sidenavs[0].getPosition()).toBe('start');
78+
expect(await sidenavs[1].getPosition()).toBe('end');
79+
expect(await sidenavs[2].getPosition()).toBe('start');
80+
});
81+
82+
it('should be able to get the mode of a sidenav', async () => {
83+
const sidenavs = await loader.getAllHarnesses(harness);
84+
85+
expect(await sidenavs[0].getMode()).toBe('over');
86+
expect(await sidenavs[1].getMode()).toBe('side');
87+
expect(await sidenavs[2].getMode()).toBe('push');
88+
});
89+
90+
it('should be able to get whether a sidenav is fixed in the viewport', async () => {
91+
const sidenavs = await loader.getAllHarnesses(harness);
92+
93+
expect(await sidenavs[0].isFixedInViewport()).toBe(false);
94+
expect(await sidenavs[1].isFixedInViewport()).toBe(false);
95+
expect(await sidenavs[2].isFixedInViewport()).toBe(true);
96+
});
97+
}
98+
99+
@Component({
100+
template: `
101+
<mat-sidenav-container>
102+
<mat-sidenav id="one" [opened]="oneOpened" position="start">One</mat-sidenav>
103+
<mat-sidenav id="two" mode="side" position="end">Two</mat-sidenav>
104+
<mat-sidenav-content>Content</mat-sidenav-content>
105+
</mat-sidenav-container>
106+
107+
<mat-sidenav-container>
108+
<mat-sidenav id="three" mode="push" [opened]="threeOpened" fixedInViewport>Three</mat-sidenav>
109+
<mat-sidenav-content>Content</mat-sidenav-content>
110+
</mat-sidenav-container>
111+
`
112+
})
113+
class SidenavHarnessTest {
114+
threeOpened = true;
115+
}
116+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {ComponentHarness, HarnessPredicate} from '@angular/cdk-experimental/testing';
10+
import {SidenavHarnessFilters} from './sidenav-harness-filters';
11+
12+
/**
13+
* Harness for interacting with a standard mat-sidenav in tests.
14+
* @dynamic
15+
*/
16+
export class MatSidenavHarness extends ComponentHarness {
17+
static hostSelector = '.mat-sidenav';
18+
19+
/**
20+
* Gets a `HarnessPredicate` that can be used to search for a sidenav with
21+
* specific attributes.
22+
* @param options Options for narrowing the search.
23+
* @return `HarnessPredicate` configured with the given options.
24+
*/
25+
static with(options: SidenavHarnessFilters = {}): HarnessPredicate<MatSidenavHarness> {
26+
return new HarnessPredicate(MatSidenavHarness)
27+
.addOption('id', options.id, async (harness, id) => {
28+
const host = await harness.host();
29+
return (await host.getAttribute('id')) === id;
30+
});
31+
}
32+
33+
/** Gets whether the sidenav is open. */
34+
async isOpen(): Promise<boolean> {
35+
return (await this.host()).hasClass('mat-drawer-opened');
36+
}
37+
38+
/** Gets the position of the sidenav inside its container. */
39+
async getPosition(): Promise<'start'|'end'> {
40+
const host = await this.host();
41+
return (await host.hasClass('mat-drawer-end')) ? 'end' : 'start';
42+
}
43+
44+
/** Gets the mode that the sidenav is in. */
45+
async getMode(): Promise<'over'|'push'|'side'> {
46+
const host = await this.host();
47+
48+
if (await host.hasClass('mat-drawer-push')) {
49+
return 'push';
50+
}
51+
52+
if (await host.hasClass('mat-drawer-side')) {
53+
return 'side';
54+
}
55+
56+
return 'over';
57+
}
58+
59+
/** Gets whether the sidenav is fixed in the viewport. */
60+
async isFixedInViewport(): Promise<boolean> {
61+
return (await this.host()).hasClass('mat-sidenav-fixed');
62+
}
63+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './public-api';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {CommonModule} from '@angular/common';
10+
import {NgModule} from '@angular/core';
11+
import {MatCommonModule} from '@angular/material/core';
12+
13+
@NgModule({
14+
imports: [MatCommonModule, CommonModule],
15+
exports: [MatCommonModule],
16+
})
17+
export class MatSidenavModule {
18+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './module';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// TODO: copy tests from existing mat-sidenav, update as necessary to fix.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// TODO: implement MDC-based sidenav
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"extends": "../tsconfig-build",
3+
"files": [
4+
"public-api.ts",
5+
"../typings.d.ts"
6+
],
7+
"angularCompilerOptions": {
8+
"annotateForClosureCompiler": true,
9+
"strictMetadataEmit": true,
10+
"flatModuleOutFile": "index.js",
11+
"flatModuleId": "@angular/material-experimental/mdc-sidenav",
12+
"skipTemplateCodegen": true,
13+
"fullTemplateTypeCheck": true
14+
}
15+
}

0 commit comments

Comments
 (0)