Skip to content

Commit 5e8b690

Browse files
committed
make sure code compiles and runs
1 parent f0aaf22 commit 5e8b690

24 files changed

+412
-81
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,9 @@
9898
# CDK experimental package
9999
/src/cdk-experimental/** @jelbourn
100100
/src/cdk-experimental/dialog/** @jelbourn @josephperrott @crisbeto
101-
/src/cdk-experimental/scrolling/** @mmalerba
102101
/src/cdk-experimental/popover-edit/** @kseamon @andrewseguin
102+
/src/cdk-experimental/scrolling/** @mmalerba
103+
/src/cdk-experimental/testing/** @mmalerba
103104

104105
# Docs examples & guides
105106
/guides/** @jelbourn
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package(default_visibility=["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "ng_module", "ng_web_test_suite")
4+
load("@npm_angular_bazel//:index.bzl", "protractor_web_test_suite")
5+
6+
7+
ng_module(
8+
name = "testing",
9+
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts", "test-app/**"]),
10+
module_name = "@angular/cdk-experimental/testing",
11+
deps = [
12+
"@npm//@angular/core",
13+
"@npm//protractor",
14+
],
15+
)
16+
17+
ng_web_test_suite(
18+
name = "unit_tests",
19+
deps = ["//src/cdk-experimental/testing/test-app:test_app_test_sources"],
20+
)
21+
22+
protractor_web_test_suite(
23+
name = "e2e_tests",
24+
configuration = ":protractor.conf.js",
25+
on_prepare = ":start-devserver.js",
26+
server = "//src/cdk-experimental/testing/test-app:devserver",
27+
deps = [
28+
"@npm//protractor",
29+
"//src/cdk-experimental/testing/test-app:test_app_e2e_test_sources",
30+
],
31+
data = [
32+
"@npm//@angular/bazel",
33+
],
34+
)

src/cdk-experimental/testing/component-harness.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +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+
19
/**
210
* Test Element interface
311
* This is a wrapper of native element
@@ -165,8 +173,7 @@ export class ComponentHarness {
165173
options?: Options): () => Promise<TestElement|T|null> {
166174
if (typeof cssOrComponentHarness === 'string') {
167175
const css = cssOrComponentHarness;
168-
const options = cssOrOptions as Options;
169-
return () => this.locator.find(css, options);
176+
return () => this.locator.find(css, cssOrOptions as Options);
170177
} else {
171178
const componentHarness = cssOrComponentHarness;
172179
const css = cssOrOptions as string;

src/cdk-experimental/testing/index.ts

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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
exports.config = {
2+
useAllAngular2AppRoots: true,
3+
allScriptsTimeout: 120000,
4+
getPageTimeout: 120000,
5+
jasmineNodeOpts: {
6+
defaultTimeoutInterval: 120000,
7+
},
8+
9+
// Since we want to use async/await we don't want to mix up with selenium's promise
10+
// manager. In order to enforce this, we disable the promise manager.
11+
SELENIUM_PROMISE_MANAGER: false,
12+
};

src/cdk-experimental/testing/protractor.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1-
import {browser, by, element, ElementFinder} from 'protractor';
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+
// TODO(mmalerba): Should this file be part of `@angular/cdk-experimental/testing` or a separate
10+
// package? It depends on protractor which we don't want to put in the deps for cdk-experimental.
11+
12+
import {browser, by, element as protractorElement, ElementFinder} from 'protractor';
213
import {promise as wdpromise} from 'selenium-webdriver';
314

4-
import {ComponentHarness, ComponentHarnessType, Locator, Options, TestElement} from './component-harness';
15+
import {
16+
ComponentHarness,
17+
ComponentHarnessType,
18+
Locator,
19+
Options,
20+
TestElement
21+
} from './component-harness';
522

623
/**
724
* Component harness factory for protractor.
@@ -52,23 +69,26 @@ export function getElementFinder(testElement: TestElement): ElementFinder {
5269
}
5370

5471
class ProtractorLocator implements Locator {
55-
private root: ProtractorElement;
56-
constructor(private rootFinder: ElementFinder) {
57-
this.root = new ProtractorElement(this.rootFinder);
72+
private _root: ProtractorElement;
73+
74+
constructor(private _rootFinder: ElementFinder) {
75+
this._root = new ProtractorElement(this._rootFinder);
5876
}
5977

6078
host(): TestElement {
61-
return this.root;
79+
return this._root;
6280
}
6381

6482
async find(css: string, options?: Options): Promise<TestElement|null> {
65-
const finder = await getElement(css, this.rootFinder, options);
66-
if (finder === null) return null;
83+
const finder = await getElement(css, this._rootFinder, options);
84+
if (finder === null) {
85+
return null;
86+
}
6787
return new ProtractorElement(finder);
6888
}
6989

7090
async findAll(css: string): Promise<TestElement[]> {
71-
const elementFinders = this.rootFinder.all(by.css(css));
91+
const elementFinders = this._rootFinder.all(by.css(css));
7292
const res: TestElement[] = [];
7393
await elementFinders.each(el => {
7494
if (el) {
@@ -81,8 +101,10 @@ class ProtractorLocator implements Locator {
81101
async load<T extends ComponentHarness>(
82102
componentHarness: ComponentHarnessType<T>, css: string,
83103
options?: Options): Promise<T|null> {
84-
const root = await getElement(css, this.rootFinder, options);
85-
if (root === null) return null;
104+
const root = await getElement(css, this._rootFinder, options);
105+
if (root === null) {
106+
return null;
107+
}
86108
const locator = new ProtractorLocator(root);
87109
return new componentHarness(locator);
88110
}
@@ -91,7 +113,7 @@ class ProtractorLocator implements Locator {
91113
componentHarness: ComponentHarnessType<T>,
92114
rootSelector: string,
93115
): Promise<T[]> {
94-
const roots = this.rootFinder.all(by.css(rootSelector));
116+
const roots = this._rootFinder.all(by.css(rootSelector));
95117
const res: T[] = [];
96118
await roots.each(el => {
97119
if (el) {
@@ -163,7 +185,7 @@ function toPromise<T>(p: wdpromise.Promise<T>): Promise<T> {
163185
async function getElement(css: string, root?: ElementFinder, options?: Options):
164186
Promise<ElementFinder|null> {
165187
const useGlobalRoot = options && !!options.global;
166-
const elem = root === undefined || useGlobalRoot ? element(by.css(css)) :
188+
const elem = root === undefined || useGlobalRoot ? protractorElement(by.css(css)) :
167189
root.element(by.css(css));
168190
const allowNull = options !== undefined && options.allowNull !== undefined ?
169191
options.allowNull :
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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 * as protractor from './protractor';
10+
import * as testbed from './testbed';
11+
12+
export * from './component-harness';
13+
export {protractor, testbed};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const protractor = require('protractor');
2+
const utils = require('@angular/bazel/protractor-utils');
3+
const spawn = require('child_process').spawn;
4+
5+
/**
6+
* Runs the specified server binary from a given workspace and waits for the server
7+
* being ready. The server binary will be resolved from the runfiles.
8+
*/
9+
async function runBazelServer(workspace, serverPath, timeout) {
10+
const serverBinary = require.resolve(`${workspace}/${serverPath}`);
11+
const port = await utils.findFreeTcpPort();
12+
13+
// Start the Bazel server binary with a random free TCP port.
14+
const serverProcess = spawn(serverBinary, ['-port', port], {stdio: 'inherit'});
15+
16+
// In case the process exited with an error, we want to propagate the error.
17+
serverProcess.on('exit', exitCode => {
18+
if (exitCode !== 0) {
19+
throw new Error(`Server exited with error code: ${exitCode}`);
20+
}
21+
});
22+
23+
// Wait for the server to be bound to the given port.
24+
await utils.waitForServer(port, timeout);
25+
26+
return port;
27+
}
28+
29+
/**
30+
* Called by Protractor before starting any tests. This is script is responsible for
31+
* starting up the devserver and updating the Protractor base URL to the proper port.
32+
*/
33+
module.exports = async function(config) {
34+
const port = await runBazelServer(config.workspace, config.server);
35+
const baseUrl = `http://localhost:${port}`;
36+
const processedConfig = await protractor.browser.getProcessedConfig();
37+
38+
// Update the protractor "baseUrl" to match the new random TCP port. We need random TCP ports
39+
// because otherwise Bazel could not execute protractor tests concurrently.
40+
protractor.browser.baseUrl = baseUrl;
41+
processedConfig.baseUrl = baseUrl;
42+
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package(default_visibility=["//visibility:public"])
2+
3+
load("@npm_bazel_typescript//:defs.bzl", "ts_devserver")
4+
load("//tools:defaults.bzl", "ng_module", "ng_test_library", "ts_library")
5+
load("//:packages.bzl", "ANGULAR_LIBRARY_UMDS")
6+
7+
ng_module(
8+
name = "test-app",
9+
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts", "harnesses/**"]),
10+
assets = glob(["**/*.html", "**/*.css"], exclude = ["index.html"]),
11+
deps = [
12+
"@npm//@angular/core",
13+
"@npm//@angular/forms",
14+
],
15+
)
16+
17+
ts_devserver(
18+
name = "devserver",
19+
port = 4200,
20+
# Name of the AMD module that should be required on page load.
21+
entry_module = "angular_material/src/cdk-experimental/testing/test-app/main",
22+
# Serving path of the bundle that serves all files specified in "deps" and "scripts".
23+
serving_path = "/bundle.js",
24+
# Root paths can be used simplify the loading of files from external Bazel repositories
25+
# (such as the Bazel managed deps repository called "npm")
26+
additional_root_paths = [
27+
"npm/node_modules",
28+
],
29+
# Files which should be provided by Bazel when running the devserver. These are not
30+
# automatically served, but can be loaded manually through HTTP requests.
31+
static_files = [
32+
"@npm//zone.js",
33+
"@npm//core-js",
34+
":index.html",
35+
],
36+
# Scripts which will be included in the serving_path bundle after "require.js" has been
37+
# loaded.
38+
# TODO(jelbourn): remove UMDs from here once we don't have to manually include them
39+
scripts = [
40+
":devserver-configure.js",
41+
"//tools/rxjs:rxjs_umd_modules",
42+
"@npm//node_modules/tslib:tslib.js",
43+
] + ANGULAR_LIBRARY_UMDS,
44+
# Dependencies that produce JavaScript output will be automatically included in the
45+
# serving_path bundle
46+
deps = [":test-app"],
47+
)
48+
49+
ng_module(
50+
name = "test_app_test_harnesses",
51+
srcs = glob(["harnesses/*.ts"]),
52+
deps = [
53+
"//src/cdk-experimental/testing",
54+
],
55+
)
56+
57+
ng_test_library(
58+
name = "test_app_test_sources",
59+
srcs = glob(["**/*.spec.ts"], exclude=["**/*.e2e.spec.ts"]),
60+
deps = [
61+
":test-app",
62+
":test_app_test_harnesses",
63+
],
64+
)
65+
66+
ts_library(
67+
name = "test_app_e2e_test_sources",
68+
srcs = glob(["**/*.e2e.spec.ts"]),
69+
tsconfig = ":tsconfig.json",
70+
deps = [
71+
"@npm//@types/jasmine",
72+
"@npm//@types/selenium-webdriver",
73+
"@npm//protractor",
74+
":test_app_test_harnesses",
75+
"//src/cdk-experimental/testing",
76+
],
77+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// We need to configure AMD modules which are not named because otherwise "require.js" is not
2+
// able to resolve AMD imports to such modules.
3+
require.config({});
4+
5+
// Workaround until https://github.com/angular/components/issues/13883 has been addressed.
6+
var module = {id: ''};

src/cdk-experimental/testing/test-app/harnesses/main-component-harness.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +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+
19
import {ComponentHarness, TestElement} from '../../component-harness';
210
import {SubComponentHarness} from './sub-component-harness';
311

@@ -23,23 +31,23 @@ export class MainComponentHarness extends ComponentHarness {
2331
readonly nullGlobalEl =
2432
this.find('wrong locator', {global: true, allowNull: true});
2533

26-
private button = this.find('button');
27-
private testTools = this.find(SubComponentHarness, 'sub');
34+
private _button = this.find('button');
35+
private _testTools = this.find(SubComponentHarness, 'sub');
2836

2937
async increaseCounter(times: number) {
30-
const button = await this.button();
38+
const button = await this._button();
3139
for (let i = 0; i < times; i++) {
3240
await button.click();
3341
}
3442
}
3543

3644
async getTestTool(index: number): Promise<TestElement> {
37-
const subComponent = await this.testTools();
45+
const subComponent = await this._testTools();
3846
return subComponent.getItem(index);
3947
}
4048

4149
async getTestTools(): Promise<TestElement[]> {
42-
const subComponent = await this.testTools();
50+
const subComponent = await this._testTools();
4351
return subComponent.getItems();
4452
}
4553
}
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
<!DOCTYPE html>
2-
<html>
1+
<!doctype html>
2+
<html lang="en">
33
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>Test App</title>
47
<base href="/">
5-
<title>angular2 page</title>
68
</head>
79
<body>
8-
<main></main>
10+
<main>Loading...</main>
911
<span class="sibling">I am a sibling!</span>
12+
13+
<!-- Static scripts which are not imported through AMD nor part of the ConcatJS bundle. -->
14+
<script src="core-js/client/core.min.js"></script>
15+
<script src="zone.js/dist/zone.min.js"></script>
16+
17+
<!-- ConcatJS bundle from the Bazel TypeScript devserver. -->
18+
<script src="bundle.js"></script>
1019
</body>
11-
<script src="/app_bundle.js"></script>
1220
</html>

0 commit comments

Comments
 (0)