Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
infalmo committed Nov 13, 2020
1 parent 3636bc5 commit 68d8791
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 61 deletions.
14 changes: 9 additions & 5 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,17 @@ func Example_race_selectors() {
page.MustElement("#id_password").MustInput(password).MustPress(input.Enter)

// It will keep retrying until one selector has found a match
page.Race().MustElement(".nav-user-icon-base", func(el *rod.Element) {
elm := page.Race().Element(".nav-user-icon-base").
Element("[data-cy=sign-in-error]").
MustDo()

if elm.MustMatches(".nav-user-icon-base") {
// print the username after successful login
fmt.Println(*el.MustAttribute("title"))
}).MustElement("[data-cy=sign-in-error]", func(el *rod.Element) {
fmt.Println(*elm.MustAttribute("title"))
} else if elm.MustMatches("[data-cy=sign-in-error]") {
// when wrong username or password
panic(el.MustText())
}).MustDo()
panic(elm.MustText())
}
}

// Rod uses mouse cursor to simulate clicks, so if a button is moving because of animation, the click may not work as expected.
Expand Down
33 changes: 13 additions & 20 deletions must.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,38 +489,31 @@ func (p *Page) MustElementsByJS(js string, params ...interface{}) Elements {
}

// MustElement is similar to Element
func (rc *RaceContext) MustElement(selector string, callback func(*Element)) *RaceContext {
return rc.Element(selector, func(el *Element) error {
callback(el)
return nil
})
func (rc *RaceContext) MustElement(selector string) *RaceContext {
return rc.Element(selector)
}

// MustElementX is similar to ElementX
func (rc *RaceContext) MustElementX(selector string, callback func(*Element)) *RaceContext {
return rc.ElementX(selector, func(el *Element) error {
callback(el)
return nil
})
func (rc *RaceContext) MustElementX(selector string) *RaceContext {
return rc.ElementX(selector)
}

// MustElementR is similar to ElementR
func (rc *RaceContext) MustElementR(selector, regex string, callback func(*Element)) *RaceContext {
return rc.ElementR(selector, regex, func(el *Element) error {
callback(el)
return nil
})
func (rc *RaceContext) MustElementR(selector, regex string) *RaceContext {
return rc.ElementR(selector, regex)
}

// MustElementByJS is similar to ElementByJS
func (rc *RaceContext) MustElementByJS(js string, params []interface{}, callback func(*Element) error) *RaceContext {
return rc.ElementByJS(Eval(js, params...), callback)
func (rc *RaceContext) MustElementByJS(js string, params []interface{}) *RaceContext {
return rc.ElementByJS(Eval(js, params...))
}

// MustDo is similar to Do
func (rc *RaceContext) MustDo() *Page {
utils.E(rc.Do())
return rc.page
func (rc *RaceContext) MustDo() *Element {
el, err := rc.Do()
utils.E(err)

return el
}

// MustMove is similar to Move
Expand Down
35 changes: 16 additions & 19 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,6 @@ func (p *Page) Search(from, to int, queries ...string) (Elements, error) {

type raceBranch struct {
condition func() (*Element, error)
callback func(*Element) error
}

// RaceContext stores the branches to race
Expand All @@ -333,55 +332,53 @@ func (p *Page) Race() *RaceContext {
return &RaceContext{page: p, noSleepPage: p.Sleeper(nil)}
}

// Element the doc is similar to MustElement but has a callback when a match is found
func (rc *RaceContext) Element(selector string, callback func(*Element) error) *RaceContext {
// Element the doc is similar to MustElement
func (rc *RaceContext) Element(selector string) *RaceContext {
rc.branches = append(rc.branches, &raceBranch{
func() (*Element, error) { return rc.noSleepPage.Element(selector) },
callback,
})
return rc
}

// ElementX the doc is similar to ElementX but has a callback when a match is found
func (rc *RaceContext) ElementX(selector string, callback func(*Element) error) *RaceContext {
// ElementX the doc is similar to ElementX
func (rc *RaceContext) ElementX(selector string) *RaceContext {
rc.branches = append(rc.branches, &raceBranch{
func() (*Element, error) { return rc.noSleepPage.ElementX(selector) },
callback,
})
return rc
}

// ElementR the doc is similar to ElementR but has a callback when a match is found
func (rc *RaceContext) ElementR(selector, regex string, callback func(*Element) error) *RaceContext {
// ElementR the doc is similar to ElementR
func (rc *RaceContext) ElementR(selector, regex string) *RaceContext {
rc.branches = append(rc.branches, &raceBranch{
func() (*Element, error) { return rc.noSleepPage.ElementR(selector, regex) },
callback,
})
return rc
}

// ElementByJS the doc is similar to MustElementByJS but has a callback when a match is found
func (rc *RaceContext) ElementByJS(opts *EvalOptions, callback func(*Element) error) *RaceContext {
// ElementByJS the doc is similar to MustElementByJS
func (rc *RaceContext) ElementByJS(opts *EvalOptions) *RaceContext {
rc.branches = append(rc.branches, &raceBranch{
func() (*Element, error) { return rc.noSleepPage.ElementByJS(opts) },
callback,
})
return rc
}

// Do the race
func (rc *RaceContext) Do() error {
return utils.Retry(rc.page.ctx, rc.page.sleeper(), func() (stop bool, err error) {
func (rc *RaceContext) Do() (*Element, error) {
var el *Element
err := utils.Retry(rc.page.ctx, rc.page.sleeper(), func() (stop bool, err error) {
for _, branch := range rc.branches {
el, err := branch.condition()
if err == nil {
return true, branch.callback(el)
} else if !errors.Is(err, &ErrElementNotFound{}) {
bEl, err := branch.condition()
if err == nil || !errors.Is(err, &ErrElementNotFound{}) {
el = bEl
return true, err
}
}
return
})

return el, err
}

// Has an element that matches the css selector
Expand Down
30 changes: 13 additions & 17 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,23 @@ func (t T) SearchIframesAfterReload() {
func (t T) PageRace() {
p := t.page.MustNavigate(t.srcFile("fixtures/selector.html"))

p.Race().MustElement("button", func(el *rod.Element) {
t.Eq("01", el.MustText())
}).MustDo()

p.Race().MustElementX("//button", func(el *rod.Element) {
t.Eq("01", el.MustText())
}).MustDo()

p.Race().MustElementR("button", "02", func(el *rod.Element) {
t.Eq("02", el.MustText())
}).MustDo()

err := p.Sleeper(func() utils.Sleeper { return utils.CountSleeper(2) }).Race().
MustElement("not-exists", func(el *rod.Element) {}).
MustElementX("//not-exists", func(el *rod.Element) {}).
MustElementR("not-exists", "test", func(el *rod.Element) {}).
t.Eq("01", p.Race().MustElement("button").MustDo())

t.Eq("01", p.Race().MustElementX("//button").MustDo())

t.Eq("02", p.Race().MustElementR("button", "02").MustDo())

el, err := p.Sleeper(func() utils.Sleeper { return utils.CountSleeper(2) }).Race().
MustElement("not-exists").
MustElementX("//not-exists").
MustElementR("not-exists", "test").
Do()
t.Err(err)
t.Nil(el)

err = p.Race().MustElementByJS(`notExists()`, nil, nil).Do()
el, err = p.Race().MustElementByJS(`notExists()`, nil).Do()
t.Err(err)
t.Nil(el)
}

func (t T) PageElementX() {
Expand Down

0 comments on commit 68d8791

Please sign in to comment.