Skip to content

Commit

Permalink
ui: reintroduce end-to-end UI tests with cypress
Browse files Browse the repository at this point in the history
A recent commit [1] removed the stale, unused end-to-end tests. In their
place, add newly-written tests that can run headlessly in TeamCity (via
Docker) as a quick-failing health check and as a more exhaustive suite.

[1] 3d171b2 (ui: remove unused end-to-end UI tests, 2022-07-25)

Release note: None
  • Loading branch information
sjbarag committed Jul 26, 2022
1 parent c149ddb commit 4e1d960
Show file tree
Hide file tree
Showing 26 changed files with 3,103 additions and 1 deletion.
16 changes: 16 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ workspace(
"@npm_protos": ["pkg/ui/workspaces/db-console/src/js/node_modules"],
"@npm_cluster_ui": ["pkg/ui/workspaces/cluster_ui/node_modules"],
"@npm_db_console": ["pkg/ui/workspaces/db-console/node_modules"],
"@npm_e2e_tests": ["pkg/ui/workspaces/e2e-tests/node_modules"],
},
)

Expand Down Expand Up @@ -263,6 +264,21 @@ yarn_install(
symlink_node_modules = True,
)

yarn_install(
name = "npm_e2e_tests",
args = [
"--offline",
],
data = [
"//pkg/ui:.yarnrc",
"@yarn_cache//:.seed",
],
package_json = "//pkg/ui/workspaces/e2e-tests:package.json",
strict_visibility = False,
yarn_lock = "//pkg/ui/workspaces/e2e-tests:yarn.lock",
symlink_node_modules = True,
)

