From 7486686ee9288081636fb69cc98f5d98780ad126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 14 May 2019 12:22:26 +0200 Subject: [PATCH 01/18] test-ui-devperspective: Create UI test to verify Developer perspective --- make/test.mk | 13 ++ test/ui/devperspective/devperspective_test.go | 121 ++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 test/ui/devperspective/devperspective_test.go diff --git a/make/test.mk b/make/test.mk index 62a1c9b..8ceb3d0 100644 --- a/make/test.mk +++ b/make/test.mk @@ -112,6 +112,19 @@ test-operator-source: push-operator-app-registry DEVCONSOLE_OPERATOR_VERSION=$(DEVCONSOLE_OPERATOR_VERSION) \ go test -vet off ${V_FLAG} $(shell go list ./... | grep $(OPSRC_DIR)) -failfast +.PHONY: test-ui-dev-perspective +test-ui-dev-perspective: + $(Q)oc login -u system:admin + $(Q)./hack/install_devconsole/consoledeveloper.sh + $(eval DEVCONSOLE_USERNAME := consoledeveloper) + $(eval DEVCONSOLE_PASSWORD := developer) + $(Q)oc login -u $(DEVCONSOLE_USERNAME) -p $(DEVCONSOLE_PASSWORD) + $(eval CONSOLE_TARGET_PORT := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.port.targetPort}')) + $(eval CONSOLE_HOST := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.host}')) + $(eval OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) + $(Q)OS_CONSOLE_URL=$(OS_CONSOLE_URL) \ + go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast + .PHONY: olm-integration-cleanup olm-integration-cleanup: get-test-namespace ifeq ($(OPENSHIFT_VERSION),3) diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go new file mode 100644 index 0000000..dcfec4a --- /dev/null +++ b/test/ui/devperspective/devperspective_test.go @@ -0,0 +1,121 @@ +package devperspective + +import ( + "fmt" + "os" + "strconv" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/tebeka/selenium" +) + +func TestDevPerspective(t *testing.T) { + chBin := Getenv("CHROMEDRIVER_BINARY", "chromedriver") + chPort, err := strconv.Atoi(Getenv("CHROMEDRIVER_PORT", "9515")) + require.NoError(t, err, "Chromedriver port") + wd, svc := InitSelenium( + t, + chBin, + chPort, + ) + + defer svc.Stop() + defer wd.Quit() + + defaultWait := 10 * time.Second + + startURL := Getenv("OS_CONSOLE_URL", "https://console-openshift-console.apps.pmacik.devcluster.openshift.com") + err = wd.Get(startURL) + require.NoError(t, err, fmt.Sprintf("Open console starting URL: %s", startURL)) + WaitForURLToContain(t, wd, "oauth", defaultWait) + + elem := FindElementBy(t, wd, selenium.ByLinkText, "consoledeveloper") + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + elem.Click() + + elem = FindElementBy(t, wd, selenium.ByID, "inputUsername") + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + SendKeysToElement(t, elem, Getenv("DEVCONSOLE_USERNAME", "consoledeveloper")) + + elem = FindElementBy(t, wd, selenium.ByID, "inputPassword") + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + SendKeysToElement(t, elem, Getenv("DEVONSOLE_PASSWORD", "developer")) + + elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/button[contains(text(),'Log In')]") + elem.Click() + + elem = FindElementBy(t, wd, selenium.ByID, "nav-toggle") + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + elem.Click() + + elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/a[@target][contains(text(),'Developer')]") + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) +} + +func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { + elem, err := wd.FindElement(by, selector) + require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) + return elem +} + +func WaitForElementToBeDisplayed(t *testing.T, wd selenium.WebDriver, element selenium.WebElement, duration time.Duration) { + err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + return element.IsDisplayed() + }, duration) + require.NoError(t, err, fmt.Sprintf("Wait for element %s to be displayed", element)) +} + +func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, duration time.Duration) { + err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + currentURL, err2 := wd.CurrentURL() + return strings.Contains(currentURL, text), err2 + }, duration) + currentURL, err2 := wd.CurrentURL() + require.NoError(t, err2, fmt.Sprintf("Get current URL")) + require.NoError(t, err, fmt.Sprintf("Wait for URL to contain '%s'. The current URL is '%s'.", text, currentURL)) +} + +func SendKeysToElement(t *testing.T, element selenium.WebElement, keys string) { + err := element.SendKeys(keys) + require.NoError(t, err, fmt.Sprintf("Send keys to element '%s'", element)) +} + +func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) (selenium.WebDriver, *selenium.Service) { + + service, err := selenium.NewChromeDriverService(chromedriverPath, chromedriverPort) + require.NoError(t, err) + + chromeOptions := map[string]interface{}{ + "args": []string{ + "--no-cache", + "--no-sandbox", + "--headless", + "--window-size=1920,1080", + "--window-position=0,0", + "--enable-features=NetworkService", + }, + } + + caps := selenium.Capabilities{ + "browserName": "chrome", + "chromeOptions": chromeOptions, + } + + wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", chromedriverPort)) + require.NoError(t, err) + return wd, service +} + +// Getenv returns a value of environment variable, if it exists. +// Returns the default value otherwise. +func Getenv(key string, defaultValue string) string { + value, found := os.LookupEnv(key) + if found { + return value + } + return defaultValue +} From 834f71154aecb4b65a38325ff5a5f4284ad42f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 14 May 2019 12:40:45 +0200 Subject: [PATCH 02/18] test-ui-devperspective: Add github.com/tebeka/selenium to Gopkg.* --- Gopkg.lock | 9 +++++++++ Gopkg.toml | 1 + 2 files changed, 10 insertions(+) diff --git a/Gopkg.lock b/Gopkg.lock index 53c079c..3d62f25 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -757,6 +757,14 @@ revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" version = "v1.3.0" +[[projects]] + digest = "1:6eb2ff006ba643721abefba0ee785c4c122bdbc553172b9f08e21b2c78a76afc" + name = "github.com/tebeka/selenium" + packages = ["."] + pruneopts = "NT" + revision = "2ccea6e0c0e7425dd3bb6ab291215e2048fd8743" + version = "v0.9.3" + [[projects]] digest = "1:00dde67969c6b5ac2d7bfe189a394095d7be3adff2bb915909235cb697e05d13" name = "github.com/toqueteos/trie" @@ -1527,6 +1535,7 @@ "github.com/redhat-developer/devconsole-git/pkg/controller/gitsourceanalysis", "github.com/stretchr/testify/assert", "github.com/stretchr/testify/require", + "github.com/tebeka/selenium", "k8s.io/api/core/v1", "k8s.io/apimachinery/pkg/api/errors", "k8s.io/apimachinery/pkg/apis/meta/v1", diff --git a/Gopkg.toml b/Gopkg.toml index 48b1a0f..404d355 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -10,6 +10,7 @@ required = [ "k8s.io/gengo/args", "sigs.k8s.io/controller-tools/pkg/crd/generator", "github.com/golang/protobuf/proto", + "github.com/tebeka/selenium", ] [[override]] From da105483bd184ef374bab4e6c1da708c0be4e166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 14 May 2019 12:56:25 +0200 Subject: [PATCH 03/18] test-ui-devperspective: Update Gopkg.* with latest github.com/tebeka/selenium --- Gopkg.lock | 22 ++++++++++++++++++---- Gopkg.toml | 4 ++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 3d62f25..ce9c7dd 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -80,6 +80,14 @@ revision = "4b2b341e8d7715fae06375aa633dbb6e91b3fb46" version = "v1.0.0" +[[projects]] + digest = "1:dafc9bfdb2d9816587ca63844a722b36525183e14423b1f356fd9a8a805b6230" + name = "github.com/blang/semver" + packages = ["."] + pruneopts = "NT" + revision = "ba2c2ddd89069b46a7011d4106f6868f17ee1705" + version = "v3.6.1" + [[projects]] digest = "1:13af3d205c774ec0bbda45fee1a4089f3cd9a55c5367b527698b34550ec15e71" name = "github.com/census-instrumentation/opencensus-proto" @@ -758,12 +766,18 @@ version = "v1.3.0" [[projects]] - digest = "1:6eb2ff006ba643721abefba0ee785c4c122bdbc553172b9f08e21b2c78a76afc" + branch = "master" + digest = "1:6cca2701b85cc807c552444eca3273868f7f1251f4c2ed0e8ac4312944a8d807" name = "github.com/tebeka/selenium" - packages = ["."] + packages = [ + ".", + "chrome", + "firefox", + "internal/zip", + "log", + ] pruneopts = "NT" - revision = "2ccea6e0c0e7425dd3bb6ab291215e2048fd8743" - version = "v0.9.3" + revision = "edf31bb7fd715ad505d9190f8d65d13f39a7c825" [[projects]] digest = "1:00dde67969c6b5ac2d7bfe189a394095d7be3adff2bb915909235cb697e05d13" diff --git a/Gopkg.toml b/Gopkg.toml index 404d355..25fa69b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -108,3 +108,7 @@ required = [ "pkg/apis", "pkg/apis/devconsole/v1alpha1", ] + +[[constraint]] + name = "github.com/tebeka/selenium" + branch = "master" From 2fc8f731ed6b5de58a7762c599d2659489b29357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 14 May 2019 13:25:54 +0200 Subject: [PATCH 04/18] test-ui-devperspective: Update steps before test. --- make/test.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/test.mk b/make/test.mk index 8ceb3d0..1bb3e75 100644 --- a/make/test.mk +++ b/make/test.mk @@ -115,13 +115,13 @@ test-operator-source: push-operator-app-registry .PHONY: test-ui-dev-perspective test-ui-dev-perspective: $(Q)oc login -u system:admin - $(Q)./hack/install_devconsole/consoledeveloper.sh + $(Q)sh ./hack/install_devconsole/consoledeveloper.sh $(eval DEVCONSOLE_USERNAME := consoledeveloper) $(eval DEVCONSOLE_PASSWORD := developer) - $(Q)oc login -u $(DEVCONSOLE_USERNAME) -p $(DEVCONSOLE_PASSWORD) $(eval CONSOLE_TARGET_PORT := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.port.targetPort}')) $(eval CONSOLE_HOST := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.host}')) $(eval OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) + $(Q)oc login -u $(DEVCONSOLE_USERNAME) -p $(DEVCONSOLE_PASSWORD) $(Q)OS_CONSOLE_URL=$(OS_CONSOLE_URL) \ go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast From 97900c9e806c9b5272a6ab7ada9601bc91e8e73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 14 May 2019 13:28:00 +0200 Subject: [PATCH 05/18] test-ui-devperspective: Fix Go lint issues. --- test/ui/devperspective/devperspective_test.go | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index dcfec4a..7e6cd39 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -23,8 +23,7 @@ func TestDevPerspective(t *testing.T) { chPort, ) - defer svc.Stop() - defer wd.Quit() + defer tearDown(t, wd, svc) defaultWait := 10 * time.Second @@ -35,7 +34,7 @@ func TestDevPerspective(t *testing.T) { elem := FindElementBy(t, wd, selenium.ByLinkText, "consoledeveloper") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - elem.Click() + ClickToElement(t, elem) elem = FindElementBy(t, wd, selenium.ByID, "inputUsername") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) @@ -46,16 +45,27 @@ func TestDevPerspective(t *testing.T) { SendKeysToElement(t, elem, Getenv("DEVONSOLE_PASSWORD", "developer")) elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/button[contains(text(),'Log In')]") - elem.Click() + ClickToElement(t, elem) elem = FindElementBy(t, wd, selenium.ByID, "nav-toggle") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - elem.Click() + ClickToElement(t, elem) elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/a[@target][contains(text(),'Developer')]") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) } +func tearDown(t *testing.T, wd selenium.WebDriver, svc *selenium.Service) { + err := wd.Quit() + if err != nil { + t.Log(err) + } + err = svc.Stop() + if err != nil { + t.Log(err) + } +} + func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { elem, err := wd.FindElement(by, selector) require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) @@ -84,6 +94,11 @@ func SendKeysToElement(t *testing.T, element selenium.WebElement, keys string) { require.NoError(t, err, fmt.Sprintf("Send keys to element '%s'", element)) } +func ClickToElement(t *testing.T, element selenium.WebElement) { + err := element.Click() + require.NoErrorf(t, err, "Click to element %s", element) +} + func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) (selenium.WebDriver, *selenium.Service) { service, err := selenium.NewChromeDriverService(chromedriverPath, chromedriverPort) From c24debb1413892f7c2e4240f566f451bab75a9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Wed, 15 May 2019 10:04:37 +0200 Subject: [PATCH 06/18] test-ui-devperspective: Install chromedriver and chomium-headless to tools. --- openshift-ci/Dockerfile.tools | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openshift-ci/Dockerfile.tools b/openshift-ci/Dockerfile.tools index d952d1d..b3c1d32 100644 --- a/openshift-ci/Dockerfile.tools +++ b/openshift-ci/Dockerfile.tools @@ -22,6 +22,8 @@ RUN yum install epel-release -y \ kubectl \ yamllint \ python36-virtualenv \ + chromium-headless \ + chromedriver \ && yum clean all # install dep From f3fb51cfbf2ba17cefea34cb07aa3d296c3e6fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Wed, 15 May 2019 15:15:42 +0200 Subject: [PATCH 07/18] test-ui-devperspective: Set CHROMEDRIVER_BINARY to full path --- Dockerfile | 2 ++ make/test.mk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 3d1c3ac..bb346fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,8 @@ RUN yum install epel-release -y \ kubectl \ yamllint \ python36-virtualenv \ + chromium-headless \ + chromedriver \ && yum clean all # install dep diff --git a/make/test.mk b/make/test.mk index 1bb3e75..7185f0c 100644 --- a/make/test.mk +++ b/make/test.mk @@ -118,11 +118,13 @@ test-ui-dev-perspective: $(Q)sh ./hack/install_devconsole/consoledeveloper.sh $(eval DEVCONSOLE_USERNAME := consoledeveloper) $(eval DEVCONSOLE_PASSWORD := developer) + $(eval CHROMEDRIVER_BINARY := /usr/bin/chromedriver) $(eval CONSOLE_TARGET_PORT := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.port.targetPort}')) $(eval CONSOLE_HOST := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.host}')) $(eval OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) $(Q)oc login -u $(DEVCONSOLE_USERNAME) -p $(DEVCONSOLE_PASSWORD) $(Q)OS_CONSOLE_URL=$(OS_CONSOLE_URL) \ + CHROMEDRIVER_BINARY=$(CHROMEDRIVER_BINARY) \ go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast .PHONY: olm-integration-cleanup From 26a1349e21f28cdb031b7a938da8d22255f118ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Wed, 15 May 2019 15:40:54 +0200 Subject: [PATCH 08/18] test-ui-devperspective: Set CHROMEDRIVER_BINARY to full path as a default. --- test/ui/devperspective/devperspective_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index 7e6cd39..ed0bbd8 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -14,7 +14,7 @@ import ( ) func TestDevPerspective(t *testing.T) { - chBin := Getenv("CHROMEDRIVER_BINARY", "chromedriver") + chBin := Getenv("CHROMEDRIVER_BINARY", "/usr/bin/chromedriver") chPort, err := strconv.Atoi(Getenv("CHROMEDRIVER_PORT", "9515")) require.NoError(t, err, "Chromedriver port") wd, svc := InitSelenium( From 6442a2e4de3655590c8cdd7a8819b35d58b21771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Fri, 17 May 2019 11:56:25 +0200 Subject: [PATCH 09/18] test-ui-devperspective: Split test for admin and non-admin user. --- make/test.mk | 30 ++++--- test/ui/devperspective/devperspective_test.go | 88 ++++++++++++++++--- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/make/test.mk b/make/test.mk index 7185f0c..e5fecf8 100644 --- a/make/test.mk +++ b/make/test.mk @@ -112,20 +112,30 @@ test-operator-source: push-operator-app-registry DEVCONSOLE_OPERATOR_VERSION=$(DEVCONSOLE_OPERATOR_VERSION) \ go test -vet off ${V_FLAG} $(shell go list ./... | grep $(OPSRC_DIR)) -failfast -.PHONY: test-ui-dev-perspective -test-ui-dev-perspective: +.PHONY: test-ui-devperspective-admin +test-ui-devperspective-admin: $(Q)oc login -u system:admin $(Q)sh ./hack/install_devconsole/consoledeveloper.sh - $(eval DEVCONSOLE_USERNAME := consoledeveloper) - $(eval DEVCONSOLE_PASSWORD := developer) - $(eval CHROMEDRIVER_BINARY := /usr/bin/chromedriver) + $(eval export DEVCONSOLE_USERNAME := $(OC_LOGIN_USERNAME)) + $(eval export DEVCONSOLE_PASSWORD := $(OC_LOGIN_PASSWORD)) + $(eval export CHROMEDRIVER_BINARY := /usr/bin/chromedriver) $(eval CONSOLE_TARGET_PORT := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.port.targetPort}')) $(eval CONSOLE_HOST := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.host}')) - $(eval OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) - $(Q)oc login -u $(DEVCONSOLE_USERNAME) -p $(DEVCONSOLE_PASSWORD) - $(Q)OS_CONSOLE_URL=$(OS_CONSOLE_URL) \ - CHROMEDRIVER_BINARY=$(CHROMEDRIVER_BINARY) \ - go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast + $(eval export OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) + $(Q)go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast + +.PHONY: test-ui-devperspective-nonadmin +test-ui-devperspective-nonadmin: + $(Q)oc login -u system:admin + $(Q)sh ./hack/install_devconsole/consoledeveloper.sh + $(eval export DEVCONSOLE_USERNAME := consoledeveloper) + $(eval export DEVCONSOLE_PASSWORD := developer) + $(eval export CHROMEDRIVER_BINARY := /usr/bin/chromedriver) + $(eval CONSOLE_TARGET_PORT := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.port.targetPort}')) + $(eval CONSOLE_HOST := $(shell oc get routes console -n openshift-console -o jsonpath='{.spec.host}')) + $(eval export OS_CONSOLE_URL := $(CONSOLE_TARGET_PORT)://$(CONSOLE_HOST)) + $(eval export USER_IS_ADMIN := false) + $(Q)go test -vet off ${V_FLAG} $(shell go list ./... | grep test/ui/devperspective) -failfast .PHONY: olm-integration-cleanup olm-integration-cleanup: get-test-namespace diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index ed0bbd8..462b4f1 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -1,8 +1,12 @@ package devperspective import ( + "bytes" "fmt" + "image" + "image/png" "os" + "path" "strconv" "strings" "testing" @@ -13,10 +17,19 @@ import ( "github.com/tebeka/selenium" ) +var tag string + func TestDevPerspective(t *testing.T) { - chBin := Getenv("CHROMEDRIVER_BINARY", "/usr/bin/chromedriver") - chPort, err := strconv.Atoi(Getenv("CHROMEDRIVER_PORT", "9515")) + tag = Getenv(t, "TAG", fmt.Sprintf("%d", time.Now().Unix())) + userIsAdmin := Getenv(t, "USER_IS_ADMIN", "true") + chBin := Getenv(t, "CHROMEDRIVER_BINARY", "/usr/bin/chromedriver") + chPort, err := strconv.Atoi(Getenv(t, "CHROMEDRIVER_PORT", "9515")) require.NoError(t, err, "Chromedriver port") + + devconsoleUsername := Getenv(t, "DEVCONSOLE_USERNAME", "consoledeveloper") + devconsolePassword := Getenv(t, "DEVCONSOLE_PASSWORD", "developer") + openshiftConsoleURL := Getenv(t, "OS_CONSOLE_URL", "http://localhost") + wd, svc := InitSelenium( t, chBin, @@ -27,22 +40,47 @@ func TestDevPerspective(t *testing.T) { defaultWait := 10 * time.Second - startURL := Getenv("OS_CONSOLE_URL", "https://console-openshift-console.apps.pmacik.devcluster.openshift.com") - err = wd.Get(startURL) - require.NoError(t, err, fmt.Sprintf("Open console starting URL: %s", startURL)) + err = wd.Get(openshiftConsoleURL) + require.NoErrorf(t, err, "Open URL: %s", openshiftConsoleURL) + consoleIsUp := false + for attempt := 0; attempt < 10; attempt++ { + err = wd.Refresh() + require.NoErrorf(t, err, "Refresh URL: %s", openshiftConsoleURL) + el, _ := wd.FindElement(selenium.ByXPATH, "//*[contains(text(),'Application is not available')]") + if el != nil { + t.Logf("Application is not available, try again after 2s.") + time.Sleep(2 * time.Second) + } else { + t.Logf("Application is up.") + consoleIsUp = true + break + } + } + if !consoleIsUp { + require.FailNow(t, "Console is not available.") + } + + require.NoError(t, err, fmt.Sprintf("Open console starting URL: %s", openshiftConsoleURL)) WaitForURLToContain(t, wd, "oauth", defaultWait) - elem := FindElementBy(t, wd, selenium.ByLinkText, "consoledeveloper") + var elem selenium.WebElement + + if userIsAdmin == "true" { + elem = FindElementBy(t, wd, selenium.ByLinkText, "kube:admin") + } else { + elem = FindElementBy(t, wd, selenium.ByLinkText, devconsoleUsername) + } + WaitForElementToBeDisplayed(t, wd, elem, defaultWait) ClickToElement(t, elem) elem = FindElementBy(t, wd, selenium.ByID, "inputUsername") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - SendKeysToElement(t, elem, Getenv("DEVCONSOLE_USERNAME", "consoledeveloper")) + SendKeysToElement(t, elem, devconsoleUsername) elem = FindElementBy(t, wd, selenium.ByID, "inputPassword") WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - SendKeysToElement(t, elem, Getenv("DEVONSOLE_PASSWORD", "developer")) + SendKeysToElement(t, elem, devconsolePassword) elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/button[contains(text(),'Log In')]") ClickToElement(t, elem) @@ -80,8 +118,12 @@ func WaitForElementToBeDisplayed(t *testing.T, wd selenium.WebDriver, element se } func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, duration time.Duration) { + counter := 1 err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { currentURL, err2 := wd.CurrentURL() + //t.Logf("current url = %s", currentURL) + //SaveScreenShotToPNG(t, wd, fmt.Sprintf("%s/%s/%d.png", tag, text, counter)) + counter++ return strings.Contains(currentURL, text), err2 }, duration) currentURL, err2 := wd.CurrentURL() @@ -106,12 +148,14 @@ func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) ( chromeOptions := map[string]interface{}{ "args": []string{ + "--verbose", "--no-cache", "--no-sandbox", "--headless", "--window-size=1920,1080", "--window-position=0,0", - "--enable-features=NetworkService", + "--enable-features=NetworkService", // to ignore invalid HTTPS certificates + //"--whitelisted-ips=''", // to support running in a container }, } @@ -127,10 +171,30 @@ func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) ( // Getenv returns a value of environment variable, if it exists. // Returns the default value otherwise. -func Getenv(key string, defaultValue string) string { +func Getenv(t *testing.T, key string, defaultValue string) string { value, found := os.LookupEnv(key) + var retVal string if found { - return value + retVal = value + } else { + retVal = defaultValue } - return defaultValue + //t.Logf("Using env variable: %s=%s", key, retVal) + return retVal +} + +func SaveScreenShotToPNG(t *testing.T, wd selenium.WebDriver, filename string) { + err := os.MkdirAll(path.Dir(filename), 0775) + require.NoError(t, err, "Create screenshot directory") + // convert []byte to image for saving to file + imgByte, err := wd.Screenshot() + require.NoError(t, err, "Taking screenshot") + img, _, _ := image.Decode(bytes.NewReader(imgByte)) + + //save the imgByte to file + out, err := os.Create(filename) + defer out.Close() + require.NoError(t, err, "Creating a file for the screenshot") + + err = png.Encode(out, img) } From 744fb053fa3818bdb1ffbb88bb93455e83726ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Fri, 17 May 2019 15:30:16 +0200 Subject: [PATCH 10/18] test-ui-devperspective: Updated log outputs for the console app. --- test/ui/devperspective/devperspective_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index 462b4f1..5a64f85 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -48,16 +48,16 @@ func TestDevPerspective(t *testing.T) { require.NoErrorf(t, err, "Refresh URL: %s", openshiftConsoleURL) el, _ := wd.FindElement(selenium.ByXPATH, "//*[contains(text(),'Application is not available')]") if el != nil { - t.Logf("Application is not available, try again after 2s.") + t.Logf("Openshift Console is not available, try again after 2s.") time.Sleep(2 * time.Second) } else { - t.Logf("Application is up.") + t.Logf("Openshift Console is up.") consoleIsUp = true break } } if !consoleIsUp { - require.FailNow(t, "Console is not available.") + require.FailNow(t, "Openshift Console is not available.") } require.NoError(t, err, fmt.Sprintf("Open console starting URL: %s", openshiftConsoleURL)) @@ -179,7 +179,7 @@ func Getenv(t *testing.T, key string, defaultValue string) string { } else { retVal = defaultValue } - //t.Logf("Using env variable: %s=%s", key, retVal) + t.Logf("Using env variable: %s=%s", key, retVal) return retVal } From 2a5b245ada920baba4c3620aae6b0c464e65bf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Mon, 20 May 2019 13:05:57 +0200 Subject: [PATCH 11/18] test-ui-devperspective: Organize code into packages --- test/support/support.go | 20 +++ test/ui/devperspective/devperspective_test.go | 155 ++++-------------- test/ui/selenium.go | 109 ++++++++++++ 3 files changed, 157 insertions(+), 127 deletions(-) create mode 100644 test/support/support.go create mode 100644 test/ui/selenium.go diff --git a/test/support/support.go b/test/support/support.go new file mode 100644 index 0000000..ec99ddb --- /dev/null +++ b/test/support/support.go @@ -0,0 +1,20 @@ +package support + +import ( + "os" + "testing" +) + +// Getenv returns a value of environment variable, if it exists. +// Returns the default value otherwise. +func Getenv(t *testing.T, key string, defaultValue string) string { + value, found := os.LookupEnv(key) + var retVal string + if found { + retVal = value + } else { + retVal = defaultValue + } + t.Logf("Using env variable: %s=%s", key, retVal) + return retVal +} diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index 5a64f85..c1a40c9 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -1,17 +1,13 @@ package devperspective import ( - "bytes" "fmt" - "image" - "image/png" - "os" - "path" "strconv" - "strings" "testing" "time" + "github.com/redhat-developer/devconsole-operator/test/support" + "github.com/redhat-developer/devconsole-operator/test/ui" "github.com/stretchr/testify/require" "github.com/tebeka/selenium" @@ -20,17 +16,17 @@ import ( var tag string func TestDevPerspective(t *testing.T) { - tag = Getenv(t, "TAG", fmt.Sprintf("%d", time.Now().Unix())) - userIsAdmin := Getenv(t, "USER_IS_ADMIN", "true") - chBin := Getenv(t, "CHROMEDRIVER_BINARY", "/usr/bin/chromedriver") - chPort, err := strconv.Atoi(Getenv(t, "CHROMEDRIVER_PORT", "9515")) + tag = support.Getenv(t, "TAG", fmt.Sprintf("%d", time.Now().Unix())) + userIsAdmin := support.Getenv(t, "USER_IS_ADMIN", "true") + chBin := support.Getenv(t, "CHROMEDRIVER_BINARY", "/usr/bin/chromedriver") + chPort, err := strconv.Atoi(support.Getenv(t, "CHROMEDRIVER_PORT", "9515")) require.NoError(t, err, "Chromedriver port") - devconsoleUsername := Getenv(t, "DEVCONSOLE_USERNAME", "consoledeveloper") - devconsolePassword := Getenv(t, "DEVCONSOLE_PASSWORD", "developer") - openshiftConsoleURL := Getenv(t, "OS_CONSOLE_URL", "http://localhost") + devconsoleUsername := support.Getenv(t, "DEVCONSOLE_USERNAME", "consoledeveloper") + devconsolePassword := support.Getenv(t, "DEVCONSOLE_PASSWORD", "developer") + openshiftConsoleURL := support.Getenv(t, "OS_CONSOLE_URL", "http://localhost") - wd, svc := InitSelenium( + wd, svc := ui.InitSelenium( t, chBin, chPort, @@ -61,36 +57,36 @@ func TestDevPerspective(t *testing.T) { } require.NoError(t, err, fmt.Sprintf("Open console starting URL: %s", openshiftConsoleURL)) - WaitForURLToContain(t, wd, "oauth", defaultWait) + ui.WaitForURLToContain(t, wd, "oauth", defaultWait) var elem selenium.WebElement if userIsAdmin == "true" { - elem = FindElementBy(t, wd, selenium.ByLinkText, "kube:admin") + elem = ui.FindElementBy(t, wd, selenium.ByLinkText, "kube:admin") } else { - elem = FindElementBy(t, wd, selenium.ByLinkText, devconsoleUsername) + elem = ui.FindElementBy(t, wd, selenium.ByLinkText, devconsoleUsername) } - WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - ClickToElement(t, elem) + ui.WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + ui.ClickToElement(t, elem) - elem = FindElementBy(t, wd, selenium.ByID, "inputUsername") - WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - SendKeysToElement(t, elem, devconsoleUsername) + elem = ui.FindElementBy(t, wd, selenium.ByID, "inputUsername") + ui.WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + ui.SendKeysToElement(t, elem, devconsoleUsername) - elem = FindElementBy(t, wd, selenium.ByID, "inputPassword") - WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - SendKeysToElement(t, elem, devconsolePassword) + elem = ui.FindElementBy(t, wd, selenium.ByID, "inputPassword") + ui.WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + ui.SendKeysToElement(t, elem, devconsolePassword) - elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/button[contains(text(),'Log In')]") - ClickToElement(t, elem) + elem = ui.FindElementBy(t, wd, selenium.ByXPATH, "//*/button[contains(text(),'Log In')]") + ui.ClickToElement(t, elem) - elem = FindElementBy(t, wd, selenium.ByID, "nav-toggle") - WaitForElementToBeDisplayed(t, wd, elem, defaultWait) - ClickToElement(t, elem) + elem = ui.FindElementBy(t, wd, selenium.ByID, "nav-toggle") + ui.WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + ui.ClickToElement(t, elem) - elem = FindElementBy(t, wd, selenium.ByXPATH, "//*/a[@target][contains(text(),'Developer')]") - WaitForElementToBeDisplayed(t, wd, elem, defaultWait) + elem = ui.FindElementBy(t, wd, selenium.ByXPATH, "//*/a[@target][contains(text(),'Developer')]") + ui.WaitForElementToBeDisplayed(t, wd, elem, defaultWait) } func tearDown(t *testing.T, wd selenium.WebDriver, svc *selenium.Service) { @@ -103,98 +99,3 @@ func tearDown(t *testing.T, wd selenium.WebDriver, svc *selenium.Service) { t.Log(err) } } - -func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { - elem, err := wd.FindElement(by, selector) - require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) - return elem -} - -func WaitForElementToBeDisplayed(t *testing.T, wd selenium.WebDriver, element selenium.WebElement, duration time.Duration) { - err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { - return element.IsDisplayed() - }, duration) - require.NoError(t, err, fmt.Sprintf("Wait for element %s to be displayed", element)) -} - -func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, duration time.Duration) { - counter := 1 - err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { - currentURL, err2 := wd.CurrentURL() - //t.Logf("current url = %s", currentURL) - //SaveScreenShotToPNG(t, wd, fmt.Sprintf("%s/%s/%d.png", tag, text, counter)) - counter++ - return strings.Contains(currentURL, text), err2 - }, duration) - currentURL, err2 := wd.CurrentURL() - require.NoError(t, err2, fmt.Sprintf("Get current URL")) - require.NoError(t, err, fmt.Sprintf("Wait for URL to contain '%s'. The current URL is '%s'.", text, currentURL)) -} - -func SendKeysToElement(t *testing.T, element selenium.WebElement, keys string) { - err := element.SendKeys(keys) - require.NoError(t, err, fmt.Sprintf("Send keys to element '%s'", element)) -} - -func ClickToElement(t *testing.T, element selenium.WebElement) { - err := element.Click() - require.NoErrorf(t, err, "Click to element %s", element) -} - -func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) (selenium.WebDriver, *selenium.Service) { - - service, err := selenium.NewChromeDriverService(chromedriverPath, chromedriverPort) - require.NoError(t, err) - - chromeOptions := map[string]interface{}{ - "args": []string{ - "--verbose", - "--no-cache", - "--no-sandbox", - "--headless", - "--window-size=1920,1080", - "--window-position=0,0", - "--enable-features=NetworkService", // to ignore invalid HTTPS certificates - //"--whitelisted-ips=''", // to support running in a container - }, - } - - caps := selenium.Capabilities{ - "browserName": "chrome", - "chromeOptions": chromeOptions, - } - - wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", chromedriverPort)) - require.NoError(t, err) - return wd, service -} - -// Getenv returns a value of environment variable, if it exists. -// Returns the default value otherwise. -func Getenv(t *testing.T, key string, defaultValue string) string { - value, found := os.LookupEnv(key) - var retVal string - if found { - retVal = value - } else { - retVal = defaultValue - } - t.Logf("Using env variable: %s=%s", key, retVal) - return retVal -} - -func SaveScreenShotToPNG(t *testing.T, wd selenium.WebDriver, filename string) { - err := os.MkdirAll(path.Dir(filename), 0775) - require.NoError(t, err, "Create screenshot directory") - // convert []byte to image for saving to file - imgByte, err := wd.Screenshot() - require.NoError(t, err, "Taking screenshot") - img, _, _ := image.Decode(bytes.NewReader(imgByte)) - - //save the imgByte to file - out, err := os.Create(filename) - defer out.Close() - require.NoError(t, err, "Creating a file for the screenshot") - - err = png.Encode(out, img) -} diff --git a/test/ui/selenium.go b/test/ui/selenium.go new file mode 100644 index 0000000..3e07b53 --- /dev/null +++ b/test/ui/selenium.go @@ -0,0 +1,109 @@ +package ui + +import ( + "bytes" + "fmt" + "image" + "image/png" + "os" + "path" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/tebeka/selenium" +) + +//FindElementBy look for a web element by a given selector and returs it back when found. +func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { + elem, err := wd.FindElement(by, selector) + require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) + return elem +} + +//WaitForElementToBeDisplayed for a given web element to be displayed/visible for a given time duration. +func WaitForElementToBeDisplayed(t *testing.T, wd selenium.WebDriver, element selenium.WebElement, duration time.Duration) { + err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + return element.IsDisplayed() + }, duration) + require.NoError(t, err, fmt.Sprintf("Wait for element %s to be displayed", element)) +} + +//WaitForURLToContain waits for a current URL to contain the given text. It waits for a given time duration. +func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, duration time.Duration) { + counter := 1 + err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + currentURL, err2 := wd.CurrentURL() + counter++ + return strings.Contains(currentURL, text), err2 + }, duration) + currentURL, err2 := wd.CurrentURL() + require.NoError(t, err2, fmt.Sprintf("Get current URL")) + require.NoError(t, err, fmt.Sprintf("Wait for URL to contain '%s'. The current URL is '%s'.", text, currentURL)) +} + +//SendKeysToElement sends keys to a given web element +func SendKeysToElement(t *testing.T, element selenium.WebElement, keys string) { + err := element.SendKeys(keys) + require.NoError(t, err, fmt.Sprintf("Send keys to element '%s'", element)) +} + +//ClickToElement performs a click on a given web element. +func ClickToElement(t *testing.T, element selenium.WebElement) { + err := element.Click() + require.NoErrorf(t, err, "Click to element %s", element) +} + +//InitSelenium creates and initializes a new ChromeDriver service. +func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) (selenium.WebDriver, *selenium.Service) { + + service, err := selenium.NewChromeDriverService(chromedriverPath, chromedriverPort) + require.NoError(t, err) + + chromeOptions := map[string]interface{}{ + "args": []string{ + "--verbose", + "--no-cache", + "--no-sandbox", + "--headless", + "--window-size=1920,1080", + "--window-position=0,0", + "--enable-features=NetworkService", // to ignore invalid HTTPS certificates + //"--whitelisted-ips=''", // to support running in a container + }, + } + + caps := selenium.Capabilities{ + "browserName": "chrome", + "chromeOptions": chromeOptions, + } + + wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", chromedriverPort)) + require.NoError(t, err) + return wd, service +} + +//SaveScreenShotToPNG saves current screen to a given PNG file. +func SaveScreenShotToPNG(t *testing.T, wd selenium.WebDriver, filename string) { + err := os.MkdirAll(path.Dir(filename), 0775) + require.NoError(t, err, "Create screenshot directory") + // convert []byte to image for saving to file + imgByte, err := wd.Screenshot() + require.NoError(t, err, "Take screenshot") + img, _, _ := image.Decode(bytes.NewReader(imgByte)) + + //save the imgByte to file + out, err := os.Create(filename) + defer close(t, out) + + require.NoError(t, err, "Create a file for the screenshot") + + err = png.Encode(out, img) + require.NoError(t, err, "Write screanshot to PNG file") +} + +func close(t *testing.T, f *os.File) { + err := f.Close() + require.NoError(t, err, "Close output file") +} From 1cb9ceaacbd5d0c97f1d2e25535983791f1d1b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Mon, 20 May 2019 13:50:58 +0200 Subject: [PATCH 12/18] test-ui-devperspective: Exclude the UI test from unit tests. --- make/test.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/test.mk b/make/test.mk index e5fecf8..759cde2 100644 --- a/make/test.mk +++ b/make/test.mk @@ -14,7 +14,7 @@ export DEPLOYED_NAMESPACE:= .PHONY: test ## Runs Go package tests and stops when the first one fails test: ./vendor - $(Q)go test -vet off ${V_FLAG} $(shell go list ./... | grep -v -E '(/test/e2e|/test/operatorsource)') -failfast + $(Q)go test -vet off ${V_FLAG} $(shell go list ./... | grep -v -E '(/test/e2e|/test/operatorsource|/test/ui)') -failfast .PHONY: test-coverage ## Runs Go package tests and produces coverage information @@ -26,7 +26,7 @@ test-coverage-html: ./vendor ./out/cover.out $(Q)go tool cover -html=./out/cover.out ./out/cover.out: ./vendor - $(Q)go test ${V_FLAG} -race $(shell go list ./... | grep -v -E '(/test/e2e|/test/operatorsource)') -failfast -coverprofile=cover.out -covermode=atomic -outputdir=./out + $(Q)go test ${V_FLAG} -race $(shell go list ./... | grep -v -E '(/test/e2e|/test/operatorsource|/test/ui)') -failfast -coverprofile=cover.out -covermode=atomic -outputdir=./out .PHONY: get-test-namespace get-test-namespace: ./out/test-namespace From 375eff97b3330127827c4cd97595cf1005a60ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Mon, 20 May 2019 14:15:53 +0200 Subject: [PATCH 13/18] test-ui-devperspective: Include the UI test in e2e tests. --- make/test.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/test.mk b/make/test.mk index 759cde2..a013ac5 100644 --- a/make/test.mk +++ b/make/test.mk @@ -48,6 +48,7 @@ ifeq ($(OPENSHIFT_VERSION),3) $(Q)oc login -u system:admin endif $(Q)operator-sdk test local ./test/e2e --namespace $(TEST_NAMESPACE) --up-local --go-test-flags "-v -timeout=15m" + $(Q)$(MAKE) test-ui-devperspective-admin .PHONY: e2e-setup From 83a06e5d28b9c33cad3f0f7ae19b4df9f85f383f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 21 May 2019 10:37:38 +0200 Subject: [PATCH 14/18] test-ui-devperspective: Implement re-tries for FindElementBy func and switch user to non-admin. --- make/test.mk | 2 +- test/ui/selenium.go | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/make/test.mk b/make/test.mk index a013ac5..249d6fa 100644 --- a/make/test.mk +++ b/make/test.mk @@ -48,7 +48,7 @@ ifeq ($(OPENSHIFT_VERSION),3) $(Q)oc login -u system:admin endif $(Q)operator-sdk test local ./test/e2e --namespace $(TEST_NAMESPACE) --up-local --go-test-flags "-v -timeout=15m" - $(Q)$(MAKE) test-ui-devperspective-admin + $(Q)$(MAKE) test-ui-devperspective-nonadmin .PHONY: e2e-setup diff --git a/test/ui/selenium.go b/test/ui/selenium.go index 3e07b53..4c05d96 100644 --- a/test/ui/selenium.go +++ b/test/ui/selenium.go @@ -17,9 +17,27 @@ import ( //FindElementBy look for a web element by a given selector and returs it back when found. func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { - elem, err := wd.FindElement(by, selector) - require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) - return elem + + maxAttempts := 10 + attemptInterval := 100 * time.Millisecond + + // To avoid a problem where the element is yet not present + counter := 0 + for { + elems, err := wd.FindElements(by, selector) + if err != nil { + if counter <= maxAttempts { + t.Logf("Element for %s=%s not found, trying again...", by, selector) + time.Sleep(attemptInterval) + counter++ + } else { + require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) + return nil + } + } else { + return elems[0] + } + } } //WaitForElementToBeDisplayed for a given web element to be displayed/visible for a given time duration. From 97f867ac302a76a998a81160061a19b4e3d3043a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 21 May 2019 12:23:24 +0200 Subject: [PATCH 15/18] test-ui-devperspective: Harden the condition for FindElementBy function. --- test/ui/selenium.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ui/selenium.go b/test/ui/selenium.go index 4c05d96..53746ac 100644 --- a/test/ui/selenium.go +++ b/test/ui/selenium.go @@ -25,7 +25,7 @@ func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector stri counter := 0 for { elems, err := wd.FindElements(by, selector) - if err != nil { + if err != nil || len(elems) == 0 { if counter <= maxAttempts { t.Logf("Element for %s=%s not found, trying again...", by, selector) time.Sleep(attemptInterval) From 2be9b3e4fae45ee315384376bf522d09a8cff799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 21 May 2019 14:07:31 +0200 Subject: [PATCH 16/18] test-ui-devperspective: Fail test if for element is not found in FindElementBy function. --- test/ui/selenium.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/ui/selenium.go b/test/ui/selenium.go index 53746ac..2b9c3e3 100644 --- a/test/ui/selenium.go +++ b/test/ui/selenium.go @@ -31,8 +31,7 @@ func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector stri time.Sleep(attemptInterval) counter++ } else { - require.NoError(t, err, fmt.Sprintf("Find element by %s=%s", by, selector)) - return nil + require.NoError(t, fmt.Errorf("element for %s=%s not found", by, selector)) } } else { return elems[0] From 65c0827eca5be9a07e692217cd2412470e3bc4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Tue, 21 May 2019 15:30:53 +0200 Subject: [PATCH 17/18] test-ui-devperspective: Make test more verbose on what is doing. --- test/ui/devperspective/devperspective_test.go | 1 + test/ui/selenium.go | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test/ui/devperspective/devperspective_test.go b/test/ui/devperspective/devperspective_test.go index c1a40c9..f2b6846 100644 --- a/test/ui/devperspective/devperspective_test.go +++ b/test/ui/devperspective/devperspective_test.go @@ -36,6 +36,7 @@ func TestDevPerspective(t *testing.T) { defaultWait := 10 * time.Second + t.Logf("Open URL: %s", openshiftConsoleURL) err = wd.Get(openshiftConsoleURL) require.NoErrorf(t, err, "Open URL: %s", openshiftConsoleURL) consoleIsUp := false diff --git a/test/ui/selenium.go b/test/ui/selenium.go index 2b9c3e3..c63d859 100644 --- a/test/ui/selenium.go +++ b/test/ui/selenium.go @@ -17,7 +17,7 @@ import ( //FindElementBy look for a web element by a given selector and returs it back when found. func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector string) selenium.WebElement { - + t.Logf("Find element by %s=%s", by, selector) maxAttempts := 10 attemptInterval := 100 * time.Millisecond @@ -41,14 +41,16 @@ func FindElementBy(t *testing.T, wd selenium.WebDriver, by string, selector stri //WaitForElementToBeDisplayed for a given web element to be displayed/visible for a given time duration. func WaitForElementToBeDisplayed(t *testing.T, wd selenium.WebDriver, element selenium.WebElement, duration time.Duration) { + t.Logf("Wait for element to be displayed") err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { return element.IsDisplayed() }, duration) - require.NoError(t, err, fmt.Sprintf("Wait for element %s to be displayed", element)) + require.NoError(t, err, "Wait for element to be displayed") } //WaitForURLToContain waits for a current URL to contain the given text. It waits for a given time duration. func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, duration time.Duration) { + t.Logf("Wait for URL to contain test '%s'...", text) counter := 1 err := wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { currentURL, err2 := wd.CurrentURL() @@ -62,14 +64,16 @@ func WaitForURLToContain(t *testing.T, wd selenium.WebDriver, text string, durat //SendKeysToElement sends keys to a given web element func SendKeysToElement(t *testing.T, element selenium.WebElement, keys string) { + t.Log("Send keys to element") err := element.SendKeys(keys) - require.NoError(t, err, fmt.Sprintf("Send keys to element '%s'", element)) + require.NoError(t, err, "Send keys to element") } //ClickToElement performs a click on a given web element. func ClickToElement(t *testing.T, element selenium.WebElement) { + t.Log("Click to element") err := element.Click() - require.NoErrorf(t, err, "Click to element %s", element) + require.NoError(t, err, "Click to element") } //InitSelenium creates and initializes a new ChromeDriver service. @@ -103,6 +107,7 @@ func InitSelenium(t *testing.T, chromedriverPath string, chromedriverPort int) ( //SaveScreenShotToPNG saves current screen to a given PNG file. func SaveScreenShotToPNG(t *testing.T, wd selenium.WebDriver, filename string) { + t.Logf("Save screenshot to '%s'", filename) err := os.MkdirAll(path.Dir(filename), 0775) require.NoError(t, err, "Create screenshot directory") // convert []byte to image for saving to file From 171fe19bf41c7663ade49f4a7c7d1253ffc9ccab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Mac=C3=ADk?= Date: Wed, 22 May 2019 13:27:41 +0200 Subject: [PATCH 18/18] test-ui-devperspective: Remove the test from e2e tests. Let's keep the test local only for now. --- make/test.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/make/test.mk b/make/test.mk index 249d6fa..b4f61ae 100644 --- a/make/test.mk +++ b/make/test.mk @@ -48,8 +48,6 @@ ifeq ($(OPENSHIFT_VERSION),3) $(Q)oc login -u system:admin endif $(Q)operator-sdk test local ./test/e2e --namespace $(TEST_NAMESPACE) --up-local --go-test-flags "-v -timeout=15m" - $(Q)$(MAKE) test-ui-devperspective-nonadmin - .PHONY: e2e-setup e2e-setup: e2e-cleanup