Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

WIP: feat(cypress_test): introduce rule #261

Closed
wants to merge 4 commits into from
Closed
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
2 changes: 2 additions & 0 deletions defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ load("//internal/karma:ts_web_test.bzl",
_ts_web_test = "ts_web_test_macro",
_ts_web_test_suite = "ts_web_test_suite")
load("//internal/protobufjs:ts_proto_library.bzl", _ts_proto_library = "ts_proto_library")
load("//internal/cypress_test:cypress_test.bzl", _cypress_test = "cypress_test")

ts_setup_workspace = _ts_setup_workspace
ts_library = _ts_library
Expand All @@ -35,3 +36,4 @@ ts_web_test_suite = _ts_web_test_suite
ts_proto_library = _ts_proto_library
# DO NOT ADD MORE rules here unless they appear in the generated docsite.
# Run yarn skydoc to re-generate the docsite.
cypress_test = _cypress_test
12 changes: 12 additions & 0 deletions examples/integration/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("//:defs.bzl", "ts_library", "cypress_test")

ts_library(
name = "test_lib",
srcs = [":index.spec.ts"],
)

cypress_test(
name = "test",
deps = [":test_lib"],
srcs = []
)
10 changes: 10 additions & 0 deletions examples/integration/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

// declare let it: any;
// declare let describe: any;
declare let cy: any;

describe('My First Test', function() {
it('Visits the Kitchen Sink', function() {
cy.visit('https://example.cypress.io')
})
})
2 changes: 1 addition & 1 deletion examples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Include the output directory in rootDirs so that generated .d.ts files
// can be used for type-checking in the editor, for example the car.proto
// produces a car.d.ts.
"rootDirs": [".", "../bazel-bin/examples"]
"rootDirs": [".", "../bazel-bin/examples"],
}
}

21 changes: 21 additions & 0 deletions internal/cypress_test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

package(default_visibility = ["//visibility:public"])

exports_files([
"cypress_runner.js",
# Exported to be consumed for generating skydoc.
"cypress_test.bzl",
])
76 changes: 76 additions & 0 deletions internal/cypress_test/cypress_runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const fs = require('fs');
const path = require('path');
const cypress = require('cypress');

const UTF8 = {
encoding: 'utf-8'
};

// These exit codes are handled specially by Bazel:
// https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44
const BAZEL_EXIT_TESTS_FAILED = 3;
const BAZEL_EXIT_NO_TESTS_FOUND = 4;
const IBAZEL_NOTIFY_BUILD_SUCCESS = 'IBAZEL_BUILD_COMPLETED SUCCESS';
const IBAZEL_NOTIFY_CHANGES = 'IBAZEL_NOTIFY_CHANGES';

// Set the StackTraceLimit to infinity. This will make stack capturing slower, but more useful.
// Since we are running tests having proper stack traces is very useful and should be always set to
// the maximum (See: https://nodejs.org/api/errors.html#errors_error_stacktracelimit)
Error.stackTraceLimit = Infinity;

async function main(args) {
if (!args.length) {
throw new Error('Spec file manifest expected argument missing');
}
const manifest = require.resolve(args[0]);
const exeRoot = path.dirname(manifest);

const specLocations = fs.readFileSync(manifest, UTF8).split('\n').filter(p =>p.length > 0).map(f => {
return require.resolve(f)
});

const specs = specLocations.filter(f => f.endsWith('spec.js'))

const cypressJsonSettings = {integrationFolder: '.', video: false, screenshots: false, supportFile: false}
fs.writeFileSync(path.join(exeRoot, 'cypress.json'), JSON.stringify(cypressJsonSettings));

const isIBazelMode = Boolean(process.env[IBAZEL_NOTIFY_CHANGES]);

// we cant use open right now due to https://github.com/cypress-io/cypress/issues/1925
if(isIBazelMode) {
await open(exeRoot, specs);
} else {
await run(exeRoot, specs);
}

}

async function run(configFilePath, specs) {
if(specs.length === 0) {
process.exit(BAZEL_EXIT_NO_TESTS_FOUND);
}

const result = await cypress.run({
project: configFilePath,
spec: specs
});

// if no tests failed then it's a pass
if(result.totalFailed > 0) {
process.exit(BAZEL_EXIT_TESTS_FAILED);
} else {
process.exit(0)
}

}

