Skip to content

Commit

Permalink
fix(cypress): allow for async cypress plugins
Browse files Browse the repository at this point in the history
cypress_repository now fails if cypress verify fails
set the HOME env variable since cypress writes files to it
remove unused includeScreenshots / includeVideos variables
browserify files are no longer included in test output files
screenshots/videos are stored directory in TEST_UNDECLARED_OUTPUTS_DIR
  • Loading branch information
Dan Muller authored and alexeagle committed Aug 10, 2020
1 parent 88c19f1 commit 4fd4653
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 62 deletions.
2 changes: 2 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ load("//packages/cypress:index.bzl", "cypress_repository")
cypress_repository(
name = "cypress",
cypress_bin = "@cypress_deps//:node_modules/cypress/bin/cypress",
# Currently cypress cannot be installed on our Linux/Windows CI machines
fail_on_error = False,
)

#
Expand Down
4 changes: 2 additions & 2 deletions packages/cypress/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ pkg_npm(
srcs = [
"index.bzl",
"package.json",
"//packages/cypress:internal/cypress-install.js",
"//packages/cypress:internal/cypress_repository.bzl",
"//packages/cypress:internal/install-cypress.js",
"//packages/cypress:internal/plugins/base.js",
"//packages/cypress:internal/plugins/index.template.js",
"//packages/cypress:internal/run-cypress.js",
Expand All @@ -90,8 +90,8 @@ pkg_npm(
"plugins/base.js",
])""",
substitutions = {
"@build_bazel_rules_nodejs//packages/cypress:internal/cypress-install.js": "TEMPLATED_node_modules_workspace_name//@bazel/cypress:internal/cypress-install.js",
"@build_bazel_rules_nodejs//packages/cypress:internal/cypress_repository.bzl": "//packages/cypress:internal/cypress_repository.bzl",
"@build_bazel_rules_nodejs//packages/cypress:internal/install-cypress.js": "TEMPLATED_node_modules_workspace_name//@bazel/cypress:internal/install-cypress.js",
"@build_bazel_rules_nodejs//packages/cypress:internal/plugins/base.js": "TEMPLATED_node_modules_workspace_name//@bazel/cypress:internal/plugins/base.js",
"@build_bazel_rules_nodejs//packages/cypress:internal/plugins/index.template.js": "TEMPLATED_node_modules_workspace_name//@bazel/cypress:internal/plugins/index.template.js",
"@build_bazel_rules_nodejs//packages/cypress:internal/run-cypress.js": "TEMPLATED_node_modules_workspace_name//@bazel/cypress:internal/run-cypress.js",
Expand Down
23 changes: 15 additions & 8 deletions packages/cypress/internal/cypress_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ load("@build_bazel_rules_nodejs//internal/node:node_labels.bzl", "get_node_label
def _cypress_repository_impl(repository_ctx):
node = repository_ctx.path(get_node_label(repository_ctx))

cypress_install = "packages/cypress/internal/cypress-install.js"
install_cypress = "packages/cypress/internal/install-cypress.js"
repository_ctx.template(
cypress_install,
repository_ctx.path(repository_ctx.attr._cypress_install),
install_cypress,
repository_ctx.path(repository_ctx.attr._install_cypress),
{},
)

Expand All @@ -36,10 +36,13 @@ def _cypress_repository_impl(repository_ctx):
)

exec_result = repository_ctx.execute(
[node, cypress_install, repository_ctx.path(repository_ctx.attr.cypress_bin)],
[node, install_cypress, repository_ctx.path(repository_ctx.attr.cypress_bin)],
quiet = repository_ctx.attr.quiet,
)

if exec_result.return_code != 0 and repository_ctx.attr.fail_on_error:
fail("\ncypress_repository exited with code: {}\n\nstdout:\n{}\n\nstderr:\n{}\n\n".format(exec_result.return_code, exec_result.stdout, exec_result.stderr))

cypress_repository = repository_rule(
implementation = _cypress_repository_impl,
attrs = {
Expand All @@ -48,17 +51,21 @@ cypress_repository = repository_rule(
allow_single_file = True,
default = "@npm//:node_modules/cypress/bin/cypress",
),
"fail_on_error": attr.bool(
default = True,
doc = "If the repository rule should allow errors",
),
"quiet": attr.bool(
default = True,
doc = "If stdout and stderr should be printed to the terminal",
),
"_cypress_install": attr.label(
allow_single_file = True,
default = "//packages/cypress:internal/cypress-install.js",
),
"_cypress_web_test": attr.label(
allow_single_file = True,
default = "//packages/cypress:internal/template.cypress_web_test.bzl",
),
"_install_cypress": attr.label(
allow_single_file = True,
default = "//packages/cypress:internal/install-cypress.js",
),
},
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* cypress-install is responsible for creating an external repository from which a cypress_web_test
* install-cypress is responsible for creating an external repository from which a cypress_web_test
* can be loaded. The script invokes `cypress install` to download and install the cypress binary
* and subsequently calls cypress verify to ensure the binary is runnable.
*
Expand Down Expand Up @@ -47,7 +47,12 @@ exports_files([
_cypress_web_test = "cypress_web_test_global_cache",
)
cypress_web_test = _cypress_web_test`)

const env = {
PATH: `${dirname(nodePath)}:${process.env.PATH}`,
};
const spawnOptions = {
env,
stdio: [process.stdin, process.stdout, process.stderr],
shell: process.env.SHELL
};
Expand All @@ -71,6 +76,7 @@ function installSandboxedCypressCache() {
const env = {
CYPRESS_CACHE_FOLDER: join(cwd, 'cypress-cache'),
PATH: `${dirname(nodePath)}:${process.env.PATH}`,
DEBUG: 'cypress:*'
}

const spawnOptions =
Expand All @@ -91,9 +97,7 @@ function installSandboxedCypressCache() {
};

let CYPRESS_RUN_BINARY;
const cacheFiles = [];
walkDir(env.CYPRESS_CACHE_FOLDER, (filePath) => {
cacheFiles.push(filePath);
if (basename(filePath) === 'Cypress') {
if (CYPRESS_RUN_BINARY) {
throw new Error(`More than one cypress executable found: ${CYPRESS_RUN_BINARY} ${filePath}`)
Expand All @@ -107,12 +111,19 @@ function installSandboxedCypressCache() {
throw new Error(`No cypress executable found.`);
}

const verify = spawnSync(`${cypressBin}`, ['verify'], spawnOptions);
spawnOptions.env.CYPRESS_RUN_BINARY = CYPRESS_RUN_BINARY;

const verify = spawnSync(cypressBin, ['verify'], spawnOptions);

if (verify.status !== 0) {
throw new Error(`cypress verify failed`);
}

const cacheFiles = [];
walkDir(env.CYPRESS_CACHE_FOLDER, (filePath) => {
cacheFiles.push(filePath);
});

writeFileSync('index.bzl', `load(
"//:packages/cypress/internal/cypress_web_test.bzl",
_cypress_web_test = "cypress_web_test",
Expand Down
31 changes: 13 additions & 18 deletions packages/cypress/internal/plugins/index.template.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const fs = require('fs');
const {join, basename, normalize} = require('path');
const {join, normalize} = require('path');

const basePluginShortPath = 'TEMPLATED_pluginsFile';
const integrationFileShortPaths = TEMPLATED_integrationFileShortPaths;
Expand All @@ -12,31 +11,27 @@ const browserifyFactory = require(normalize(`TEMPLATED_@cypress/browserify-prepr
const browserify = browserifyFactory(browserifyFactory.defaultOptions);

module.exports = (on, config) => {
// Load in the user's cypress plugin
config = basePlugin(on, config);
// Set env variables needed usually set by for `bazel test` invocations
// (they are not set automatically for `bazel run`).
process.env.RUNFILES_DIR = process.env.RUNFILES_DIR || join(cwd, '../');
process.env.RUNFILES_MANIFEST_FILE =
process.env.RUNFILES_MANIFEST_FILE || join(cwd, '../', 'MANIFEST');

// Set test files to tests passed as `srcs`
config.integrationFolder = cwd;
config.testFiles = integrationFileShortPaths;

// Set screenshots folder to a writable directory
const screenshotsFolder = join(process.env['TEST_UNDECLARED_OUTPUTS_DIR'], 'screenshots');
fs.mkdirSync(screenshotsFolder);
config.screenshotsFolder = screenshotsFolder;

// Set videos folder to a writable directory
const videosFolder = join(process.env['TEST_UNDECLARED_OUTPUTS_DIR'], 'videos');
fs.mkdirSync(videosFolder);
config.videosFolder = videosFolder;

// Chrome sandboxing must be disabled for execution during bazel test.
config.chromeWebSecurity = false;
// Set screenshots/videos folder to a writable directory
config.screenshotsFolder = process.env['TEST_UNDECLARED_OUTPUTS_DIR'] || process.env.RUNFILES_DIR;
config.videosFolder = process.env['TEST_UNDECLARED_OUTPUTS_DIR'] || process.env.RUNFILES_DIR;

// Set file preprocessing output path to writable directory.
on('file:preprocessor', (file) => {
file.outputPath = join(process.env['TEST_UNDECLARED_OUTPUTS_DIR'], basename(file.outputPath));
file.outputPath =
join(process.env['TEST_TMPDIR'], file.outputPath.split('/bundles/').slice(1).join());
return browserify(file);
});

return config;
// Load in the user's cypress plugin
return basePlugin(on, config);
};
6 changes: 3 additions & 3 deletions packages/cypress/internal/run-cypress.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const [node, entry, configFilePath, pluginsFilePath, cypressExecutable, ...args]
if (cypressExecutable) {
process.env.CYPRESS_RUN_BINARY =
join(process.cwd(), cypressExecutable.replace('external/', '../'));
process.env.CYPRESS_CACHE_FOLDER =
join(process.env.CYPRESS_RUN_BINARY.split('/cypress-cache/')[0], '/cypress-cache');
process.env.HOME = process.env['TEST_TMPDIR'];
}

console.log(process.argv);


const pluginsFile = runfiles.resolveWorkspaceRelative(pluginsFilePath).replace(process.cwd(), '.');
const configFile = runfiles.resolveWorkspaceRelative(configFilePath).replace(process.cwd(), '.');

Expand Down
35 changes: 8 additions & 27 deletions packages/cypress/internal/template.cypress_web_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ def _cypress_plugin_impl(ctx):
template = ctx.file._plugin_template,
substitutions = {
"TEMPLATED_@cypress/browserify-preprocessor": "${cwd}/../cypress_deps/node_modules/@cypress/browserify-preprocessor/index",
"TEMPLATED_includeScreenshots": "true" if ctx.attr.include_screenshots else "false",
"TEMPLATED_includeVideos": "true" if ctx.attr.include_video else "false",
"TEMPLATED_integrationFileShortPaths": "[\n {files}\n]".format(files = ",\n ".join(integration_files_short_paths)),
"TEMPLATED_pluginsFile": plugins_file.short_path,
},
Expand All @@ -52,13 +50,6 @@ def _cypress_plugin_impl(ctx):
files = depset([ctx.outputs.plugin]),
)]

# Avoid using non-normalized paths (workspace/../other_workspace/path)
def _to_manifest_path(ctx, file):
if file.short_path.startswith("../"):
return file.short_path[3:]
else:
return ctx.workspace_name + "/" + file.short_path

_cypress_plugin = rule(
implementation = _cypress_plugin_impl,
outputs = {"plugin": "%{name}_cypress_plugin.js"},
Expand All @@ -67,8 +58,6 @@ _cypress_plugin = rule(
allow_single_file = [".json"],
mandatory = True,
),
"include_screenshots": attr.bool(default = False),
"include_video": attr.bool(default = False),
"plugins_file": attr.label(
default = Label("@build_bazel_rules_nodejs//packages/cypress:internal/plugins/base.js"),
allow_single_file = True,
Expand All @@ -89,8 +78,6 @@ def cypress_web_test(
name,
config_file,
srcs = [],
include_screenshots = False,
include_video = False,
plugins_file = Label("@build_bazel_rules_nodejs//packages/cypress:internal/plugins/base.js"),
cypress = Label("TEMPLATED_node_modules_workspace_name//cypress:cypress"),
cypress_browserify_preprocessor = Label("TEMPLATED_node_modules_workspace_name//@cypress/browserify-preprocessor"),
Expand All @@ -106,8 +93,6 @@ def cypress_web_test(
name = cypress_plugin,
srcs = srcs,
tags = tags,
include_screenshots = include_screenshots,
include_video = include_video,
plugins_file = plugins_file,
config_file = config_file,
testonly = True,
Expand All @@ -123,14 +108,14 @@ def cypress_web_test(
cypress_browserify_preprocessor,
cypress_cache,
cypress_executable,
":{cypress_plugin}".format(cypress_plugin = cypress_plugin),
":{config_file}".format(config_file = config_file),
"{cypress_plugin}".format(cypress_plugin = cypress_plugin),
"{config_file}".format(config_file = config_file),
] + srcs,
entry_point = "@build_bazel_rules_nodejs//packages/cypress:internal/run-cypress.js",
templated_args = [
"--nobazel_patch_module_resolver",
"$(rootpath :{config_file})".format(config_file = config_file),
"$(rootpath :{cypress_plugin})".format(cypress_plugin = cypress_plugin),
"$(rootpath {config_file})".format(config_file = config_file),
"$(rootpath {cypress_plugin})".format(cypress_plugin = cypress_plugin),
"$(rootpath {cypress_executable})".format(cypress_executable = cypress_executable),
] + templated_args,
**kwargs
Expand All @@ -140,8 +125,6 @@ def cypress_web_test_global_cache(
name,
config_file,
srcs = [],
include_screenshots = False,
include_video = False,
plugins_file = Label("@build_bazel_rules_nodejs//packages/cypress:plugins/base.js"),
cypress = Label("TEMPLATED_node_modules_workspace_name//cypress:cypress"),
cypress_browserify_preprocessor = Label("TEMPLATED_node_modules_workspace_name//@cypress/browserify-preprocessor"),
Expand All @@ -155,8 +138,6 @@ def cypress_web_test_global_cache(
name = cypress_plugin,
srcs = srcs,
tags = tags,
include_screenshots = include_screenshots,
include_video = include_video,
plugins_file = plugins_file,
config_file = config_file,
testonly = True,
Expand All @@ -170,14 +151,14 @@ def cypress_web_test_global_cache(
plugins_file,
cypress,
cypress_browserify_preprocessor,
":{cypress_plugin}".format(cypress_plugin = cypress_plugin),
":{config_file}".format(config_file = config_file),
"{cypress_plugin}".format(cypress_plugin = cypress_plugin),
"{config_file}".format(config_file = config_file),
] + srcs,
entry_point = "@build_bazel_rules_nodejs//packages/cypress:internal/run-cypress.js",
templated_args = [
"--nobazel_patch_module_resolver",
"$(rootpath :{config_file})".format(config_file = config_file),
"$(rootpath :{cypress_plugin})".format(cypress_plugin = cypress_plugin),
"$(rootpath {config_file})".format(config_file = config_file),
"$(rootpath {cypress_plugin})".format(cypress_plugin = cypress_plugin),
] + templated_args,
**kwargs
)

0 comments on commit 4fd4653

Please sign in to comment.