authelia/internal/suites/webdriver.go
Amir Zarrinkafsh 54694c4fca
[MISC] Ignore errcheck recommendations for legacy code (#893)
* [MISC] Ignore errcheck recommendations for legacy code
Some of this is likely intended to stay how it is, some could use refactoring, for now we will mark is and ignore it from the linter to be potentially addressed in the future.

* [MISC] Ensure files are gofmt-ed
2020-04-22 13:33:14 +10:00

194 lines
5.4 KiB
Go

package suites
import (
"context"
"errors"
"fmt"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/tebeka/selenium"
"github.com/tebeka/selenium/chrome"
)
// WebDriverSession binding a selenium service and a webdriver.
type WebDriverSession struct {
service *selenium.Service
WebDriver selenium.WebDriver
}
// StartWebDriverWithProxy create a selenium session
func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error) {
service, err := selenium.NewChromeDriverService("/usr/bin/chromedriver", port)
if err != nil {
return nil, err
}
browserPath := os.Getenv("BROWSER_PATH")
if browserPath == "" {
browserPath = "/usr/bin/chromium-browser"
}
chromeCaps := chrome.Capabilities{
Path: browserPath,
}
chromeCaps.Args = append(chromeCaps.Args, "--ignore-certificate-errors")
if os.Getenv("HEADLESS") != "" {
chromeCaps.Args = append(chromeCaps.Args, "--headless")
chromeCaps.Args = append(chromeCaps.Args, "--no-sandbox")
}
if proxy != "" {
chromeCaps.Args = append(chromeCaps.Args, fmt.Sprintf("--proxy-server=%s", proxy))
}
caps := selenium.Capabilities{}
caps.AddChrome(chromeCaps)
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
service.Stop() //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
panic(err)
}
return &WebDriverSession{
service: service,
WebDriver: wd,
}, nil
}
// StartWebDriver create a selenium session
func StartWebDriver() (*WebDriverSession, error) {
return StartWebDriverWithProxy("", 4444)
}
// Stop stop the selenium session
func (wds *WebDriverSession) Stop() error {
err := wds.WebDriver.Quit()
if err != nil {
return err
}
return wds.service.Stop()
}
// WithWebdriver run some actions against a webdriver
func WithWebdriver(fn func(webdriver selenium.WebDriver) error) error {
wds, err := StartWebDriver()
if err != nil {
return err
}
defer wds.Stop() //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
return fn(wds.WebDriver)
}
// Wait wait until condition holds true
func (wds *WebDriverSession) Wait(ctx context.Context, condition selenium.Condition) error {
done := make(chan error, 1)
go func() {
done <- wds.WebDriver.Wait(condition)
}()
select {
case <-ctx.Done():
return errors.New("waiting timeout reached")
case err := <-done:
return err
}
}
func (wds *WebDriverSession) waitElementLocated(ctx context.Context, t *testing.T, by, value string) selenium.WebElement {
var el selenium.WebElement
err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) {
var err error
el, err = driver.FindElement(by, value)
if err != nil {
if strings.Contains(err.Error(), "no such element") {
return false, nil
}
return false, err
}
return el != nil, nil
})
require.NoError(t, err)
require.NotNil(t, el)
return el
}
func (wds *WebDriverSession) waitElementsLocated(ctx context.Context, t *testing.T, by, value string) []selenium.WebElement {
var el []selenium.WebElement
err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) {
var err error
el, err = driver.FindElements(by, value)
if err != nil {
if strings.Contains(err.Error(), "no such element") {
return false, nil
}
return false, err
}
return el != nil, nil
})
require.NoError(t, err)
require.NotNil(t, el)
return el
}
// WaitElementLocatedByID wait an element is located by id
func (wds *WebDriverSession) WaitElementLocatedByID(ctx context.Context, t *testing.T, id string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByID, id)
}
// WaitElementLocatedByTagName wait an element is located by tag name
func (wds *WebDriverSession) WaitElementLocatedByTagName(ctx context.Context, t *testing.T, tagName string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByTagName, tagName)
}
// WaitElementLocatedByClassName wait an element is located by class name
func (wds *WebDriverSession) WaitElementLocatedByClassName(ctx context.Context, t *testing.T, className string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByClassName, className)
}
// WaitElementLocatedByLinkText wait an element is located by link text
func (wds *WebDriverSession) WaitElementLocatedByLinkText(ctx context.Context, t *testing.T, linkText string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByLinkText, linkText)
}
// WaitElementLocatedByCSSSelector wait an element is located by class name
func (wds *WebDriverSession) WaitElementLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByCSSSelector, cssSelector)
}
// WaitElementsLocatedByCSSSelector wait an element is located by CSS selector
func (wds *WebDriverSession) WaitElementsLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) []selenium.WebElement {
return wds.waitElementsLocated(ctx, t, selenium.ByCSSSelector, cssSelector)
}
// WaitElementTextContains wait the text of an element contains a pattern
func (wds *WebDriverSession) WaitElementTextContains(ctx context.Context, t *testing.T, element selenium.WebElement, pattern string) {
err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) {
text, err := element.Text()
if err != nil {
return false, err
}
return strings.Contains(text, pattern), nil
})
require.NoError(t, err)
}