Skip to content

Commit

Permalink
Use full compilation for closure_js_test
Browse files Browse the repository at this point in the history
Fixed #67
  • Loading branch information
jart committed May 27, 2016
1 parent 93fb8d4 commit 8143c2d
Show file tree
Hide file tree
Showing 22 changed files with 397 additions and 305 deletions.
108 changes: 65 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Closure Rules for Bazel (αlpha) [![Build Status](https://travis-ci.org/bazelbuild/rules_closure.svg?branch=master)](https://travis-ci.org/bazelbuild/rules_closure)

JavaScript | Templating | Stylesheets | Protocol Buffers
--- | --- | --- | ---
JavaScript | Templating | Stylesheets | Miscellaneous
--- | --- | --- | --- | ---
[closure_js_library](#closure_js_library) | [closure_template_js_library](#closure_template_js_library) | [closure_css_library](#closure_css_library) | [closure_proto_js_library](#closure_proto_js_library)
[closure_js_binary](#closure_js_binary) | [closure_template_java_library](#closure_template_java_library) | [closure_css_binary](#closure_css_binary) |
[closure_js_binary](#closure_js_binary) | [closure_template_java_library](#closure_template_java_library) | [closure_css_binary](#closure_css_binary) | [phantomjs_test](#phantomjs_test)
[closure_js_deps](#closure_js_deps) | [closure_template_py_library](#closure_template_py_library) | |
[closure_js_test](#closure_js_test) | | |

Expand Down Expand Up @@ -256,8 +256,8 @@ target. See the documentation of the `deps` attribute for further information.
Closure Library [base.js][base-js]. If this flag is used, an error will be
raised if any `deps` do not also specify this flag.

All `closure_js_library` rules have an implicit dependency on
`@closure_library//:closure/goog/base.js` by default. This is a lightweight
All `closure_js_library` rules with nonempty `srcs` have an implicit
dependency on `@closure_library//:closure/goog/base.js`. This is a lightweight
file that boostraps very important functions, e.g. `goog.provide`. Linking
this file by default is important because:

Expand Down Expand Up @@ -390,48 +390,27 @@ compatibility:

```python
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_test")
closure_js_test(name, srcs, deps, language)
closure_js_test(name, srcs, deps, html, compilation_level, css, defs,
dependency_mode, entry_points, formatting, language, pedantic,
suppress)
```

Runs JavaScript unit tests inside a headless web browser.

PhantomJS (QtWebKit) is used to run tests. This program does not need to be
installed separately; it is fetched automatically by Bazel. In the future, other
testing environments may be supported, e.g. SlimerJS, Node.js, JSDom, etc.
This is a build macro that composes [closure_js_library](#closure_js_library),
[closure_js_binary](#closure_js_binary), and
[phantomjs_test](#phantomjs_test).

#### Test Definitions

A test is defined as any function in the global namespace that begins with
`test`. If you don't have a global namespace, because you're either using
modules or `goog.scope`, then you must register your test functions with
`goog.testing.testSuite`.

Each `foo_test.js` file listed in `srcs` is tested individually. Each test file
is loaded into a separate global namespace; therefore, they may not reference
each other. Test helper functions must be defined in a dependent
`closure_js_library` with `testonly = True`.
Each test file should require `goog.testing.jsunit` and `goog.testing.asserts`
because they run the tests and provide useful [testing functions][asserts] such
as `assertEquals()`. Test files should also require `goog.testing.testSuite`
which is used to register the test functions.

Any JavaScript file related to testing is strongly recommended to contain a
`goog.setTestOnly()` statement in the file. However this is not required,
because some projects might not want to directly reference Closure Library
functions.

#### Assertions

You do not need to require `goog.testing.jsunit` and `goog.testing.asserts`
because they are loaded automatically by the test runner. These modules define
useful [testing functions][asserts] such as `assertEquals()`.

#### No Type Safety

Don't bother using type notation in your unit tests because it won't be checked.
Type safety is not feasible in unit tests because the mocking utilities in
Closure Library make the type checker angry.

This offers certain advantageous, such as the ability to override `const`
definitions and access private members; however, you should test by public APIs
whenever possible.

#### No Network Access

Your test will run within a hermetically sealed environment. You are not allowed
Expand All @@ -444,15 +423,58 @@ path.

- **name:** ([Name][name]; required) A unique name for this rule.

- **srcs:** (List of [labels][labels]; required) A list of `_test.js` source
files that represent this library.
- **srcs:** (List of [labels][labels]; required) List of `_test.js` source files
that register test functions.

- **deps:** (List of [labels][labels]; optional) Direct dependency list. This
has the same meaning as it does in `closure_js_binary`.
- **deps:** (List of [labels][labels]; optional) Direct dependency list passed
along to `closure_js_library`. This list will almost certainly need to include
`"@io_bazel_rules_closure//closure/library:testing"`.

- **language:** (String; optional; default is `"ECMASCRIPT5_STRICT"`) Variant of
JavaScript in which `srcs` are written. See the `closure_js_library`
documentation for more information.
- **html:** (Label; required; default is
`"@io_bazel_rules_closure//closure/testing:empty.html"`) HTML file containing
DOM structure of virtual web page *before* `<script>` tags are automatically
inserted.

- **compilation_level:** See `closure_js_binary`.
- **css:** See `closure_js_binary`.
- **defs:** See `closure_js_binary`.
- **dependency_mode:** See `closure_js_binary`.
- **entry_points:** See `closure_js_binary`.
- **formatting:** See `closure_js_binary`.
- **language:** See `closure_js_binary`.
- **pedantic:** See `closure_js_binary`.
- **suppress:** See `closure_js_library`.


## phantomjs\_test

```python
load("@io_bazel_rules_closure//closure:defs.bzl", "phantomjs_test")
phantomjs_test(name, deps, html, harness, runner)
```

Runs PhantomJS (QtWebKit) for unit testing purposes.

This is a low level rule. Please use the `closure_js_test` macro if possible.

### Arguments

- **name:** ([Name][name]; required) Unique name for this rule.

- **deps:** (List of [labels][labels]; required) Labels of Skylark rules
exporting `transitive_js_srcs`. Each source will be inserted into the webpage
in its own `<script>` tag based on a depth-first preordering.

- **harness:** (Label; required; default is
`"@io_bazel_rules_closure//closure/testing:phantomjs_harness"`) JS binary or
library exporting a single source file, to be used as the PhantomJS outer
script.

- **runner:** (Label; optional; default is
`"@io_bazel_rules_closure//closure/testing:phantomjs_jsunit_runner"`) Same as
`deps` but guaranteed to be loaded inside the virtual web page last. This
should run whatever tests got loaded by `deps` and then invoke `callPhantom`
to report the result to the `harness`.


## closure\_js\_deps
Expand Down
9 changes: 6 additions & 3 deletions closure/compiler/closure_js_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ def _impl(ctx):
srcs, externs = collect_js_srcs(ctx)
if not ctx.files.srcs and not ctx.files.externs and not ctx.attr.exports:
fail("Either 'srcs', 'externs', or 'exports' must be specified")
if ctx.attr.no_closure_library and is_using_closure_library(srcs):
fail("no_closure_library is pointless when the Closure Library is " +
"already part of the transitive closure")
if ctx.attr.no_closure_library:
if not ctx.files.srcs:
fail("no_closure_library is pointless when srcs is empty")
if is_using_closure_library(srcs):
fail("no_closure_library is pointless when the Closure Library is " +
"already part of the transitive closure")
inputs = []
args = ["--output=%s" % ctx.outputs.provided.path,
"--output_errors=%s" % ctx.outputs.stderr.path,
Expand Down
1 change: 1 addition & 0 deletions closure/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ load("//closure:repositories.bzl", "closure_repositories")
load("//closure/stylesheets:closure_css_binary.bzl", "closure_css_binary")
load("//closure/stylesheets:closure_css_library.bzl", "closure_css_library")
load("//closure/testing:closure_js_test.bzl", "closure_js_test")
load("//closure/testing:phantomjs_test.bzl", "phantomjs_test")
load("//closure/templates:closure_template_java_library.bzl", "closure_template_java_library")
load("//closure/templates:closure_template_js_library.bzl", "closure_template_js_library")
load("//protobuf:closure_proto_js_library.bzl", "closure_proto_js_library")
60 changes: 31 additions & 29 deletions closure/library/test/dom_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,34 @@ goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.html.SafeHtml');
goog.require('goog.testing.asserts');


function setUp() {
goog.dom.appendChild(
goog.global.document.body,
goog.dom.safeHtmlToNode(
goog.html.SafeHtml.create(
goog.dom.TagName.DIV,
{'id': 'hello'},
'Hello World!')));
}


function testGetElement() {
assertNotNull(goog.dom.getElement('hello'));
}


function testGetTextContent() {
assertEquals('Hello World!',
goog.dom.getTextContent(
goog.dom.getRequiredElement('hello')));
}


function testHtml() {
assertHTMLEquals('<div id="hello">Hello World!</div>',
goog.dom.getRequiredElement('hello').outerHTML);
}
goog.require('goog.testing.jsunit');
goog.require('goog.testing.testSuite');

goog.testing.testSuite({

'setUp': function() {
goog.dom.appendChild(
goog.global.document.body,
goog.dom.safeHtmlToNode(
goog.html.SafeHtml.create(
goog.dom.TagName.DIV,
{'id': 'hello'},
'Hello World!')));
},

'testGetElement': function() {
assertNotNull(goog.dom.getElement('hello'));
},

'testGetTextContent': function() {
assertEquals('Hello World!',
goog.dom.getTextContent(
goog.dom.getRequiredElement('hello')));
},

'testHtml': function() {
assertHTMLEquals('<div id="hello">Hello World!</div>',
goog.dom.getRequiredElement('hello').outerHTML);
}

}); // goog.testing.testSuite
28 changes: 17 additions & 11 deletions closure/private/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""

CSS_FILE_TYPE = FileType([".css", ".gss"])
HTML_FILE_TYPE = FileType([".html"])
JS_FILE_TYPE = FileType([".js"])
JS_LANGUAGE_DEFAULT = "ECMASCRIPT5_STRICT"
JS_TEST_FILE_TYPE = FileType(["_test.js"])
Expand All @@ -42,16 +43,20 @@ JS_HIDE_WARNING_ARGS = [
"--hide_warnings_for=.soy.js",
"--hide_warnings_for=external/closure_library/",
"--hide_warnings_for=external/soyutils_usegoog/",
"--hide_warnings_for=external/protobuf_js/",
"--hide_warnings_for=bazel-out/local-fastbuild/genfiles/",
]

JS_DEPS_ATTR = attr.label_list(
allow_files=False,
providers=["js_language",
"js_exports",
"js_provided",
"required_css_labels",
"transitive_js_srcs",
"transitive_js_externs"])
JS_DEPS_PROVIDERS = [
"js_language",
"js_exports",
"js_provided",
"required_css_labels",
"transitive_js_srcs",
"transitive_js_externs",
]

JS_DEPS_ATTR = attr.label_list(allow_files=False, providers=JS_DEPS_PROVIDERS)

CSS_DEPS_ATTR = attr.label_list(
allow_files=False,
Expand All @@ -72,15 +77,16 @@ CLOSURE_LIBRARY_DEPS_ATTR = attr.label(
def collect_js_srcs(ctx):
srcs = set(order="compile")
externs = set(order="compile")
base = None
if hasattr(ctx.attr, 'css'):
if ctx.attr.css:
srcs += [ctx.file._closure_library_base,
ctx.file._closure_library_deps,
ctx.attr.css.js_css_renaming_map]
elif (hasattr(ctx.file, '_closure_library_base')
and (not hasattr(ctx.attr, 'no_closure_library')
or not ctx.attr.no_closure_library)):
and (not hasattr(ctx.attr, 'no_closure_library')
or not ctx.attr.no_closure_library)
and (not hasattr(ctx.files, 'srcs')
or ctx.files.srcs)):
srcs += [ctx.file._closure_library_base,
ctx.file._closure_library_deps]
for dep in ctx.attr.deps:
Expand Down
5 changes: 4 additions & 1 deletion closure/templates/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@ closure_js_library(
closure_js_test(
name = "greeter_test",
srcs = ["greeter_test.js"],
deps = [":greeter_lib"],
deps = [
":greeter_lib",
"//closure/library:testing",
],
)
16 changes: 11 additions & 5 deletions closure/templates/test/greeter_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.testSuite');
goog.require('io.bazel.rules.closure.Greeter');

goog.testing.testSuite({

function testGreet() {
var greeter = new io.bazel.rules.closure.Greeter('Justine');
greeter.greet();
assertHTMLEquals('<p>Hello <b>Justine</b>!', document.body.innerHTML);
}
'testGreet': function() {
var greeter = new io.bazel.rules.closure.Greeter('Justine');
greeter.greet();
assertHTMLEquals('<p>Hello <b>Justine</b>!', document.body.innerHTML);
}

}); // goog.testing.testSuite
19 changes: 7 additions & 12 deletions closure/testing/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,17 @@ package(

load("//closure/compiler:closure_js_library.bzl", "closure_js_library")

exports_files(["phantomjs_runner.js"])
exports_files(["empty.html"])

closure_js_library(
name = "phantomjs_jsunit_runner_lib",
name = "phantomjs_jsunit_runner",
srcs = ["phantomjs_jsunit_runner.js"],
language = "ECMASCRIPT5_STRICT",
deps = [
"//closure/library",
"//closure/library:testing",
],
no_closure_library = True,
)

closure_js_library(
name = "phantomjs_runner_lib",
srcs = ["phantomjs_runner.js"],
language = "ECMASCRIPT5_STRICT",
visibility = ["//visibility:private"],
deps = ["//closure/testing/externs:phantom_lib"],
name = "phantomjs_harness",
srcs = ["phantomjs_harness.js"],
no_closure_library = True,
deps = ["//closure/testing/externs:phantomjs"],
)
Loading

0 comments on commit 8143c2d

Please sign in to comment.