feat(bazel): Initial commit of protractor_web_test_suite (#24787)

Co-authored-by: Andrew Z Allen <me@andrewzallen.com>

PR Close #24787
This commit is contained in:
mrmeku 2018-04-09 00:53:31 -06:00 committed by Matias Niemelä
parent 0399c6972a
commit 71e0df039c
10 changed files with 224 additions and 0 deletions

View File

@ -22,6 +22,7 @@ node_modules_filegroup(
"jasmine", "jasmine",
"minimist", "minimist",
"protobufjs", "protobufjs",
"protractor",
"reflect-metadata", "reflect-metadata",
"source-map-support", "source-map-support",
"tsickle", "tsickle",

View File

@ -11,6 +11,12 @@ http_archive(
sha256 = "634206524d90dc03c52392fa3f19a16637d2bcf154910436fe1d669a0d9d7b9c", sha256 = "634206524d90dc03c52392fa3f19a16637d2bcf154910436fe1d669a0d9d7b9c",
) )
http_archive(
name = "bazel_gazelle",
sha256 = "d03625db67e9fb0905bbd206fa97e32ae9da894fe234a493e7517fd25faec914",
url = "https://github.com/bazelbuild/bazel-gazelle/releases/download/0.10.1/bazel-gazelle-0.10.1.tar.gz",
)
http_archive( http_archive(
name = "io_bazel_rules_webtesting", name = "io_bazel_rules_webtesting",
url = "https://github.com/bazelbuild/rules_webtesting/archive/v0.2.0.zip", url = "https://github.com/bazelbuild/rules_webtesting/archive/v0.2.0.zip",
@ -85,6 +91,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_too
go_rules_dependencies() go_rules_dependencies()
go_register_toolchains() go_register_toolchains()
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
gazelle_dependencies()
load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories") load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories")
web_test_repositories() web_test_repositories()

View File

@ -9,6 +9,8 @@ Users should not load files under "/src"
load("//packages/bazel/src:ng_module.bzl", _ng_module = "ng_module") load("//packages/bazel/src:ng_module.bzl", _ng_module = "ng_module")
load("//packages/bazel/src/ng_package:ng_package.bzl", _ng_package = "ng_package") load("//packages/bazel/src/ng_package:ng_package.bzl", _ng_package = "ng_package")
load("//packages/bazel/src/protractor:protractor_web_test_suite.bzl", _protractor_web_test_suite = "protractor_web_test_suite")
ng_module = _ng_module ng_module = _ng_module
ng_package = _ng_package ng_package = _ng_package
protractor_web_test_suite = _protractor_web_test_suite

View File

@ -0,0 +1,4 @@
exports_files([
"conf.js.tmpl",
"protractor_runner.js",
])

View File

@ -0,0 +1,14 @@
const baseConf = require("BASE_CONF_IMPORT_PATH");
exports.config = {
...baseConf.config,
framework: "jasmine2",
seleniumAddress: process.env.WEB_TEST_HTTP_SERVER.trim() + "/wd/hub",
specs: [
SPEC_FILE_IMPORT_PATHS
].map(specPath => require.resolve(specPath)),
// TODO: Allow users to specifify other browsers.
capabilities: {
browserName: "chrome"
},
};

View File

@ -0,0 +1,23 @@
/**
* @license
* Copyright Google Inc. 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
*
* @fileoverview A wrapper around the protractor cli for bazel compatibility.
*/
const launcher = require('protractor/built/launcher');
function main(args) {
if (!args.length) {
throw new Error('Config file argument missing');
}
const config = require.resolve(args[0]);
launcher.init(config);
}
if (require.main === module) {
process.exitCode = main(process.argv.slice(2));
}

View File

@ -0,0 +1,107 @@
# Copyright Google Inc. 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
"""Implementation of the protractor_web_test_suite rule.
"""
load("@io_bazel_rules_webtesting//web:web.bzl", "web_test_suite")
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("@build_bazel_rules_nodejs//internal/common:sources_aspect.bzl", "sources_aspect")
load("@build_bazel_rules_nodejs//internal/common:module_mappings.bzl", "module_mappings_runtime_aspect")
def _modify_tsconfig_impl(ctx):
spec_file_import_paths = []
for dep in ctx.attr.deps:
# For each transitive ES5 dependency, grab the short path
for f in dep.node_sources.to_list():
spec_file_import_paths.append("\"{workspace}/{path}\"".format(workspace=ctx.workspace_name, path=f.short_path))
ctx.actions.expand_template(
template = ctx.file._conf_templ,
output = ctx.outputs._modified_conf,
substitutions = {
"BASE_CONF_IMPORT_PATH": "{workspace}/{path}".format(workspace=ctx.workspace_name, path=ctx.file.base_conf.short_path),
"SPEC_FILE_IMPORT_PATHS": ',\n '.join(spec_file_import_paths),
})
_modify_conf = rule(
attrs = {
"base_conf": attr.label(
doc = """conf.js file used to configure protractor.""",
allow_single_file = True,
cfg = "data",
aspects = [
sources_aspect,
module_mappings_runtime_aspect,
],
),
"deps": attr.label_list(
doc = """Spec and page files used for testing.""",
allow_files = True,
cfg = "data",
aspects = [
sources_aspect,
module_mappings_runtime_aspect,
],
),
"_conf_templ": attr.label(
allow_files = True,
single_file = True,
default = Label("@angular//packages/bazel/src/protractor:conf.js.tmpl"),
),
},
outputs = {
"_modified_conf": "%{name}.conf.js",
},
implementation = _modify_tsconfig_impl,
)
def protractor_web_test_suite(name, conf, deps, data = [], **kwargs):
"""Runs protractor using the passed conf.js file and tests listed within deps.
Args:
name: The name of the web_test_suite rule the macro expands into.
conf: A conf.js file to be used as a base template. The following fields of the base
config are overridden:
framework
seleniumAddress
specs
capabilities
deps: A list of dependencies containing the test files to run within protractor.
data: Any runtime files which are needed to run the test suite.
**kwargs: Any other arguements are passed directory to the expanded web_test_suite rule.
Returns:
This macro expands into a web_test_suite rule which runs the protractor tests.
"""
_modify_conf_name = "%s_modify_conf" % name
_modify_conf(
name = _modify_conf_name,
base_conf = conf,
deps = deps,
testonly = True,
)
_modified_conf = "%s.conf.js" % _modify_conf_name
_protractor_runner_name = name + "_protractor_runner"
nodejs_binary(
name = _protractor_runner_name,
entry_point = "angular/packages/bazel/src/protractor/protractor_runner.js",
data = data + deps + [_modified_conf, "@angular//packages/bazel/src/protractor:protractor_runner.js"],
templated_args = ["$(location :%s)" % _modified_conf],
tags = ["manual"],
testonly = True,
)
web_test_suite(
name = name,
# TODO: Allow users to specify more browsers. Currently conf.js is hardcoded for chrome.
browsers = ["@io_bazel_rules_webtesting//browsers:chromium-local"],
data = data + deps + [conf, _modified_conf],
test = ":%s_bin" % _protractor_runner_name,
testonly = True,
**kwargs
)

View File

@ -0,0 +1,14 @@
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library")
ts_library(
name = "ts_spec",
testonly = True,
srcs = ["test.spec.ts"],
)
protractor_web_test_suite(
name = "demo",
conf = "conf.js",
deps = [":ts_spec"],
)

View File

@ -0,0 +1,29 @@
/**
* @license
* Copyright Google Inc. 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
*/
/**
* @fileoverview A demo of what a user's conf.js file might look like.
*/
const http = require('http');
const PORT = 3000;
exports.config = {
baseUrl: `http://localhost:${PORT}`,
onPrepare() {
const app = new http.Server();
app.on('request', (req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World');
res.end('\n');
});
return new Promise(resolve => { app.listen(PORT, () => { resolve(); }); });
}
};

View File

@ -0,0 +1,20 @@
/**
* @license
* Copyright Google Inc. 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
*
* @fileoverview A small demo of how to run a protractor test.
*/
import {$, browser} from 'protractor';
describe('Basic test', () => {
it('should say hello world', () => {
browser.waitForAngularEnabled(false);
browser.get('/');
expect($('body').getText()).toContain('Hello World');
});
});