authelia/internal/suites/webdriver.go
Amir Zarrinkafsh 83488d52a6
refactor(suites): replace selenium with go-rod (#2534)
* refactor(suites): replace selenium with go-rod

This change replaces [tebeka/selenium](https://github.com/tebeka/selenium) with [go-rod](https://github.com/go-rod/rod).

We no longer have a chromedriver/external driver dependency to utilise Selenium as we instead utilise the Chrome Dev Protocol to communicate with the browser.

Rod [documents](https://go-rod.github.io/#/why-rod) benefits of choosing the library as opposed to the available alternatives.
2021-11-06 00:14:42 +11:00

116 lines
2.5 KiB
Go

package suites
import (
"fmt"
"os"
"strings"
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
"github.com/stretchr/testify/require"
)
// RodSession binding a chrome session with devtool protocol.
type RodSession struct {
Launcher *launcher.Launcher
WebDriver *rod.Browser
}
// StartRodWithProxy create a rod/chromedp session.
func StartRodWithProxy(proxy string) (*RodSession, error) {
browserPath := os.Getenv("BROWSER_PATH")
if browserPath == "" {
browserPath = "/usr/bin/chromium-browser"
}
headless := false
trace := true
motion := 0 * time.Second
if os.Getenv("HEADLESS") != "" {
headless = true
trace = false
motion = 0 * time.Second
}
l := launcher.New().
Bin(browserPath).
Proxy(proxy).
Headless(headless).
Devtools(true)
url := l.MustLaunch()
browser := rod.New().
ControlURL(url).
Trace(trace).
SlowMotion(motion).
MustConnect()
browser.MustIgnoreCertErrors(true)
return &RodSession{
Launcher: l,
WebDriver: browser,
}, nil
}
// StartRod create a rod/chromedp session.
func StartRod() (*RodSession, error) {
return StartRodWithProxy("")
}
// Stop stop the rod/chromedp session.
func (rs *RodSession) Stop() error {
err := rs.WebDriver.Close()
if err != nil {
return err
}
rs.Launcher.Cleanup()
return err
}
// WaitElementLocatedByClassName wait an element is located by class name.
func (rs *RodSession) WaitElementLocatedByClassName(t *testing.T, page *rod.Page, className string) *rod.Element {
e, err := page.Element("." + className)
require.NoError(t, err)
require.NotNil(t, e)
return e
}
// WaitElementLocatedByCSSSelector wait an element is located by class name.
func (rs *RodSession) WaitElementLocatedByCSSSelector(t *testing.T, page *rod.Page, cssSelector string) *rod.Element {
e, err := page.Element("#" + cssSelector)
require.NoError(t, err)
require.NotNil(t, e)
return e
}
// WaitElementsLocatedByCSSSelector wait an element is located by CSS selector.
func (rs *RodSession) WaitElementsLocatedByCSSSelector(t *testing.T, page *rod.Page, cssSelector string) rod.Elements {
e, err := page.Elements("#" + cssSelector)
require.NoError(t, err)
require.NotNil(t, e)
return e
}
func (rs *RodSession) waitBodyContains(t *testing.T, page *rod.Page, pattern string) {
text, err := page.MustElementR("body", pattern).Text()
require.NoError(t, err)
require.NotNil(t, text)
if strings.Contains(text, pattern) {
err = nil
} else {
err = fmt.Errorf("body does not contain pattern: %s", pattern)
}
require.NoError(t, err)
}