| 
									
										
										
										
											2020-02-04 11:45:40 -08:00
										 |  |  | """Npm integration testing
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Returns the manifest path of a file: `workspace/path/to/file` | 
					
						
							|  |  |  | def _to_manifest_path(ctx, file): | 
					
						
							|  |  |  |     if file.short_path.startswith("../"): | 
					
						
							|  |  |  |         # Strip the ../ from short_path to external repository | 
					
						
							|  |  |  |         return file.short_path[3:] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         # Add the repository name for short_path to local repository | 
					
						
							|  |  |  |         return ctx.workspace_name + "/" + file.short_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _npm_integration_test_config_impl(ctx): | 
					
						
							|  |  |  |     if len(ctx.files.test_files) == 0: | 
					
						
							|  |  |  |         fail("No files were found to run under integration testing.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ctx.attr.debug: | 
					
						
							|  |  |  |         for f in ctx.files.test_files: | 
					
						
							|  |  |  |             if f.is_directory: | 
					
						
							|  |  |  |                 fail("In debug mode, directory test_files labels not supported.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     commands = [] | 
					
						
							|  |  |  |     for c in ctx.attr.commands: | 
					
						
							|  |  |  |         commands.append(ctx.expand_location(c, targets = ctx.attr.data)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # pass --define vars to test; these are added to the environment using process.env(). | 
					
						
							|  |  |  |     env_vars = {} | 
					
						
							|  |  |  |     for k in ctx.attr.configuration_env_vars: | 
					
						
							|  |  |  |         if k in ctx.var.keys(): | 
					
						
							|  |  |  |             env_vars[k] = ctx.var[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Serialize configuration file for test runner | 
					
						
							|  |  |  |     ctx.actions.write( | 
					
						
							|  |  |  |         output = ctx.outputs.config, | 
					
						
							|  |  |  |         content = """// npm_integration_test runner config generated by npm_integration_test rule
 | 
					
						
							|  |  |  | module.exports = {{ | 
					
						
							|  |  |  |     testFiles: [ {TMPL_test_files} ], | 
					
						
							|  |  |  |     commands: [ {TMPL_commands} ], | 
					
						
							|  |  |  |     npmPackages: {{ {TMPL_npm_packages} }}, | 
					
						
							|  |  |  |     checkNpmPackages: [ {TMPL_check_npm_packages} ], | 
					
						
							|  |  |  |     envVars: {{ {TMPL_env_vars} }}, | 
					
						
							|  |  |  |     debug: {TMPL_debug}, | 
					
						
							|  |  |  | }}; | 
					
						
							|  |  |  | """.format(
 | 
					
						
							|  |  |  |             TMPL_test_files = ", ".join(["'%s'" % f.short_path for f in ctx.files.test_files]), | 
					
						
							|  |  |  |             TMPL_commands = ", ".join(["'%s'" % s for s in commands]), | 
					
						
							|  |  |  |             TMPL_npm_packages = ", ".join(["'%s': '%s'" % (ctx.attr.npm_packages[n], n.files.to_list()[0].short_path) for n in ctx.attr.npm_packages]), | 
					
						
							|  |  |  |             TMPL_check_npm_packages = ", ".join(["'%s'" % s for s in ctx.attr.check_npm_packages]), | 
					
						
							|  |  |  |             TMPL_env_vars = ", ".join(["'%s': '%s'" % (k, env_vars[k]) for k in env_vars]), | 
					
						
							|  |  |  |             TMPL_debug = "true" if ctx.attr.debug else "false", | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     runfiles = [ctx.outputs.config] + ctx.files.test_files + ctx.files.npm_packages | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [DefaultInfo(runfiles = ctx.runfiles(files = runfiles))] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _NPM_INTEGRATION_TEST_CONFIG_ATTRS = { | 
					
						
							|  |  |  |     "commands": attr.string_list( | 
					
						
							|  |  |  |         default = [], | 
					
						
							|  |  |  |         mandatory = True, | 
					
						
							|  |  |  |         doc = """The list of test commands to run. Defaults to `[]`.""", | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "configuration_env_vars": attr.string_list( | 
					
						
							|  |  |  |         doc = """Pass these configuration environment variables to the resulting test.
 | 
					
						
							|  |  |  |         Chooses a subset of the configuration environment variables (taken from `ctx.var`), which also | 
					
						
							|  |  |  |         includes anything specified via the --define flag. | 
					
						
							|  |  |  |         Note, this can lead to different results for the test.""",
 | 
					
						
							|  |  |  |         default = [], | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "check_npm_packages": attr.string_list( | 
					
						
							|  |  |  |         doc = """A list of npm packages that should be replaced in this test.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This attribute checks that none of the npm packages lists is found in the workspace-under-test's | 
					
						
							|  |  |  | package.json file unlinked to a generated npm package. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This can be used to verify that all npm package artifacts that need to be tested against are indeed | 
					
						
							|  |  |  | replaced in all integration tests. For example, | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | check_npm_packages = [ | 
					
						
							|  |  |  |     "@angular/common", | 
					
						
							|  |  |  |     "@angular/compiler", | 
					
						
							|  |  |  |     "@angular/compiler-cli", | 
					
						
							|  |  |  |     "@angular/core", | 
					
						
							|  |  |  | ], | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | If an `npm_packages` replacement on any package listed is missed then the test will fail. Since listing all | 
					
						
							|  |  |  | npm packages in `npm_packages` is expensive as any change will result in all integration tests re-running, | 
					
						
							|  |  |  | this attribute allows a fine grained `npm_packages` per integration test with the added safety that none | 
					
						
							|  |  |  | are missed for any one test. | 
					
						
							|  |  |  | """,
 | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "data": attr.label_list( | 
					
						
							|  |  |  |         doc = """Data dependencies for test.""", | 
					
						
							|  |  |  |         allow_files = True, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "debug": attr.bool( | 
					
						
							|  |  |  |         doc = """Setup the test for debugging.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If set to true then the package.json replacement are done in-place instead of a tmp folder | 
					
						
							|  |  |  | and the test is not run. This is used to configure the test folder for local testing and debugging. | 
					
						
							|  |  |  | """,
 | 
					
						
							|  |  |  |         default = False, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "npm_packages": attr.label_keyed_string_dict( | 
					
						
							|  |  |  |         doc = """A label keyed string dictionary of npm package replacements to make in the workspace-under-test's
 | 
					
						
							|  |  |  | package.json with npm package targets. The targets should be pkg_tar tar.gz archives. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For example, | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | npm_packages = { | 
					
						
							|  |  |  |     "//packages/common:npm_package_archive": "@angular/common", | 
					
						
							|  |  |  |     "//packages/compiler:npm_package_archive": "@angular/compiler", | 
					
						
							|  |  |  |     "//packages/compiler-cli:npm_package_archive": "@angular/compiler-cli", | 
					
						
							|  |  |  |     "//packages/core:npm_package_archive": "@angular/core", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ```""",
 | 
					
						
							|  |  |  |         allow_files = True, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     "test_files": attr.label( | 
					
						
							|  |  |  |         doc = """A filegroup of all files necessary to run the test.""", | 
					
						
							|  |  |  |         allow_files = True, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _npm_integration_test_config = rule( | 
					
						
							|  |  |  |     implementation = _npm_integration_test_config_impl, | 
					
						
							|  |  |  |     doc = """Generates an npm_integration_test config.""", | 
					
						
							|  |  |  |     attrs = _NPM_INTEGRATION_TEST_CONFIG_ATTRS, | 
					
						
							|  |  |  |     outputs = { | 
					
						
							|  |  |  |         "config": "%{name}.js", | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def npm_integration_test(name, **kwargs): | 
					
						
							|  |  |  |     """Runs an npm integration test.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     See _NPM_INTEGRATION_TEST_CONFIG_ATTRS above for configuration arguments. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     commands = kwargs.pop("commands", []) | 
					
						
							|  |  |  |     configuration_env_vars = kwargs.pop("configuration_env_vars", []) | 
					
						
							|  |  |  |     check_npm_packages = kwargs.pop("check_npm_packages", []) | 
					
						
							|  |  |  |     npm_packages = kwargs.pop("npm_packages", {}) | 
					
						
							|  |  |  |     test_files = kwargs.pop("test_files", []) | 
					
						
							|  |  |  |     data = kwargs.pop("data", []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _npm_integration_test_config( | 
					
						
							|  |  |  |         name = name + ".config", | 
					
						
							|  |  |  |         commands = commands, | 
					
						
							|  |  |  |         configuration_env_vars = configuration_env_vars, | 
					
						
							|  |  |  |         check_npm_packages = check_npm_packages, | 
					
						
							|  |  |  |         data = data, | 
					
						
							|  |  |  |         npm_packages = npm_packages, | 
					
						
							|  |  |  |         test_files = test_files, | 
					
						
							|  |  |  |         visibility = ["//visibility:private"], | 
					
						
							|  |  |  |         tags = ["manual"], | 
					
						
							|  |  |  |         testonly = True, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Config for debug target below | 
					
						
							|  |  |  |     _npm_integration_test_config( | 
					
						
							|  |  |  |         name = name + ".debug.config", | 
					
						
							|  |  |  |         commands = commands, | 
					
						
							|  |  |  |         configuration_env_vars = configuration_env_vars, | 
					
						
							|  |  |  |         check_npm_packages = check_npm_packages, | 
					
						
							|  |  |  |         data = data, | 
					
						
							|  |  |  |         npm_packages = npm_packages, | 
					
						
							|  |  |  |         test_files = test_files, | 
					
						
							|  |  |  |         debug = True, | 
					
						
							|  |  |  |         visibility = ["//visibility:private"], | 
					
						
							|  |  |  |         tags = ["manual"], | 
					
						
							|  |  |  |         testonly = True, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tags = kwargs.pop("tags", []) | 
					
						
							|  |  |  |     npm_deps = ["@npm//tmp"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nodejs_test( | 
					
						
							|  |  |  |         name = name, | 
					
						
							|  |  |  |         data = data + npm_deps + [":%s.config" % name, ":%s.config.js" % name], | 
					
						
							|  |  |  |         tags = tags, | 
					
						
							| 
									
										
										
										
											2020-03-29 13:29:50 -07:00
										 |  |  |         templated_args = ["$(rootpath :%s.config.js)" % name], | 
					
						
							| 
									
										
										
										
											2020-02-04 11:45:40 -08:00
										 |  |  |         entry_point = "//tools/npm_integration_test:test_runner.js", | 
					
						
							|  |  |  |         **kwargs | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Setup a .debug target that sets the debug attribute to True. | 
					
						
							|  |  |  |     # This target must be run with `bazel run` so it is tagged manual. | 
					
						
							|  |  |  |     nodejs_test( | 
					
						
							|  |  |  |         name = name + ".debug", | 
					
						
							|  |  |  |         data = data + npm_deps + [":%s.debug.config" % name, ":%s.debug.config.js" % name], | 
					
						
							|  |  |  |         tags = tags + ["manual", "local"], | 
					
						
							| 
									
										
										
										
											2020-03-29 13:29:50 -07:00
										 |  |  |         templated_args = ["$(rootpath :%s.debug.config.js)" % name], | 
					
						
							| 
									
										
										
										
											2020-02-04 11:45:40 -08:00
										 |  |  |         entry_point = "//tools/npm_integration_test:test_runner.js", | 
					
						
							|  |  |  |         **kwargs | 
					
						
							|  |  |  |     ) |