diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3ec83c..de0f363 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v3 - name: install deps run: | - apt update && apt install jq -y + apt-get update && apt-get install jq chromium -y make REVISION=$GITHUB_SHA install - name: make test run: | diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 3518d14..7e59c18 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v3 - name: install deps run: | - apt update && apt install jq -y + apt-get update && apt-get install jq chromium -y make REVISION=$GITHUB_SHA install - name: make test run: | diff --git a/Makefile b/Makefile index 5d187d3..4ef32ee 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ btr: build tag release # TEST test: test_prereq - go test `go list ./... | grep -v */generated/` -v -mod=readonly -race -coverprofile=.coverage/out | go-junit-report > .coverage/report-junit.xml && \ + go test ./... -v -mod=readonly -race -coverprofile=.coverage/out | go-junit-report > .coverage/report-junit.xml && \ gocov convert .coverage/out | gocov-xml > .coverage/report-cobertura.xml test_ci: diff --git a/README.md b/README.md index dc6d0b0..a4622f3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=dnitsch_uistrategy&metric=bugs)](https://sonarcloud.io/summary/new_code?id=dnitsch_uistrategy) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=dnitsch_uistrategy&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=dnitsch_uistrategy) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=dnitsch_uistrategy&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=dnitsch_uistrategy) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=dnitsch_uistrategy&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=dnitsch_uistrategy) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=dnitsch_uistrategy&metric=coverage)](https://sonarcloud.io/summary/new_code?id=dnitsch_uistrategy) + # UI Strategy - Beta [![Go Report Card](https://goreportcard.com/badge/github.com/dnitsch/uistrategy)](https://goreportcard.com/report/github.com/dnitsch/uistrategy) diff --git a/auth.go b/auth.go index 9ce8dad..33169ab 100644 --- a/auth.go +++ b/auth.go @@ -1,6 +1,10 @@ package uistrategy -import "github.com/go-rod/rod" +import ( + "fmt" + + "github.com/go-rod/rod" +) type Auth struct { Username Element `yaml:"username" json:"username"` @@ -50,6 +54,9 @@ func (web *Web) doLocalAuth(auth Auth) (*LoggedInPage, error) { // SP initiated will be simpler as you can omit the idpUrl // the flow will follow redirects func (web *Web) doIdpAuth(auth Auth) (*LoggedInPage, error) { + if auth.IdpSelector == nil { + return nil, fmt.Errorf("idpSelector must be specified") + } page := web.browser.MustPage(web.config.BaseUrl + auth.Navigate).MustWaitLoad() lp := &LoggedInPage{web, page, UIStrategyError{}} @@ -58,7 +65,7 @@ func (web *Web) doIdpAuth(auth Auth) (*LoggedInPage, error) { idpSelect, err := determinActionElement(lp.log, page, *auth.IdpSelector) if err != nil { - web.log.Errorf("unable to find IdpSelector field, by selector: %v", *auth.IdpSelector.Selector) + web.log.Errorf("unable to find IdpSelector field, by selector: %v, error: %v", auth.IdpSelector.Selector, err.Error()) return nil, err } idpSelect.MustClick() diff --git a/auth_test.go b/auth_test.go new file mode 100644 index 0000000..6cc0db1 --- /dev/null +++ b/auth_test.go @@ -0,0 +1,164 @@ +package uistrategy_test + +import ( + "bytes" + "net/http" + "net/http/httptest" + "testing" + + log "github.com/dnitsch/simplelog" + "github.com/dnitsch/uistrategy" + "github.com/dnitsch/uistrategy/internal/util" +) + +func TestDoLoginBasic(t *testing.T) { + t.Parallel() + ttests := map[string]struct { + baseConf func(t *testing.T, url string) uistrategy.BaseConfig + auth func(t *testing.T, url string) *uistrategy.Auth + handler func(t *testing.T) http.Handler + // auth func(t *testing.T, url string) *uistrategy.Auth + }{ + "local login": { + func(t *testing.T, url string) uistrategy.BaseConfig { + return uistrategy.BaseConfig{ + BaseUrl: url, + LauncherConfig: &uistrategy.WebConfig{ + Headless: true, + }, + } + }, + func(t *testing.T, url string) *uistrategy.Auth { + return &uistrategy.Auth{ + Username: uistrategy.Element{ + Selector: util.Str("#username"), + Value: util.Str("test"), + }, + Password: uistrategy.Element{ + Selector: util.Str("#password"), + Value: util.Str("test"), + }, + Navigate: "/login", + Submit: uistrategy.Element{ + Selector: util.Str("#submit"), + }, + } + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(localLoginHtml) + }) + mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(`Hello!`)) + }) + return mux + }, + }, + "idp auth": { + func(t *testing.T, url string) uistrategy.BaseConfig { + return uistrategy.BaseConfig{ + BaseUrl: url, + LauncherConfig: &uistrategy.WebConfig{ + Headless: true, + }, + } + }, + func(t *testing.T, url string) *uistrategy.Auth { + return &uistrategy.Auth{ + Username: uistrategy.Element{ + Selector: util.Str("#username"), + Value: util.Str("test"), + }, + Password: uistrategy.Element{ + Selector: util.Str("#password"), + Value: util.Str("test"), + }, + Navigate: "/login-idp", + IdpManaged: true, + IdpSelector: &uistrategy.Element{ + Selector: util.Str("#idp-login"), + }, + IdpUrl: url, + Submit: uistrategy.Element{ + Selector: util.Str("#submit"), + }, + } + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/login-idp", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(idpLoginHtml) + }) + mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(`Hello!`)) + }) + return mux + }, + }, + "mfa Login": { + func(t *testing.T, url string) uistrategy.BaseConfig { + return uistrategy.BaseConfig{ + BaseUrl: url, + LauncherConfig: &uistrategy.WebConfig{ + Headless: true, + }, + } + }, + func(t *testing.T, url string) *uistrategy.Auth { + return &uistrategy.Auth{ + Username: uistrategy.Element{ + Selector: util.Str("#username"), + Value: util.Str("test"), + }, + Password: uistrategy.Element{ + Selector: util.Str("#password"), + Value: util.Str("test"), + }, + Navigate: "/login-idp", + IdpManaged: true, + MfaSelector: &uistrategy.Element{ + Selector: util.Str("#mfa"), + }, + IdpSelector: &uistrategy.Element{ + Selector: util.Str("#idp-login"), + }, + IdpUrl: url, + Submit: uistrategy.Element{ + Selector: util.Str("#submit"), + }, + } + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/login-idp", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(mfaLogin) + }) + mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(`Hello!`)) + }) + return mux + }, + }, + } + for name, tt := range ttests { + t.Run(name, func(t *testing.T) { + ts := httptest.NewServer(tt.handler(t)) + defer ts.Close() + uiWeb := uistrategy.New(tt.baseConf(t, ts.URL)).WithLogger(log.New(&bytes.Buffer{}, log.ErrorLvl)) + lp, err := uiWeb.DoAuth(tt.auth(t, ts.URL)) + if err != nil { + t.Errorf("failed to do auth: %v", err) + } + if lp == nil { + t.Errorf("logged in page - got nil expected not nil") + } + }) + } +} diff --git a/cmd/uistrategy/uistrategy.go b/cmd/uistrategy/uistrategy.go index 6b62411..78a1137 100644 --- a/cmd/uistrategy/uistrategy.go +++ b/cmd/uistrategy/uistrategy.go @@ -18,7 +18,7 @@ var ( Use: "uistrategy", RunE: runActions, Short: "executes a series of actions against a setup config", - Long: ``, + Long: `executes a series of instructions against a any number of paths under the same host. supports multiple login options - basic/Idp/MFA e.g. `, } ) diff --git a/cmd/uistrategy/uistrategy_test.go b/cmd/uistrategy/uistrategy_test.go index fff3829..ad5c011 100644 --- a/cmd/uistrategy/uistrategy_test.go +++ b/cmd/uistrategy/uistrategy_test.go @@ -1,32 +1,146 @@ package cmd import ( + "bytes" + "io" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" "testing" - "github.com/spf13/cobra" + "github.com/dnitsch/uistrategy" + "github.com/dnitsch/uistrategy/internal/util" + "gopkg.in/yaml.v2" ) -func Test_runActions_integration(t *testing.T) { - tests := []struct { - name string - path string +func helperTestSeed(conf *uistrategy.UiStrategyConf) string { + b, _ := yaml.Marshal(conf) + dir, _ := os.MkdirTemp("", "uiseeder-test") + file := filepath.Join(dir, "uiseeder.yml") + _ = os.WriteFile(file, b, 0777) + return file +} + +func Test_runActions(t *testing.T) { + tests := map[string]struct { + path func(t *testing.T, baseUrl string) string + handler func(t *testing.T) http.Handler + additionalArgs []string }{ - { - name: "integration without configmanager", - path: "../../test/integration.yml", + "simple test with 1 action": { + func(t *testing.T, baseUrl string) string { + conf := &uistrategy.UiStrategyConf{ + Setup: uistrategy.BaseConfig{ + BaseUrl: baseUrl, + LauncherConfig: &uistrategy.WebConfig{ + Headless: true, + }, + }, + Actions: []*uistrategy.ViewAction{ + { + Name: "test get", + Navigate: "/get/index.html", + ElementActions: []*uistrategy.ElementAction{ + { + Name: "get input id", + // SkipOnErrorMessage: , + CaptureOutput: false, + Element: uistrategy.Element{ + Selector: util.Str("//*/input"), + }, + }, + }, + }, + }, + } + return helperTestSeed(conf) + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/get/index.html", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(``)) + }) + return mux + }, + []string{}, + }, + "verbose with 1 action": { + func(t *testing.T, baseUrl string) string { + conf := &uistrategy.UiStrategyConf{ + Setup: uistrategy.BaseConfig{ + BaseUrl: baseUrl, + LauncherConfig: &uistrategy.WebConfig{ + Headless: true, + }, + }, + Actions: []*uistrategy.ViewAction{ + { + Name: "test get", + Navigate: "/get/index.html", + ElementActions: []*uistrategy.ElementAction{ + { + Name: "get input id", + // SkipOnErrorMessage: , + CaptureOutput: false, + Element: uistrategy.Element{ + Selector: func(input string) *string { return &input }("//*/input"), + }, + }, + }, + }, + }, + } + return helperTestSeed(conf) + }, + func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/get/index.html", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write([]byte(``)) + }) + return mux + }, + []string{"-v"}, }, - // { - // name: "integration with configmanager", - // path: "../../test/integration-with-configmanager.yml", - // }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - path = tt.path - verbose = true - if e := runActions(&cobra.Command{}, []string{}); e != nil { - t.Errorf("%v", e) + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + ts := httptest.NewServer(tt.handler(t)) + defer ts.Close() + + path = tt.path(t, ts.URL) + stdout, errout := &bytes.Buffer{}, &bytes.Buffer{} + cmd := rootCmd + args := []string{"-i", path} + args = append(args, tt.additionalArgs...) + cmd.SetArgs(args) + cmd.SetErr(errout) + cmd.SetOut(stdout) + if _, err := cmd.ExecuteC(); err != nil { + t.Errorf("uiseeder cmd failed: %v", err) } }) } } + +func TestVersion(t *testing.T) { + b := new(bytes.Buffer) + cmd := rootCmd + cmd.SetArgs([]string{"version"}) + cmd.SetErr(b) + cmd.SetOut(b) + _, err := cmd.ExecuteC() + if err != nil { + t.Errorf("...") + } + out, _ := io.ReadAll(b) + if !strings.Contains(string(out), "Version:") { + t.Errorf("version not shown correctly") + } + if !strings.Contains(string(out), "Revision:") { + t.Errorf("revision not shown correctly") + } +} diff --git a/cmd/uistrategy/version.go b/cmd/uistrategy/version.go index bfe4e3a..a70a56e 100644 --- a/cmd/uistrategy/version.go +++ b/cmd/uistrategy/version.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "os" "github.com/dnitsch/uistrategy/internal/config" "github.com/spf13/cobra" @@ -16,8 +15,8 @@ var ( Short: fmt.Sprintf("Get version number %s", config.SELF_NAME), Long: `Version and Revision number of the installed CLI`, Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Version: %s\nRevision: %s\n", Version, Revision) - os.Exit(0) + fmt.Fprint(cmd.OutOrStdout(), fmt.Sprintf("Version: %s\nRevision: %s\n", Version, Revision)) + // os.Exit(0) }, } ) diff --git a/go.mod b/go.mod index 963adcd..888ed04 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( golang.org/x/net v0.5.0 // indirect golang.org/x/sys v0.4.0 // indirect golang.org/x/text v0.6.0 // indirect + gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 061348c..142107a 100644 --- a/go.sum +++ b/go.sum @@ -113,5 +113,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/cmdutil/cmdutil.go b/internal/cmdutil/cmdutil.go index afeba24..d23f67a 100644 --- a/internal/cmdutil/cmdutil.go +++ b/internal/cmdutil/cmdutil.go @@ -2,7 +2,6 @@ package cmdutil import ( "context" - "fmt" "io" "github.com/dnitsch/configmanager" @@ -15,10 +14,7 @@ type ConfManager interface { } func RunActions(ui *uistrategy.Web, conf *uistrategy.UiStrategyConf) error { - if err := ui.Drive(context.Background(), conf.Auth, conf.Actions); len(err.Error()) > 0 { - return fmt.Errorf(err.Error()) - } - return nil + return ui.Drive(context.Background(), conf.Auth, conf.Actions) } // YamlParseInput will return a filled pointer with Unmarshalled data diff --git a/test/idp.html b/test/idp.html new file mode 100644 index 0000000..a5a7300 --- /dev/null +++ b/test/idp.html @@ -0,0 +1,46 @@ + + + + + + Page Title + + + + + + + + + + + \ No newline at end of file diff --git a/test/scratch.js b/test/scratch.js new file mode 100644 index 0000000..0020a98 --- /dev/null +++ b/test/scratch.js @@ -0,0 +1,10 @@ +$('#idp-login').click(function() { + $('#idp-login').css({ + visibility: "hidden", + display: "none" + }); + $('#login-form').css({ + display: "block" + + }) +}); \ No newline at end of file diff --git a/uistrategy.go b/uistrategy.go index 3471a90..f7593e3 100644 --- a/uistrategy.go +++ b/uistrategy.go @@ -139,7 +139,7 @@ type Web struct { // with the provided BaseConfig func New(conf BaseConfig) *Web { _ = util.InitDirDeps() - url := newLauncher(conf.LauncherConfig).NoSandbox(conf.LauncherConfig.NoSandbox).MustLaunch() + url := newLauncher(conf.LauncherConfig).MustLaunch() browser := rod.New(). ControlURL(url). MustConnect().NoDefaultDevice() @@ -175,6 +175,9 @@ func newLauncher(webconf *WebConfig) *launcher.Launcher { if webconf.Headless { l.Headless(true) } + if webconf.NoSandbox { + l.NoSandbox(webconf.NoSandbox) + } } return l @@ -215,6 +218,10 @@ func (e *UIStrategyError) Error() string { return "" } +func (e *UIStrategyError) hasError() bool { + return len(e.errorMap) > 0 +} + // Drive runs a single UIStrategy in the same logged in session // returns a custom error type with details of errors per action func (web *Web) Drive(ctx context.Context, auth *Auth, allActions []*ViewAction) error { @@ -240,7 +247,11 @@ func (web *Web) Drive(ctx context.Context, auth *Auth, allActions []*ViewAction) // send to report builder here web.buildReport(allActions) // logOut - return &page.errors + // return errors to caller for visibility if any + if page.errors.hasError() { + return &page.errors + } + return nil } // PerformAction handles a single action on Navigate'd page/view of SPA diff --git a/uistrategy_samples_test.go b/uistrategy_samples_test.go deleted file mode 100644 index 1e9e2db..0000000 --- a/uistrategy_samples_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package uistrategy_test - -var testHtml_style = []byte(` - - - - - Collections - Acme - PocketBase - - - - - - - - - - - - - - - - -
id
testField1
created
updated
No records found.
- - - -
`) - -var testHtml_noStyle = []byte(` - - - - - Collections - Acme - PocketBase - - - - - - - - - - - - - - - - -
id
testField1
created
updated
No records found.
- - - -
`) diff --git a/uistrategy_test.go b/uistrategy_test.go index d50edcc..4939cb3 100644 --- a/uistrategy_test.go +++ b/uistrategy_test.go @@ -1,10 +1,10 @@ package uistrategy_test import ( + "bytes" "context" "net/http" "net/http/httptest" - "os" "testing" log "github.com/dnitsch/simplelog" @@ -12,106 +12,8 @@ import ( "github.com/dnitsch/uistrategy/internal/util" ) -var ( - testAuth = &uistrategy.Auth{ - Username: uistrategy.Element{ - Value: util.Str(`test@example.com`), - Selector: util.Str(`//*[@class="app-body"]/div[1]/main/div/form/div[2]/input`), - }, - RequireConfirm: true, - Password: uistrategy.Element{ - - Value: util.Str(`P4s$w0rd123!`), - Selector: util.Str(`//*[@class="app-body"]/div[1]/main/div/form/div[3]/input`), - }, - ConfirmPassword: uistrategy.Element{ - Value: util.Str(`P4s$w0rd123!`), - Selector: util.Str(`//*[@class="app-body"]/div[1]/main/div/form/div[4]/input`), - }, - Navigate: `/_/#/login`, - Submit: uistrategy.Element{ - Selector: util.Str(`#app > div > div > div.page-wrapper.full-page.center-content > main > div > form > button`), - }, - } - testActions = []*uistrategy.ViewAction{ - { - Name: "create test collection", - Navigate: `/_/?#/collections`, - ElementActions: []*uistrategy.ElementAction{{ - Name: "create new collection", - Element: uistrategy.Element{ - Selector: util.Str(`#app > div > div > div.page-wrapper.center-content > main > div > button`), - }, - }, - { - Name: "Name it test", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-header > form > div > input`), - Value: util.Str(`test`), - }, - // InputText: util.Str("test"), - }, - { - Name: "Save it", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-header > form > div > input`), - // Value: util.Str(`test`), - }, - }, - { - Name: "Add New Field", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-content > div > div > button`), - }, - }, - { - Name: "Name Field testField1", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-content > div > div > div.accordions > div > div > form > div > div:nth-child(2) > div > input`), - Value: util.Str(`testField1`), - }, - }, - { - Name: "Click Done", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-content > div > div > div.accordions > div > div > form > div > div.col-sm-4.txt-right > div.inline-flex.flex-gap-sm.flex-nowrap > button.btn.btn-sm.btn-outline.btn-expanded-sm`), - }, - }, - { - Name: "Click Create collection", - Element: uistrategy.Element{ - Selector: util.Str(`body > div.overlays > div:nth-child(2) > div > div.overlay-panel.overlay-panel-lg.colored-header.compact-header.collection-panel > div.overlay-panel-section.panel-footer > button.btn.btn-expanded`), - }, - }, - }, - }, - } - testBaseConfig = uistrategy.BaseConfig{BaseUrl: "http://localhost:8090", ContinueOnError: false} -) - -// func Test_DoAuth(t *testing.T) { -// tests := map[string]struct { -// auth *uistrategy.Auth -// }{ -// "register path": { -// auth: testAuth, -// }, -// "no auth": {nil}, -// } -// for name, tt := range tests { -// t.Run(name, func(t *testing.T) { -// ui := uistrategy.New(testBaseConfig).WithLogger(log.New(os.Stderr, log.DebugLvl)) -// p, e := ui.DoAuth(tt.auth) -// if e != nil { -// t.Errorf("wanted %v to be ", e) -// } -// fmt.Println(p) -// }) -// } -// } - func Test_NoAuthSimulate(t *testing.T) { - l := log.New(os.Stderr, log.DebugLvl) + l := log.New(&bytes.Buffer{}, log.DebugLvl) tests := map[string]struct { name string auth *uistrategy.Auth @@ -128,7 +30,7 @@ func Test_NoAuthSimulate(t *testing.T) { mux.HandleFunc("/route", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Write(testHtml_style) + w.Write(pocketBaseStyle) }) return mux }, @@ -141,10 +43,10 @@ func Test_NoAuthSimulate(t *testing.T) { Navigate: `/route`, ElementActions: []*uistrategy.ElementAction{ { - Name: "asset collection is created and present in sidebar", + Name: "Click Button", Assert: true, Element: uistrategy.Element{ - Selector: util.Str(`//*[@class='sidebar-content']/*[contains(., 'test')]/span`), + Selector: util.Str(`//*[@id="app"]/div/div/aside/footer/button/./span[text() = 'New collection']`), }, }, { @@ -190,9 +92,52 @@ func Test_NoAuthSimulate(t *testing.T) { }, }}, }, + expect: "following errors occured:\n\n\tin view: asset collection is created and present in sidebar, performing action: //*[@class='sidebar-content']/*[contains(., 'test')]/span, failed on: element not found", + }, + "not found but continueOnError": { + auth: nil, + handler: func(t *testing.T) http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("/route", func(w http.ResponseWriter, r *http.Request) { + + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(pocketBaseStyle) + }) + return mux + }, + baseConf: func(t *testing.T, url string) uistrategy.BaseConfig { + return uistrategy.BaseConfig{BaseUrl: url, ContinueOnError: true, LauncherConfig: &uistrategy.WebConfig{Headless: true}} + }, + actions: []*uistrategy.ViewAction{ + { + Name: "test route", + Navigate: `/route`, + ElementActions: []*uistrategy.ElementAction{ + { + Name: "Found element", + Assert: true, + Element: uistrategy.Element{ + Selector: util.Str(`//*[@id="app"]/div/div/aside/footer/button/./span[text() = 'New collection']`), + }, + }, + { + Name: "not found id", + Assert: true, + Element: uistrategy.Element{ + Selector: util.Str(`#notfound`), + }, + }, + { + Name: "assert field testField1 is created", + Element: uistrategy.Element{ + Selector: util.Str(`//*[@class='page-wrapper']//span[contains(., 'testField1')]`), + }, + Assert: true, + }, + }, + }}, + expect: "following errors occured:\n\n\tin view: not found id, performing action: #notfound, failed on: element not found", }, - // test iframe - // test with auth } for name, tt := range tests { @@ -205,7 +150,7 @@ func Test_NoAuthSimulate(t *testing.T) { if err.Error() != tt.expect { t.Errorf("got: %v\n\nwant: %v", err, nil) } - t.Logf("error: %s \n\nmatches the expected \n\noutput: %s", err.Error(), tt.expect) + // t.Logf("error: %s \n\nmatches the expected \n\noutput: %s", err.Error(), tt.expect) return } }) diff --git a/x_ui_setup_test.go b/x_ui_setup_test.go new file mode 100644 index 0000000..c4e7fc0 --- /dev/null +++ b/x_ui_setup_test.go @@ -0,0 +1,123 @@ +package uistrategy_test + +var pocketBaseStyle = []byte(` +
id
testField1
created
updated
No records found.
+
`) + +var localLoginHtml = []byte(` + + + + + Page Title + + + + + +
+ + + +
+ + +`) + +var idpLoginHtml = []byte(` + + + + + Page Title + + + + + + + + + +`) + +var mfaLogin = []byte(` + + + + + Page Title + + + + + + + + + + +`)