yarn_install(
name = "npm_protos",
args = [
Expand Down
20 changes: 20 additions & 0 deletions build/teamcity/cockroach/ci/tests/ui_e2e_test_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail

source "$(dirname "${0}")/teamcity-support.sh"
source "./ui_e2e_test_impl.sh"

tc_prepare

tc_start_block "Build Docker image"
build_docker_image
tc_end_block "Build Docker image"

# TeamCity doesn't restore permissions for files retrieved from artifact
# dependencies, so ensure the cockroach binary is executable before running it
# in a Docker container.
chmod a+x upstream_artifacts/cockroach

tc_start_block "Run all Cypress tests"
run_tests
tc_end_block "Run all Cypress tests"
20 changes: 20 additions & 0 deletions build/teamcity/cockroach/ci/tests/ui_e2e_test_health.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail

source "$(dirname "${0}")/teamcity-support.sh"
source "./ui_e2e_test_impl.sh"

tc_prepare

tc_start_block "Build Docker image"
build_docker_image
tc_end_block "Build Docker image"

# TeamCity doesn't restore permissions for files retrieved from artifact
# dependencies, so ensure the cockroach binary is executable before running it
# in a Docker container.
chmod a+x upstream_artifacts/cockroach

tc_start_block "Run Cypress health checks"
run_tests health
tc_end_block "Run Cypress health checks"
25 changes: 25 additions & 0 deletions build/teamcity/cockroach/ci/tests/ui_e2e_test_impl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
function build_docker_image() {
# Buffer noisy output and only print it on failure.
DOCKER_BUILDKIT=1 run docker build \
-f ./pkg/ui/workspaces/e2e-tests/Dockerfile \
-t cockroachdb/cockroach-cypress \
--progress=plain \
$PWD &> artifacts/docker-build.log || (cat artifacts/docker-build.log && false)
rm artifacts/docker-build.log
}

function run_tests() {
SPEC_ARG=""
if [ "health" = "${$1:='EMPTY'}" ]; then
SPEC_ARG="--spec 'cypress/e2e/health-check/**'"
fi

run docker run \
--rm \
-v $PWD/upstream_artifacts:/upstream_artifacts \
-v $PWD/artifacts:/artifacts \
cockroachdb/cockroach-cypress \
--reporter teamcity \
$SPEC_ARG
}
72 changes: 72 additions & 0 deletions pkg/cmd/dev/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"os/signal"
"path"
"path/filepath"
"strings"

"github.com/spf13/cobra"
)
Expand All @@ -39,6 +40,7 @@ func makeUICmd(d *dev) *cobra.Command {
uiCmd.AddCommand(makeUILintCmd(d))
uiCmd.AddCommand(makeUITestCmd(d))
uiCmd.AddCommand(makeUIWatchCmd(d))
uiCmd.AddCommand(makeUIE2eCmd(d))

return uiCmd
}
Expand All @@ -49,6 +51,8 @@ type UIDirectories struct {
clusterUI string
// dbConsole is the absolute path to ./pkg/ui/workspaces/db-console.
dbConsole string
// e2eTests is the absolute path to ./pkg/ui/workspaces/e2e-tests.
e2eTests string
// eslintPlugin is the absolute path to ./pkg/ui/workspaces/eslint-plugin-crdb.
eslintPlugin string
}
Expand All @@ -63,6 +67,7 @@ func getUIDirs(d *dev) (*UIDirectories, error) {
return &UIDirectories{
clusterUI: path.Join(workspace, "./pkg/ui/workspaces/cluster-ui"),
dbConsole: path.Join(workspace, "./pkg/ui/workspaces/db-console"),
e2eTests: path.Join(workspace, "./pkg/ui/workspaces/e2e-tests"),
eslintPlugin: path.Join(workspace, "./pkg/ui/workspaces/eslint-plugin-crdb"),
}, nil
}
Expand Down Expand Up @@ -552,6 +557,73 @@ Replaces 'make ui-test' and 'make ui-test-watch'.`,
return testCmd
}

func makeUIE2eCmd(d *dev) *cobra.Command {
e2eTestCmd := &cobra.Command{
Use: "e2e -- [args passed to Cypress ...]",
Short: "run e2e (Cypress) tests",
Long: strings.TrimSpace(`
Run end-to-end tests with Cypress, spinning up a real local cluster and
launching test in a real browser. Extra flags are passed directly to the
'cypress' binary".
`),
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, commandLine []string) error {
ctx := cmd.Context()
uiDirs, err := getUIDirs(d)
if err != nil {
return err
}

workspace, err := d.getWorkspace(ctx)
if err != nil {
return err
}

// Ensure e2e-tests dependencies are installed
installArgv := buildBazelYarnArgv("--cwd", uiDirs.e2eTests, "install")
logCommand("bazel", installArgv...)
err = d.exec.CommandContextInheritingStdStreams(ctx, "bazel", installArgv...)
if err != nil {
return fmt.Errorf("unable to install NPM dependencies: %w", err)
}

// Build cockroach (relying on Bazel to short-circuit repeated builds)
buildCockroachArgv := []string {
"build",
"//pkg/cmd/cockroach:cockroach",
"--config=with_ui",
}
logCommand("bazel", buildCockroachArgv...)
err = d.exec.CommandContextInheritingStdStreams(ctx, "bazel", buildCockroachArgv...)
if err != nil {
return fmt.Errorf("unable to build cockroach with UI: %w", err)
}

// Run Cypress tests, passing any extra args through to 'cypress'
startCrdbMovrSh := path.Join(uiDirs.e2eTests, "build/start-crdb-movr.sh")
runCypressArgv := append(
[]string { "bazel" },
buildBazelYarnArgv("--cwd", uiDirs.e2eTests, "cy:run")...
)
runCypressArgv = append(runCypressArgv, cmd.Flags().Args()...)

logCommand(startCrdbMovrSh, runCypressArgv...)
env := append(
os.Environ(),
fmt.Sprintf("COCKROACH=%s", path.Join(workspace, "cockroach")),
)
err = d.exec.CommandContextWithEnv(ctx, env, startCrdbMovrSh, runCypressArgv...)
if err != nil {
return fmt.Errorf("error while running Cypress tests: %w", err)
}

return nil
},
}

return e2eTestCmd
}

// buildBazelYarnArgv returns the provided argv formatted so it can be run with
// the bazel-provided version of yarn via `d.exec.CommandContextWithEnv`, e.g.:
//
Expand Down
1 change: 1 addition & 0 deletions pkg/ui/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ test_suite(
tests = [
"//pkg/ui/workspaces/cluster-ui:lint",
"//pkg/ui/workspaces/db-console:lint",
"//pkg/ui/workspaces/e2e-tests:lint",
],
)

Expand Down
1 change: 1 addition & 0 deletions pkg/ui/not-yarn-workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set -euo pipefail
yarn --cwd workspaces/db-console/src/js install
yarn --cwd workspaces/cluster-ui install
yarn --cwd workspaces/db-console install
yarn --cwd workspaces/e2e-tests install
)

cat << "EOF"
Expand Down
17 changes: 17 additions & 0 deletions pkg/ui/workspaces/e2e-tests/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"root": true,
"extends": "@cockroachlabs/eslint-config",
"settings": {
"react": {
"pragma": "React",
"version": "17.0"
}
},
"rules": {
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off"
}
}
2 changes: 2 additions & 0 deletions pkg/ui/workspaces/e2e-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
videos
screenshots
26 changes: 26 additions & 0 deletions pkg/ui/workspaces/e2e-tests/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
load("@npm_e2e_tests//eslint:index.bzl", "eslint_test")

eslint_test(
name = "lint",
data = [
".eslintrc.json",
"prettier.config.js",
"cypress",
"cypress.config.ts",
"//pkg/ui/workspaces/eslint-plugin-crdb",
"@npm_e2e_tests//@cockroachlabs/eslint-config",
"@npm_e2e_tests//@typescript-eslint/eslint-plugin",
"@npm_e2e_tests//@typescript-eslint/parser",
"@npm_e2e_tests//eslint-plugin-prettier",
"@npm_e2e_tests//eslint-plugin-react",
"@npm_e2e_tests//eslint-plugin-react-hooks",
"@npm_e2e_tests//prettier",
],
templated_args = [
"--ext .ts",
"-c",
"$$(rlocation $(rootpath .eslintrc.json))",
"$$(rlocation $(rootpath cypress))",
"$$(rlocation $(rootpath cypress.config.ts))",
],
)
51 changes: 51 additions & 0 deletions pkg/ui/workspaces/e2e-tests/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# WARNING:
# This Dockerfile must be built from the root of cockroachdb.git with a prebuilt
# cockroach binary at ./upstream_artifactsl/cockroach. Running it from other
# directories or without a prebuilt cockroach binary will cause errors.
#
# Build (from the root of cockroach.git):
# $ DOCKER_BUILDKIT=1 docker build \
# -f ./pkg/ui/workspaces/e2e-tests/Dockerfile \
# -t cockroachdb/cockroach-ci-ui \
# $PWD
#
# Run Locally (from the root of cockroach.git):
# $ docker run \
# --rm \
# -it \
# -v $PWD:/upstream_artifacts \
# -v $PWD/pkg/ui/workspaces/e2e-tests/cypress:/cypress
# cockroachdb/cockroach-ci-ui
#
# Run in TeamCity (from the root of cockroach.git):
# $ docker run \
# --rm \
# -it \
# -v $PWD/upstream_artifacts:/upstream_artifacts \
# -v $PWD/artifacts:/artifacts \
# cockroachdb/cockroach-ci-ui

FROM cypress/browsers:node16.14.2-slim-chrome100-ff99-edge

# Install CRDB prerequisites
RUN apt install libresolv-wrapper

# Add the tests and install NPM dependencies
WORKDIR /cypress
COPY --chown=node ./pkg/ui/yarn-vendor ./yarn-vendor/
COPY --chown=node ./pkg/ui/workspaces/e2e-tests ./
ADD ./pkg/ui/.yarnrc ./
RUN yarn install

ENV IS_DOCKER=1

# Use the compiled CRDB binary from a previous TC job via Artifact Dependency:
# TODO(barag): include a TC link here
# bazel-bin/pkg/cmd/cockroach/cockroach_/cockroach=>upstream_artifacts
ENV COCKROACH=/upstream_artifacts/cockroach

VOLUME /artifacts

# Execute 'yarn test' by default, allowing extra arguments to be appended during
# 'docker run'.
ENTRYPOINT ["/usr/local/bin/yarn", "test"]
6 changes: 6 additions & 0 deletions pkg/ui/workspaces/e2e-tests/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/*
!upstream_artifacts
!pkg/ui/.yarnrc
!pkg/ui/yarn-vendor
!pkg/ui/workspaces/e2e-tests
pkg/ui/workspaces/e2e-tests/node_modules
Loading

0 comments on commit 4e1d960

Please sign in to comment.