function open(configFilePath, specs) {
cypress.open({
project: configFilePath,
spec: specs
});
}

if (require.main === module) {
main(process.argv.slice(2)).catch(err => console.log(err));
}
99 changes: 99 additions & 0 deletions internal/cypress_test/cypress_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""NodeJS testing

These rules let you run tests outside of a browser. This is typically faster
than launching a test in Karma, for example.
"""
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_test")
load("@build_bazel_rules_nodejs//internal/common:devmode_js_sources.bzl", "devmode_js_sources")
CYPRESS_JSON_CONTENT = "{ \"integrationFolder\": \".\", \"video\": false, \"screenshots\": false, \"supportFile\": false }"

def _short_path_to_manifest_path(ctx, short_path):
if short_path.startswith("../"):
return short_path[3:]
else:
return ctx.workspace_name + "/" + short_path

def _impl(ctx):

conf = ctx.actions.declare_file("cypress.json")
ctx.actions.write(output = ctx.outputs.cypressjson, content = CYPRESS_JSON_CONTENT)

# files = depset(ctx.files.srcs)
# for d in ctx.attr.deps:
# print(d.files)
# if hasattr(d, "node_sources"):
# files += d.node_sources
# elif hasattr(d, "files"):
# files += d.files
files = depset(ctx.files.srcs)
for d in ctx.attr.deps:
if hasattr(d, "node_sources"):
files = depset(transitive = [files, d.node_sources])
elif hasattr(d, "files"):
files = depset(transitive = [files, d.files])

ctx.actions.write(
output = ctx.outputs.executable,
is_executable = True,
content = """#!/usr/bin/env bash
if [ -e "$RUNFILES_MANIFEST_FILE" ]; then
while read line; do
declare -a PARTS=($line)
if [ "${{PARTS[0]}}" == "{TMPL_cypress}" ]; then
readonly CYPRESS=${{PARTS[1]}}
fi
done < $RUNFILES_MANIFEST_FILE
else
readonly CYPRESS=../{TMPL_cypress}
fi
export HOME=$(mktemp -d)
ARGV=()
# Detect that we are running as a test, by using well-known environment
# variables. See go/test-encyclopedia
# Note: in Bazel 0.14 and later, TEST_TMPDIR is set for both bazel test and bazel run
# so we also check for the BUILD_WORKSPACE_DIRECTORY which is set only for bazel run
if [[ ! -z "${{TEST_TMPDIR}}" && ! -n "${{BUILD_WORKSPACE_DIRECTORY}}" ]]; then
ARGV+=( "run" )
fi
# $CYPRESS ${{ARGV[@]}}
echo $CYPRESS
$CYPRESS open
""".format(TMPL_cypress = _short_path_to_manifest_path(ctx, ctx.executable.cypress.short_path)))

cypress_runfiles = [conf] + ctx.files.srcs + ctx.files.data

return [DefaultInfo(
files = depset([ctx.outputs.executable]),
runfiles = ctx.runfiles(
files = cypress_runfiles,
transitive_files = files,
# Propagate karma_bin and its runfiles
collect_data = True,
collect_default = True,
),
executable = ctx.outputs.executable,
)]

cypress_test = rule (
implementation = _impl,
test = True,
# executable = True,
outputs = {"cypressjson": "cypress.json"},
attrs = {
"deps": attr.label_list(),
"srcs": attr.label_list(
doc = "JavaScript source files",
allow_files = [".js"]),
"data": attr.label_list(
doc = "Runtime dependencies",
cfg = "target"),
"cypress": attr.label(
default = Label("//tools/cypress-rule:cypress_bin"),
executable = True,
cfg = "data",
single_file = False,
allow_files = True
),

}
)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"typescript": ">=2.4.2"
},
"dependencies": {
"cypress": "^3.1.0",
"protobufjs": "5.0.0",
"tsickle": "0.25.x",
"tsutils": "2.20.0"
Expand Down
Loading